diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 23752b56d555..ee3306a217c0 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -2307,7 +2307,7 @@ int Sketch::initMove(int geoId, PointPos pos, bool fine) GCS::Point ¢er = Points[Geoms[geoId].midPointId]; GCS::Point p0,p1; - if (pos == mid | pos == none) { + if (pos == mid || pos == none) { MoveParameters.resize(2); // cx,cy p0.x = &MoveParameters[0]; p0.y = &MoveParameters[1]; diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index f992bb598ea0..4c8f75d3a772 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -355,6 +355,8 @@ int SketchObject::delGeometry(int GeoId) if (GeoId < 0 || GeoId >= int(vals.size())) return -1; + this->DeleteUnusedInternalGeometry(GeoId); + std::vector< Part::Geometry * > newVals(vals); newVals.erase(newVals.begin()+GeoId); @@ -1358,17 +1360,7 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point) delConstraintOnPoint(GeoId, end, false); Part::GeomArcOfEllipse *aoe1 = dynamic_cast(geomlist[GeoId]); aoe1->setRange(startAngle, startAngle + theta1); - Sketcher::Constraint *newConstr = new Sketcher::Constraint(); - newConstr->Type = constrType; - newConstr->First = GeoId; - newConstr->FirstPos = end; - newConstr->Second = GeoId1; - - if (constrType == Sketcher::Coincident) - newConstr->SecondPos = secondPos; - - addConstraint(newConstr); - delete newConstr; + return 0; } } @@ -1378,6 +1370,264 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point) return -1; } +int SketchObject::ExposeInternalGeometry(int GeoId) +{ + if (GeoId < 0 || GeoId > getHighestCurveIndex()) + return -1; + + const Part::Geometry *geo = getGeometry(GeoId); + // Only for supported types + if(geo->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { + // First we search what has to be restored + bool major=false; + bool minor=false; + bool focus1=false; + bool focus2=false; + + int majorelementindex=-1; + int minorelementindex=-1; + int focus1elementindex=-1; + int focus2elementindex=-1; + + const std::vector< Sketcher::Constraint * > &vals = Constraints.getValues(); + + for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin(); + it != vals.end(); ++it) { + if((*it)->Type == Sketcher::InternalAlignment && (*it)->Second == GeoId) + { + switch((*it)->AlignmentType){ + case Sketcher::EllipseMajorDiameter: + major=true; + majorelementindex=(*it)->First; + break; + case Sketcher::EllipseMinorDiameter: + minor=true; + minorelementindex=(*it)->First; + break; + case Sketcher::EllipseFocus1: + focus1=true; + focus1elementindex=(*it)->First; + break; + case Sketcher::EllipseFocus2: + focus2=true; + focus2elementindex=(*it)->First; + break; + } + } + } + + int currentgeoid= getHighestCurveIndex(); + int incrgeo= 0; + + Base::Vector3d center; + double majord; + double minord; + double phi; + + if(geo->getTypeId() == Part::GeomEllipse::getClassTypeId()){ + const Part::GeomEllipse *ellipse = static_cast(geo); + + center=ellipse->getCenter(); + majord=ellipse->getMajorRadius(); + minord=ellipse->getMinorRadius(); + phi=ellipse->getAngleXU(); + } + else { + const Part::GeomArcOfEllipse *aoe = static_cast(geo); + + center=aoe->getCenter(); + majord=aoe->getMajorRadius(); + minord=aoe->getMinorRadius(); + phi=aoe->getAngleXU(); + } + + Base::Vector3d majorpositiveend = center + majord * Base::Vector3d(cos(phi),sin(phi),0); + Base::Vector3d majornegativeend = center - majord * Base::Vector3d(cos(phi),sin(phi),0); + Base::Vector3d minorpositiveend = center + minord * Base::Vector3d(-sin(phi),cos(phi),0); + Base::Vector3d minornegativeend = center - minord * Base::Vector3d(-sin(phi),cos(phi),0); + + double df= sqrt(majord*majord-minord*minord); + + Base::Vector3d focus1P = center + df * Base::Vector3d(cos(phi),sin(phi),0); + Base::Vector3d focus2P = center - df * Base::Vector3d(cos(phi),sin(phi),0); + + if(!major) + { + Part::GeomLineSegment *lmajor = new Part::GeomLineSegment(); + lmajor->setPoints(majorpositiveend,majornegativeend); + + this->addGeometry(lmajor); // create line for major axis + this->setConstruction(currentgeoid+incrgeo+1,true); + delete lmajor; + + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = EllipseMajorDiameter; + newConstr->First = currentgeoid+incrgeo+1; + newConstr->Second = GeoId; + + addConstraint(newConstr); + delete newConstr; + incrgeo++; + } + if(!minor) + { + Part::GeomLineSegment *lminor = new Part::GeomLineSegment(); + lminor->setPoints(minorpositiveend,minornegativeend); + + this->addGeometry(lminor); // create line for major axis + this->setConstruction(currentgeoid+incrgeo+1,true); + delete lminor; + + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = EllipseMinorDiameter; + newConstr->First = currentgeoid+incrgeo+1; + newConstr->Second = GeoId; + + addConstraint(newConstr); + delete newConstr; + incrgeo++; + } + if(!focus1) + { + Part::GeomPoint *pf1 = new Part::GeomPoint(); + pf1->setPoint(focus1P); + this->addGeometry(pf1); + delete pf1; + + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = EllipseFocus1; + newConstr->First = currentgeoid+incrgeo+1; + newConstr->FirstPos = Sketcher::start; + newConstr->Second = GeoId; + + addConstraint(newConstr); + delete newConstr; + incrgeo++; + } + if(!focus2) + { + Part::GeomPoint *pf2 = new Part::GeomPoint(); + pf2->setPoint(focus2P); + this->addGeometry(pf2); + delete pf2; + + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = EllipseFocus2; + newConstr->First = currentgeoid+incrgeo+1; + newConstr->FirstPos = Sketcher::start; + newConstr->Second = GeoId; + + addConstraint(newConstr); + delete newConstr; + } + + return incrgeo; //number of added elements + } + else + return -1; // not supported type +} + +int SketchObject::DeleteUnusedInternalGeometry(int GeoId) +{ + if (GeoId < 0 || GeoId > getHighestCurveIndex()) + return -1; + + const Part::Geometry *geo = getGeometry(GeoId); + // Only for supported types + if(geo->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { + // First we search what has to be deleted + bool major=false; + bool minor=false; + bool focus1=false; + bool focus2=false; + + int majorelementindex=-1; + int minorelementindex=-1; + int focus1elementindex=-1; + int focus2elementindex=-1; + + const std::vector< Sketcher::Constraint * > &vals = Constraints.getValues(); + + for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin(); + it != vals.end(); ++it) { + if((*it)->Type == Sketcher::InternalAlignment && (*it)->Second == GeoId) + { + switch((*it)->AlignmentType){ + case Sketcher::EllipseMajorDiameter: + major=true; + majorelementindex=(*it)->First; + break; + case Sketcher::EllipseMinorDiameter: + minor=true; + minorelementindex=(*it)->First; + break; + case Sketcher::EllipseFocus1: + focus1=true; + focus1elementindex=(*it)->First; + break; + case Sketcher::EllipseFocus2: + focus2=true; + focus2elementindex=(*it)->First; + break; + } + } + } + + // Hide unused geometry here + int majorconstraints=0; // number of constraints associated to the geoid of the major axis + int minorconstraints=0; + int focus1constraints=0; + int focus2constraints=0; + + int decrgeo=0; + + for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin(); + it != vals.end(); ++it) { + + if((*it)->Second == majorelementindex || (*it)->First == majorelementindex || (*it)->Third == majorelementindex) + majorconstraints++; + else if((*it)->Second == minorelementindex || (*it)->First == minorelementindex || (*it)->Third == minorelementindex) + minorconstraints++; + else if((*it)->Second == focus1elementindex || (*it)->First == focus1elementindex || (*it)->Third == focus1elementindex) + focus1constraints++; + else if((*it)->Second == focus2elementindex || (*it)->First == focus2elementindex || (*it)->Third == focus2elementindex) + focus2constraints++; + } + + std::vector delgeometries; + + // those with less than 2 constraints must be removed + if(focus2constraints<2) + delgeometries.push_back(focus2elementindex); + + if(focus1constraints<2) + delgeometries.push_back(focus1elementindex); + + if(minorconstraints<2) + delgeometries.push_back(minorelementindex); + + if(majorconstraints<2) + delgeometries.push_back(majorelementindex); + + std::sort(delgeometries.begin(), delgeometries.end()); // indices over an erased element get automatically updated!! + + if(delgeometries.size()>0) + { + for (std::vector::reverse_iterator it=delgeometries.rbegin(); it!=delgeometries.rend(); ++it) { + delGeometry(*it); + } + } + + return delgeometries.size(); //number of deleted elements + } + else + return -1; // not supported type +} + int SketchObject::addExternal(App::DocumentObject *Obj, const char* SubName) { // so far only externals to the support of the sketch diff --git a/src/Mod/Sketcher/App/SketchObject.h b/src/Mod/Sketcher/App/SketchObject.h index c04859fb55e2..560bab9bfb9a 100644 --- a/src/Mod/Sketcher/App/SketchObject.h +++ b/src/Mod/Sketcher/App/SketchObject.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2008 * + * Copyright (c) J�rgen Riegel (juergen.riegel@web.de) 2008 * * * * This file is part of the FreeCAD CAx development system. * * * @@ -47,6 +47,7 @@ class SketcherExport SketchObject : public Part::Part2DObject Part ::PropertyGeometryList Geometry; Sketcher::PropertyConstraintList Constraints; App ::PropertyLinkSubList ExternalGeometry; + const char* ss; /** @name methods overide Feature */ //@{ /// recalculate the Feature @@ -127,6 +128,10 @@ class SketcherExport SketchObject : public Part::Part2DObject /// trim a curve int trim(int geoId, const Base::Vector3d& point); + /// Exposes all internal geometry of an object supporting internal geometry + int ExposeInternalGeometry(int GeoId); + /// Deletes all unused (not further constrained) internal geometry + int DeleteUnusedInternalGeometry(int GeoId); /// retrieves for a Vertex number the corresponding GeoId and PosId void getGeoVertexIndex(int VertexId, int &GeoId, PointPos &PosId) const; @@ -158,6 +163,7 @@ class SketcherExport SketchObject : public Part::Part2DObject virtual int getAxisCount(void) const; /// retrieves an axis iterating through the construction lines of the sketch (indices start at 0) virtual Base::Axis getAxis(int axId) const; + const char*& it(int arg1, int arg2); protected: /// get called by the container when a property has changed diff --git a/src/Mod/Sketcher/App/SketchObjectPy.xml b/src/Mod/Sketcher/App/SketchObjectPy.xml index 3d94b91c9615..e8f1c489e09a 100644 --- a/src/Mod/Sketcher/App/SketchObjectPy.xml +++ b/src/Mod/Sketcher/App/SketchObjectPy.xml @@ -112,6 +112,16 @@ trim a curve with a given id at a given reference point + + + Exposes all internal geometry of an object supporting internal geometry + + + + + Deletes all unused (not further constrained) internal geometry + + Number of Constraints in this sketch diff --git a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp index 44126c8b2acd..fabea7da2e0e 100644 --- a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp +++ b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp @@ -596,6 +596,40 @@ PyObject* SketchObjectPy::trim(PyObject *args) } +PyObject* SketchObjectPy::ExposeInternalGeometry(PyObject *args) +{ + int GeoId; + + if (!PyArg_ParseTuple(args, "i", &GeoId)) + return 0; + + if (this->getSketchObjectPtr()->ExposeInternalGeometry(GeoId)==-1) { + std::stringstream str; + str << "Object does not support internal geometry: " << GeoId; + PyErr_SetString(PyExc_ValueError, str.str().c_str()); + return 0; + } + + Py_Return; +} + +PyObject* SketchObjectPy::DeleteUnusedInternalGeometry(PyObject *args) +{ + int GeoId; + + if (!PyArg_ParseTuple(args, "i", &GeoId)) + return 0; + + if (this->getSketchObjectPtr()->DeleteUnusedInternalGeometry(GeoId)==-1) { + std::stringstream str; + str << "Object does not support internal geometry: " << GeoId; + PyErr_SetString(PyExc_ValueError, str.str().c_str()); + return 0; + } + + Py_Return; +} + Py::Int SketchObjectPy::getConstraintCount(void) const { return Py::Int(this->getSketchObjectPtr()->Constraints.getSize()); diff --git a/src/Mod/Sketcher/Gui/CMakeLists.txt b/src/Mod/Sketcher/Gui/CMakeLists.txt index 15fcbedfde1f..ad044b052e3b 100644 --- a/src/Mod/Sketcher/Gui/CMakeLists.txt +++ b/src/Mod/Sketcher/Gui/CMakeLists.txt @@ -62,6 +62,7 @@ SET(SketcherGui_SRCS AppSketcherGuiPy.cpp Command.cpp CommandCreateGeo.cpp + CommandConstraints.h CommandConstraints.cpp CommandSketcherTools.cpp CommandAlterGeometry.cpp diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 86e33c741b51..973233519115 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -42,6 +42,7 @@ #include "ViewProviderSketch.h" #include "ui_InsertDatum.h" #include "EditDatumDialog.h" +#include "CommandConstraints.h" using namespace std; using namespace SketcherGui; @@ -154,6 +155,162 @@ bool isSimpleVertex(const Sketcher::SketchObject* Obj, int GeoId, PointPos PosId return false; } +/// Makes a tangency constraint using external construction line between +/// geom1 => an ellipse +/// geom2 => any of an ellipse, an arc of ellipse, a circle, or an arc (of circle) +/// NOTE: A command must be opened before calling this function, which this function +/// commits or aborts as appropriate. The reason is for compatibility reasons with +/// other code e.g. "Autoconstraints" in DrawSketchHandler.cpp +void SketcherGui::makeTangentToEllipseviaConstructionLine(const Sketcher::SketchObject* Obj, + const Part::Geometry *geom1, + const Part::Geometry *geom2, + int geoId1, + int geoId2 + ) +{ + const Part::GeomEllipse *ellipse = static_cast(geom1); + + Base::Vector3d center=ellipse->getCenter(); + double majord=ellipse->getMajorRadius(); + double minord=ellipse->getMinorRadius(); + double phi=ellipse->getAngleXU(); + + Base::Vector3d center2; + + if( geom2->getTypeId() == Part::GeomEllipse::getClassTypeId() ) + center2= (static_cast(geom2))->getCenter(); + else if( geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) + center2= (static_cast(geom2))->getCenter(); + else if( geom2->getTypeId() == Part::GeomCircle::getClassTypeId()) + center2= (static_cast(geom2))->getCenter(); + else if( geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) + center2= (static_cast(geom2))->getCenter(); + + Base::Vector3d direction=center2-center; + double tapprox=atan2(direction.y,direction.x)-phi; // we approximate the eccentric anomally by the polar + + Base::Vector3d PoE = Base::Vector3d(center.x+majord*cos(tapprox)*cos(phi)-minord*sin(tapprox)*sin(phi), + center.y+majord*cos(tapprox)*sin(phi)+minord*sin(tapprox)*cos(phi), 0); + + Base::Vector3d perp = Base::Vector3d(direction.y,-direction.x); + + Base::Vector3d endpoint = PoE+perp; + + int currentgeoid= Obj->getHighestCurveIndex(); + + try { + // Add a construction line + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))", + Obj->getNameInDocument(), + PoE.x,PoE.y,endpoint.x,endpoint.y); // create line for major axis + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",Obj->getNameInDocument(),currentgeoid+1); + + // Point on first object + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", + Obj->getNameInDocument(),currentgeoid+1,Sketcher::start,geoId1); // constrain major axis + // Point on second object + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", + Obj->getNameInDocument(),currentgeoid+1,Sketcher::start,geoId2); // constrain major axis + // tangent to first object + Gui::Command::doCommand( + Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ", + Obj->getNameInDocument(),currentgeoid+1,geoId1); + // tangent to second object + Gui::Command::doCommand( + Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ", + Obj->getNameInDocument(),currentgeoid+1,geoId2); + + } + catch (const Base::Exception& e) { + Base::Console().Error("%s\n", e.what()); + Gui::Command::abortCommand(); + Gui::Command::updateActive(); + return; + } + + Gui::Command::commitCommand(); + Gui::Command::updateActive(); +} +/// Makes a tangency constraint using external construction line between +/// geom1 => an arc of ellipse +/// geom2 => any of an arc of ellipse, a circle, or an arc (of circle) +/// NOTE: A command must be opened before calling this function, which this function +/// commits or aborts as appropriate. The reason is for compatibility reasons with +/// other code e.g. "Autoconstraints" in DrawSketchHandler.cpp +void SketcherGui::makeTangentToArcOfEllipseviaConstructionLine(const Sketcher::SketchObject* Obj, + const Part::Geometry *geom1, + const Part::Geometry *geom2, + int geoId1, + int geoId2 + ) +{ + const Part::GeomArcOfEllipse *aoe = static_cast(geom1); + + Base::Vector3d center=aoe->getCenter(); + double majord=aoe->getMajorRadius(); + double minord=aoe->getMinorRadius(); + double phi=aoe->getAngleXU(); + + Base::Vector3d center2; + + if( geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) + center2= (static_cast(geom2))->getCenter(); + else if( geom2->getTypeId() == Part::GeomCircle::getClassTypeId()) + center2= (static_cast(geom2))->getCenter(); + else if( geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) + center2= (static_cast(geom2))->getCenter(); + + Base::Vector3d direction=center2-center; + double tapprox=atan2(direction.y,direction.x)-phi; // we approximate the eccentric anomally by the polar + + Base::Vector3d PoE = Base::Vector3d(center.x+majord*cos(tapprox)*cos(phi)-minord*sin(tapprox)*sin(phi), + center.y+majord*cos(tapprox)*sin(phi)+minord*sin(tapprox)*cos(phi), 0); + + Base::Vector3d perp = Base::Vector3d(direction.y,-direction.x); + + Base::Vector3d endpoint = PoE+perp; + + int currentgeoid= Obj->getHighestCurveIndex(); + + Gui::Command::openCommand("add tangent constraint"); + + try { + + // Add a construction line + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))", + Obj->getNameInDocument(), + PoE.x,PoE.y,endpoint.x,endpoint.y); // create line for major axis + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",Obj->getNameInDocument(),currentgeoid+1); + + // Point on first object + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", + Obj->getNameInDocument(),currentgeoid+1,Sketcher::start,geoId1); // constrain major axis + // Point on second object + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", + Obj->getNameInDocument(),currentgeoid+1,Sketcher::start,geoId2); // constrain major axis + // tangent to first object + Gui::Command::doCommand( + Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ", + Obj->getNameInDocument(),currentgeoid+1,geoId1); + // tangent to second object + Gui::Command::doCommand( + Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ", + Obj->getNameInDocument(),currentgeoid+1,geoId2); + + } + catch (const Base::Exception& e) { + Base::Console().Error("%s\n", e.what()); + Gui::Command::abortCommand(); + Gui::Command::updateActive(); + return; + } + + Gui::Command::commitCommand(); + Gui::Command::updateActive(); +} + namespace SketcherGui { struct SketchSelection{ @@ -1374,6 +1531,9 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) PoE.x,PoE.y,endpoint.x,endpoint.y); Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",Obj->getNameInDocument(),currentgeoid+1); + + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Distance',%d,%f)) ", + selection[0].getFeatName(),currentgeoid+1,direction.Length()); // Point on first object (ellipse, arc of ellipse) Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", @@ -1480,74 +1640,35 @@ void CmdSketcherConstrainTangent::activated(int iMsg) QObject::tr("Cannot add a tangency constraint at an unconnected point!")); return; } - - openCommand("add tangent constraint"); - Gui::Command::doCommand( - Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d,%d,%d)) ", - selection[0].getFeatName(),GeoId1,PosId1,GeoId2,PosId2); - commitCommand(); - updateActive(); - getSelection().clearSelection(); - return; - } - else if ((isVertex(GeoId1,PosId1) && isEdge(GeoId2,PosId2)) || - (isEdge(GeoId1,PosId1) && isVertex(GeoId2,PosId2))) { // tangency point - if (isVertex(GeoId2,PosId2)) { - std::swap(GeoId1,GeoId2); - std::swap(PosId1,PosId2); - } - - if (isSimpleVertex(Obj, GeoId1, PosId1)) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Cannot add a tangency constraint at an unconnected point!")); - return; - } - - openCommand("add tangent constraint"); - Gui::Command::doCommand( - Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d,%d)) ", - selection[0].getFeatName(),GeoId1,PosId1,GeoId2); - commitCommand(); - updateActive(); - getSelection().clearSelection(); - return; - } - else if (isEdge(GeoId1,PosId1) && isEdge(GeoId2,PosId2)) { // simple tangency between GeoId1 and GeoId2 - + const Part::Geometry *geom1 = Obj->getGeometry(GeoId1); const Part::Geometry *geom2 = Obj->getGeometry(GeoId2); - + if( geom1 && geom2 && - ( geom1->getTypeId() == Part::GeomEllipse::getClassTypeId() || - geom2->getTypeId() == Part::GeomEllipse::getClassTypeId() )){ + ( geom1->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || + geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() )){ - if(geom1->getTypeId() != Part::GeomEllipse::getClassTypeId()) + if(geom1->getTypeId() != Part::GeomArcOfEllipse::getClassTypeId()) std::swap(GeoId1,GeoId2); - // GeoId1 is the ellipse + // GeoId1 is the arc of ellipse geom1 = Obj->getGeometry(GeoId1); geom2 = Obj->getGeometry(GeoId2); - if( geom2->getTypeId() == Part::GeomEllipse::getClassTypeId() || - geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || - geom2->getTypeId() == Part::GeomCircle::getClassTypeId() || + if( geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() ) { - const Part::GeomEllipse *ellipse = static_cast(geom1); + const Part::GeomArcOfEllipse *aoe = static_cast(geom1); - Base::Vector3d center=ellipse->getCenter(); - double majord=ellipse->getMajorRadius(); - double minord=ellipse->getMinorRadius(); - double phi=ellipse->getAngleXU(); + Base::Vector3d center=aoe->getCenter(); + double majord=aoe->getMajorRadius(); + double minord=aoe->getMinorRadius(); + double phi=aoe->getAngleXU(); Base::Vector3d center2; - if( geom2->getTypeId() == Part::GeomEllipse::getClassTypeId() ) - center2= (static_cast(geom2))->getCenter(); - else if( geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) + if( geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) center2= (static_cast(geom2))->getCenter(); - else if( geom2->getTypeId() == Part::GeomCircle::getClassTypeId()) - center2= (static_cast(geom2))->getCenter(); else if( geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) center2= (static_cast(geom2))->getCenter(); @@ -1566,17 +1687,19 @@ void CmdSketcherConstrainTangent::activated(int iMsg) openCommand("add tangent constraint"); try { - //construct the point - /*Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))", - Obj->getNameInDocument(), - PoE.x,PoE.y);*/ + // do points coincident + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Coincident',%d,%d,%d,%d)) ", + selection[0].getFeatName(),GeoId1,PosId1,GeoId2,PosId2); // Add a construction line Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))", selection[0].getFeatName(), - PoE.x,PoE.y,endpoint.x,endpoint.y); // create line for major axis + PoE.x,PoE.y,endpoint.x,endpoint.y); Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",Obj->getNameInDocument(),currentgeoid+1); + + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Distance',%d,%f)) ", + selection[0].getFeatName(),currentgeoid+1,direction.Length()); // Point on first object Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", @@ -1600,9 +1723,7 @@ void CmdSketcherConstrainTangent::activated(int iMsg) Gui::Command::updateActive(); return; } - - - + commitCommand(); updateActive(); getSelection().clearSelection(); @@ -1610,6 +1731,65 @@ void CmdSketcherConstrainTangent::activated(int iMsg) } } + + openCommand("add tangent constraint"); + Gui::Command::doCommand( + Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d,%d,%d)) ", + selection[0].getFeatName(),GeoId1,PosId1,GeoId2,PosId2); + commitCommand(); + updateActive(); + getSelection().clearSelection(); + return; + } + else if ((isVertex(GeoId1,PosId1) && isEdge(GeoId2,PosId2)) || + (isEdge(GeoId1,PosId1) && isVertex(GeoId2,PosId2))) { // tangency point + if (isVertex(GeoId2,PosId2)) { + std::swap(GeoId1,GeoId2); + std::swap(PosId1,PosId2); + } + + if (isSimpleVertex(Obj, GeoId1, PosId1)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Cannot add a tangency constraint at an unconnected point!")); + return; + } + + openCommand("add tangent constraint"); + Gui::Command::doCommand( + Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d,%d)) ", + selection[0].getFeatName(),GeoId1,PosId1,GeoId2); + commitCommand(); + updateActive(); + getSelection().clearSelection(); + return; + } + else if (isEdge(GeoId1,PosId1) && isEdge(GeoId2,PosId2)) { // simple tangency between GeoId1 and GeoId2 + + const Part::Geometry *geom1 = Obj->getGeometry(GeoId1); + const Part::Geometry *geom2 = Obj->getGeometry(GeoId2); + + if( geom1 && geom2 && + ( geom1->getTypeId() == Part::GeomEllipse::getClassTypeId() || + geom2->getTypeId() == Part::GeomEllipse::getClassTypeId() )){ + + if(geom1->getTypeId() != Part::GeomEllipse::getClassTypeId()) + std::swap(GeoId1,GeoId2); + + // GeoId1 is the ellipse + geom1 = Obj->getGeometry(GeoId1); + geom2 = Obj->getGeometry(GeoId2); + + if( geom2->getTypeId() == Part::GeomEllipse::getClassTypeId() || + geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || + geom2->getTypeId() == Part::GeomCircle::getClassTypeId() || + geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() ) { + + Gui::Command::openCommand("add tangent constraint via construction element"); + makeTangentToEllipseviaConstructionLine(Obj,geom1,geom2,GeoId1,GeoId2); + getSelection().clearSelection(); + return; + } + } if( geom1 && geom2 && ( geom1->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || @@ -1626,70 +1806,8 @@ void CmdSketcherConstrainTangent::activated(int iMsg) geom2->getTypeId() == Part::GeomCircle::getClassTypeId() || geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() ) { - const Part::GeomArcOfEllipse *aoe = static_cast(geom1); - - Base::Vector3d center=aoe->getCenter(); - double majord=aoe->getMajorRadius(); - double minord=aoe->getMinorRadius(); - double phi=aoe->getAngleXU(); - - Base::Vector3d center2; - - if( geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) - center2= (static_cast(geom2))->getCenter(); - else if( geom2->getTypeId() == Part::GeomCircle::getClassTypeId()) - center2= (static_cast(geom2))->getCenter(); - else if( geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) - center2= (static_cast(geom2))->getCenter(); - - Base::Vector3d direction=center2-center; - double tapprox=atan2(direction.y,direction.x)-phi; // we approximate the eccentric anomally by the polar - - Base::Vector3d PoE = Base::Vector3d(center.x+majord*cos(tapprox)*cos(phi)-minord*sin(tapprox)*sin(phi), - center.y+majord*cos(tapprox)*sin(phi)+minord*sin(tapprox)*cos(phi), 0); - - Base::Vector3d perp = Base::Vector3d(direction.y,-direction.x); - - Base::Vector3d endpoint = PoE+perp; - - int currentgeoid= Obj->getHighestCurveIndex(); - - openCommand("add tangent constraint"); - - try { - - // Add a construction line - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))", - selection[0].getFeatName(), - PoE.x,PoE.y,endpoint.x,endpoint.y); // create line for major axis - - Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",Obj->getNameInDocument(),currentgeoid+1); - - // Point on first object - Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", - selection[0].getFeatName(),currentgeoid+1,Sketcher::start,GeoId1); // constrain major axis - // Point on second object - Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", - selection[0].getFeatName(),currentgeoid+1,Sketcher::start,GeoId2); // constrain major axis - // tangent to first object - Gui::Command::doCommand( - Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ", - selection[0].getFeatName(),currentgeoid+1,GeoId1); - // tangent to second object - Gui::Command::doCommand( - Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ", - selection[0].getFeatName(),currentgeoid+1,GeoId2); - - } - catch (const Base::Exception& e) { - Base::Console().Error("%s\n", e.what()); - Gui::Command::abortCommand(); - Gui::Command::updateActive(); - return; - } - - commitCommand(); - updateActive(); + Gui::Command::openCommand("add tangent constraint via construction element"); + makeTangentToArcOfEllipseviaConstructionLine(Obj,geom1,geom2,GeoId1,GeoId2); getSelection().clearSelection(); return; } diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.h b/src/Mod/Sketcher/Gui/CommandConstraints.h new file mode 100644 index 000000000000..8e8d3f635c7c --- /dev/null +++ b/src/Mod/Sketcher/Gui/CommandConstraints.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (c) 2014 Abdullah.tahiri.yo@gmail.com * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef SKETCHERGUI_CommandConstraints_H +#define SKETCHERGUI_CommandConstraints_H + +namespace SketcherGui { + +// These functions are declared here to promote code reuse from other modules + +/// Makes a tangency constraint using external construction line between +/// geom1 => an ellipse +/// geom2 => any of an ellipse, an arc of ellipse, a circle, or an arc (of circle) +/// NOTE: A command must be opened before calling this function, which this function +/// commits or aborts as appropriate. The reason is for compatibility reasons with +/// other code e.g. "Autoconstraints" in DrawSketchHandler.cpp +void makeTangentToEllipseviaConstructionLine(const Sketcher::SketchObject* Obj, + const Part::Geometry *geom1, + const Part::Geometry *geom2, + int geoId1, + int geoId2 + ); +/// Makes a tangency constraint using external construction line between +/// geom1 => an arc of ellipse +/// geom2 => any of an arc of ellipse, a circle, or an arc (of circle) +/// NOTE: A command must be opened before calling this function, which this function +/// commits or aborts as appropriate. The reason is for compatibility reasons with +/// other code e.g. "Autoconstraints" in DrawSketchHandler.cpp +void makeTangentToArcOfEllipseviaConstructionLine(const Sketcher::SketchObject* Obj, + const Part::Geometry *geom1, + const Part::Geometry *geom2, + int geoId1, + int geoId2 + ); + +} +#endif // SKETCHERGUI_DrawSketchHandler_H + diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index 8d7bf1c4859c..16161d895917 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -1709,7 +1709,7 @@ class DrawSketchHandlerCircle : public DrawSketchHandler setPositionText(onSketchPos, text); sketchgui->drawEdit(EditCurve); - if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f), + if (seekAutoConstraint(sugConstr2, onSketchPos, onSketchPos - EditCurve[0], AutoConstraint::CURVE)) { renderSuggestConstraintsCursor(sugConstr2); return; @@ -1928,7 +1928,8 @@ class DrawSketchHandlerEllipse : public DrawSketchHandler if (method == PERIAPSIS_APOAPSIS_B) { if (mode == STATUS_SEEK_PERIAPSIS) { setPositionText(onSketchPos); - if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) { // TODO: ellipse prio 1 + if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f), + AutoConstraint::CURVE)) { renderSuggestConstraintsCursor(sugConstr1); return; } @@ -1945,6 +1946,11 @@ class DrawSketchHandlerEllipse : public DrawSketchHandler sketchgui->drawEdit(editCurve); // Suggestions for ellipse and curves are disabled because many tangent constraints // need an intermediate point or line. + if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f), + AutoConstraint::CURVE)) { + renderSuggestConstraintsCursor(sugConstr2); + return; + } } else if (mode == STATUS_SEEK_B) { solveEllipse(onSketchPos); approximateEllipse(); @@ -1955,6 +1961,11 @@ class DrawSketchHandlerEllipse : public DrawSketchHandler setPositionText(onSketchPos, text); sketchgui->drawEdit(editCurve); + if (seekAutoConstraint(sugConstr3, onSketchPos, Base::Vector2D(0.f,0.f), + AutoConstraint::CURVE)) { + renderSuggestConstraintsCursor(sugConstr3); + return; + } } } else { // method is CENTER_PERIAPSIS_B if (mode == STATUS_SEEK_CENTROID) { @@ -1974,6 +1985,11 @@ class DrawSketchHandlerEllipse : public DrawSketchHandler setPositionText(onSketchPos, text); sketchgui->drawEdit(editCurve); + if (seekAutoConstraint(sugConstr2, onSketchPos, onSketchPos - centroid, + AutoConstraint::CURVE)) { + renderSuggestConstraintsCursor(sugConstr2); + return; + } } else if ((mode == STATUS_SEEK_A) || (mode == STATUS_SEEK_B)) { solveEllipse(onSketchPos); approximateEllipse(); @@ -1984,6 +2000,11 @@ class DrawSketchHandlerEllipse : public DrawSketchHandler setPositionText(onSketchPos, text); sketchgui->drawEdit(editCurve); + if (seekAutoConstraint(sugConstr3, onSketchPos, onSketchPos - centroid, + AutoConstraint::CURVE)) { + renderSuggestConstraintsCursor(sugConstr3); + return; + } } } applyCursor(); @@ -2037,7 +2058,7 @@ class DrawSketchHandlerEllipse : public DrawSketchHandler return true; } protected: - std::vector sugConstr1; + std::vector sugConstr1, sugConstr2, sugConstr3; private: SelectMode mode; /// the method of constructing the ellipse @@ -2344,7 +2365,6 @@ class DrawSketchHandlerEllipse : public DrawSketchHandler octave << "plot(centroid(1), centroid(2), \"b.\", \"markersize\", 5);\n"; octave << "plot(f(1), f(2), \"c.\", \"markersize\", 5);\n"; octave << "plot(fPrime(1), fPrime(2), \"m.\", \"markersize\", 5);\n"; - octave << "n = [periapsis(1) - f(1), periapsis(2) - f(2)];\n"; octave << "h = quiver(f(1),f(2),n(1),n(2), 0);\n"; octave << "set (h, \"maxheadsize\", 0.1);\n\n"; @@ -2490,67 +2510,10 @@ class DrawSketchHandlerEllipse : public DrawSketchHandler currentgeoid++; try { - // create line for major axis - Gui::Command::doCommand(Gui::Command::Doc, - "App.ActiveDocument.%s.addGeometry(Part.Line" - "(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))", - sketchgui->getObject()->getNameInDocument(), - periapsis.fX,periapsis.fY, - apoapsis.fX,apoapsis.fY); - - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ", - sketchgui->getObject()->getNameInDocument(),currentgeoid+1); - - // constrain major axis - Gui::Command::doCommand(Gui::Command::Doc, - "App.ActiveDocument.%s.addConstraint(Sketcher.Constraint" - "('InternalAlignment:EllipseMajorDiameter',%d,%d)) ", - sketchgui->getObject()->getNameInDocument(), - currentgeoid+1,currentgeoid); - - // create line for minor axis - Gui::Command::doCommand(Gui::Command::Doc, - "App.ActiveDocument.%s.addGeometry(Part.Line" - "(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))", - sketchgui->getObject()->getNameInDocument(), - positiveB.fX,positiveB.fY, - negativeB.fX,negativeB.fY); - - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ", - sketchgui->getObject()->getNameInDocument(),currentgeoid+2); - - // constrain minor axis - Gui::Command::doCommand(Gui::Command::Doc, - "App.ActiveDocument.%s.addConstraint(Sketcher.Constraint" - "('InternalAlignment:EllipseMinorDiameter',%d,%d)) ", - sketchgui->getObject()->getNameInDocument(), - currentgeoid+2,currentgeoid); - - // create point for focus - Gui::Command::doCommand(Gui::Command::Doc, - "App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))", - sketchgui->getObject()->getNameInDocument(), - f.fX,f.fY); - - // constrain focus - Gui::Command::doCommand(Gui::Command::Doc, - "App.ActiveDocument.%s.addConstraint(Sketcher.Constraint" - "('InternalAlignment:EllipseFocus1',%d,%d,%d)) ", - sketchgui->getObject()->getNameInDocument(), - currentgeoid+3,Sketcher::start,currentgeoid); - - // create point for second focus Gui::Command::doCommand(Gui::Command::Doc, - "App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))", - sketchgui->getObject()->getNameInDocument(), - fPrime.fX,fPrime.fY); - - // constrain second focus - Gui::Command::doCommand(Gui::Command::Doc, - "App.ActiveDocument.%s.addConstraint(Sketcher.Constraint" - "('InternalAlignment:EllipseFocus2',%d,%d,%d)) ", - sketchgui->getObject()->getNameInDocument(), - currentgeoid+4,Sketcher::start,currentgeoid); + "App.ActiveDocument.%s.ExposeInternalGeometry(%d)", + sketchgui->getObject()->getNameInDocument(), + currentgeoid); } catch (const Base::Exception& e) { Base::Console().Error("%s\n", e.what()); @@ -2562,10 +2525,35 @@ class DrawSketchHandlerEllipse : public DrawSketchHandler Gui::Command::commitCommand(); Gui::Command::updateActive(); - // add auto constraints for the center point - if (sugConstr1.size() > 0) { - createAutoConstraints(sugConstr1, currentgeoid, Sketcher::mid); - sugConstr1.clear(); + if (method == CENTER_PERIAPSIS_B) { + // add auto constraints for the center point + if (sugConstr1.size() > 0) { + createAutoConstraints(sugConstr1, currentgeoid, Sketcher::mid); + sugConstr1.clear(); + } + if (sugConstr2.size() > 0) { + createAutoConstraints(sugConstr2, currentgeoid, Sketcher::none); + sugConstr2.clear(); + } + if (sugConstr3.size() > 0) { + createAutoConstraints(sugConstr3, currentgeoid, Sketcher::none); + sugConstr3.clear(); + } + } + + if (method == PERIAPSIS_APOAPSIS_B) { + if (sugConstr1.size() > 0) { + createAutoConstraints(sugConstr1, currentgeoid, Sketcher::none); + sugConstr1.clear(); + } + if (sugConstr2.size() > 0) { + createAutoConstraints(sugConstr2, currentgeoid, Sketcher::none); + sugConstr2.clear(); + } + if (sugConstr3.size() > 0) { + createAutoConstraints(sugConstr3, currentgeoid, Sketcher::none); + sugConstr3.clear(); + } } // delete the temp construction curve from the sketch @@ -2720,11 +2708,11 @@ class DrawSketchHandlerArcOfEllipse : public DrawSketchHandler setPositionText(onSketchPos, text); sketchgui->drawEdit(EditCurve); - if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f), + if (seekAutoConstraint(sugConstr2, onSketchPos, onSketchPos - centerPoint, AutoConstraint::CURVE)) { renderSuggestConstraintsCursor(sugConstr2); return; - } + } } else if (Mode==STATUS_SEEK_Third) { // angle between the major axis of the ellipse and the X axis @@ -2751,8 +2739,7 @@ class DrawSketchHandlerArcOfEllipse : public DrawSketchHandler setPositionText(onSketchPos, text); sketchgui->drawEdit(EditCurve); - if (seekAutoConstraint(sugConstr3, onSketchPos, Base::Vector2D(0.f,0.f), - AutoConstraint::CURVE)) { + if (seekAutoConstraint(sugConstr3, onSketchPos, Base::Vector2D(0.f,0.f))) { renderSuggestConstraintsCursor(sugConstr3); return; } @@ -2791,8 +2778,7 @@ class DrawSketchHandlerArcOfEllipse : public DrawSketchHandler setPositionText(onSketchPos, text); sketchgui->drawEdit(EditCurve); - if (seekAutoConstraint(sugConstr4, onSketchPos, Base::Vector2D(0.f,0.f), - AutoConstraint::CURVE)) { + if (seekAutoConstraint(sugConstr4, onSketchPos, Base::Vector2D(0.f,0.f))) { renderSuggestConstraintsCursor(sugConstr4); return; } @@ -2849,11 +2835,14 @@ class DrawSketchHandlerArcOfEllipse : public DrawSketchHandler double angle2 = angle1 + (angle1 < 0. ? 2 : -2) * M_PI ; arcAngle = abs(angle1-arcAngle) < abs(angle2-arcAngle) ? angle1 : angle2; + bool isOriginalArcCCW=true; + if (arcAngle > 0) endAngle = startAngle + arcAngle; else { endAngle = startAngle; startAngle += arcAngle; + isOriginalArcCCW=false; } Base::Vector2D majAxisDir,minAxisDir,minAxisPoint,majAxisPoint; @@ -2883,19 +2872,7 @@ class DrawSketchHandlerArcOfEllipse : public DrawSketchHandler phi-=M_PI/2; double t=a; a=b; b=t;//swap a,b } - - Base::Vector3d center = Base::Vector3d(centerPoint.fX,centerPoint.fY,0); - - Base::Vector3d majorpositiveend = center + a * Base::Vector3d(cos(phi),sin(phi),0); - Base::Vector3d majornegativeend = center - a * Base::Vector3d(cos(phi),sin(phi),0); - Base::Vector3d minorpositiveend = center + b * Base::Vector3d(-sin(phi),cos(phi),0); - Base::Vector3d minornegativeend = center - b * Base::Vector3d(-sin(phi),cos(phi),0); - - double cf = sqrt( abs(a*a - b*b) );//using abs, avoided using different formula for a>b/agetObject()->getNameInDocument(), - majorpositiveend.x,majorpositiveend.y,majornegativeend.x,majornegativeend.y); // create line for major axis - - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ", - sketchgui->getObject()->getNameInDocument(),currentgeoid+1); - - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseMajorDiameter',%d,%d)) ", - sketchgui->getObject()->getNameInDocument(),currentgeoid+1,currentgeoid); // constrain major axis - - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))", - sketchgui->getObject()->getNameInDocument(), - minorpositiveend.x,minorpositiveend.y,minornegativeend.x,minornegativeend.y); // create line for minor axis - - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ", - sketchgui->getObject()->getNameInDocument(),currentgeoid+2); - - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseMinorDiameter',%d,%d)) ", - sketchgui->getObject()->getNameInDocument(),currentgeoid+2,currentgeoid); // constrain minor axis - - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))", - sketchgui->getObject()->getNameInDocument(), - focus1P.x,focus1P.y); - - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseFocus1',%d,%d,%d)) ", - sketchgui->getObject()->getNameInDocument(),currentgeoid+3,Sketcher::start,currentgeoid); - - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))", - sketchgui->getObject()->getNameInDocument(), - focus2P.x,focus2P.y); - - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseFocus2',%d,%d,%d)) ", - sketchgui->getObject()->getNameInDocument(),currentgeoid+4,Sketcher::start,currentgeoid); + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.ExposeInternalGeometry(%d)", + sketchgui->getObject()->getNameInDocument(), + currentgeoid); } catch (const Base::Exception& e) { Base::Console().Error("%s\n", e.what()); @@ -2959,15 +2907,27 @@ class DrawSketchHandlerArcOfEllipse : public DrawSketchHandler // add auto constraints for the center point if (sugConstr1.size() > 0) { - createAutoConstraints(sugConstr1, getHighestCurveIndex(), Sketcher::mid); + createAutoConstraints(sugConstr1, currentgeoid, Sketcher::mid); sugConstr1.clear(); } - // add suggested constraints for circumference + // add suggested constraints for arc if (sugConstr2.size() > 0) { - //createAutoConstraints(sugConstr2, getHighestCurveIndex(), Sketcher::none); + createAutoConstraints(sugConstr2, currentgeoid, Sketcher::none); sugConstr2.clear(); } + + // add suggested constraints for start of arc + if (sugConstr3.size() > 0) { + createAutoConstraints(sugConstr3, currentgeoid, isOriginalArcCCW?Sketcher::start:Sketcher::end); + sugConstr3.clear(); + } + + // add suggested constraints for start of arc + if (sugConstr4.size() > 0) { + createAutoConstraints(sugConstr4, currentgeoid, isOriginalArcCCW?Sketcher::end:Sketcher::start); + sugConstr4.clear(); + } EditCurve.clear(); sketchgui->drawEdit(EditCurve); diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp b/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp index b6bdcbc91438..5485ec1315b6 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp +++ b/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ #include "DrawSketchHandler.h" #include "ViewProviderSketch.h" +#include "CommandConstraints.h" using namespace SketcherGui; @@ -138,6 +140,8 @@ int DrawSketchHandler::seekAutoConstraint(std::vector &suggested if (!sketchgui->Autoconstraints.getValue()) return 0; // If Autoconstraints property is not set quit + Base::Vector3d hitShapeDir = Base::Vector3d(0,0,0); // direction of hit shape (if it is a line, the direction of the line) + // Get Preselection int preSelPnt = sketchgui->getPreselectPoint(); int preSelCrv = sketchgui->getPreselectCurve(); @@ -146,16 +150,29 @@ int DrawSketchHandler::seekAutoConstraint(std::vector &suggested Sketcher::PointPos PosId = Sketcher::none; if (preSelPnt != -1) sketchgui->getSketchObject()->getGeoVertexIndex(preSelPnt, GeoId, PosId); - else if (preSelCrv != -1) + else if (preSelCrv != -1){ GeoId = preSelCrv; + const Part::Geometry *geom = sketchgui->getSketchObject()->getGeometry(GeoId); + + if(geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()){ + const Part::GeomLineSegment *line = static_cast(geom); + hitShapeDir= line->getEndPoint()-line->getStartPoint(); + } + + } else if (preSelCrs == 0) { // root point GeoId = -1; PosId = Sketcher::start; } - else if (preSelCrs == 1) // x axis + else if (preSelCrs == 1){ // x axis GeoId = -1; - else if (preSelCrs == 2) // y axis + hitShapeDir = Base::Vector3d(1,0,0); + + } + else if (preSelCrs == 2){ // y axis GeoId = -2; + hitShapeDir = Base::Vector3d(0,1,0); + } if (GeoId != Constraint::GeoUndef) { // Currently only considers objects in current Sketcher @@ -171,12 +188,25 @@ int DrawSketchHandler::seekAutoConstraint(std::vector &suggested constr.Type = Sketcher::PointOnObject; else if (type == AutoConstraint::CURVE && PosId == Sketcher::none) constr.Type = Sketcher::Tangent; + + if(constr.Type == Sketcher::Tangent && Dir.Length() > 1e-8 && hitShapeDir.Length() > 1e-8) { // We are hitting a line and have hitting vector information + Base::Vector3d dir3d = Base::Vector3d(Dir.fX,Dir.fY,0); + double cosangle=dir3d.Normalize()*hitShapeDir.Normalize(); + + // the angle between the line and the hitting direction are over around 6 degrees (it is substantially parallel) + // or if it is an sketch axis (that can not move to accomodate to the shape), then only if it is around 6 degrees with the normal (around 84 degrees) + if(abs(cosangle) < 0.995f || ((GeoId==-1 || GeoId==-2) && abs(cosangle) < 0.1)) + suggestedConstraints.push_back(constr); + + + return suggestedConstraints.size(); + } if (constr.Type != Sketcher::None) suggestedConstraints.push_back(constr); } - - if (Dir.Length() < 1e-8) + + if (Dir.Length() < 1e-8 || type == AutoConstraint::CURVE) // Direction not set so return; return suggestedConstraints.size(); @@ -263,8 +293,8 @@ int DrawSketchHandler::seekAutoConstraint(std::vector &suggested Base::Vector3d focus1PMirrored = focus1P + 2*distancetoline*norm; // mirror of focus1 with respect to the line double error = abs((focus1PMirrored-focus2P).Length() - 2*a); - - if ( error< tangDeviation ) { + + if ( error< tangDeviation) { tangId = i; tangDeviation = error; } @@ -297,7 +327,52 @@ int DrawSketchHandler::seekAutoConstraint(std::vector &suggested tangDeviation = projDist; } } - } + } else if ((*it)->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { + const Part::GeomArcOfEllipse *aoe = dynamic_cast((*it)); + + Base::Vector3d center = aoe->getCenter(); + + double a = aoe->getMajorRadius(); + double b = aoe->getMinorRadius(); + double phi = aoe->getAngleXU(); + + double cf = sqrt(a*a - b*b); + + Base::Vector3d focus1P = center + cf * Base::Vector3d(cos(phi),sin(phi),0); + Base::Vector3d focus2P = center - cf * Base::Vector3d(cos(phi),sin(phi),0); + + Base::Vector3d norm = Base::Vector3d(Dir.fY,-Dir.fX).Normalize(); + + double distancetoline = norm*(tmpPos - focus1P); // distance focus1 to line + + Base::Vector3d focus1PMirrored = focus1P + 2*distancetoline*norm; // mirror of focus1 with respect to the line + + double error = abs((focus1PMirrored-focus2P).Length() - 2*a); + + if ( error< tangDeviation ) { + tangId = i; + tangDeviation = error; + } + + if (error < tangDeviation) { + double startAngle, endAngle; + aoe->getRange(startAngle, endAngle); + + double angle = Base::fmod( + atan2(-aoe->getMajorRadius()*((tmpPos.x-center.x)*sin(aoe->getAngleXU())-(tmpPos.y-center.y)*cos(aoe->getAngleXU())), + aoe->getMinorRadius()*((tmpPos.x-center.x)*cos(aoe->getAngleXU())+(tmpPos.y-center.y)*sin(aoe->getAngleXU())) + )- startAngle, 2.f*M_PI); + + while(angle < startAngle) + angle += 2*D_PI; // Bring it to range of arc + + // if the point is on correct side of arc + if (angle <= endAngle) { // Now need to check only one side + tangId = i; + tangDeviation = error; + } + } + } } if (tangId != Constraint::GeoUndef) { @@ -364,6 +439,58 @@ void DrawSketchHandler::createAutoConstraints(const std::vector ); } break; case Sketcher::Tangent: { + Sketcher::SketchObject* Obj = dynamic_cast(sketchgui->getObject()); + + const Part::Geometry *geom1 = Obj->getGeometry(geoId1); + const Part::Geometry *geom2 = Obj->getGeometry(it->GeoId); + + int geoId2 = it->GeoId; + + // ellipse tangency support using construction elements (lines) + if( geom1 && geom2 && + ( geom1->getTypeId() == Part::GeomEllipse::getClassTypeId() || + geom2->getTypeId() == Part::GeomEllipse::getClassTypeId() )){ + + if(geom1->getTypeId() != Part::GeomEllipse::getClassTypeId()) + std::swap(geoId1,geoId2); + + // geoId1 is the ellipse + geom1 = Obj->getGeometry(geoId1); + geom2 = Obj->getGeometry(geoId2); + + if( geom2->getTypeId() == Part::GeomEllipse::getClassTypeId() || + geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || + geom2->getTypeId() == Part::GeomCircle::getClassTypeId() || + geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() ) { + // in all these cases an intermediate element is needed + makeTangentToEllipseviaConstructionLine(Obj,geom1,geom2,geoId1,geoId2); + return; + } + } + + // arc of ellipse tangency support using external elements + if( geom1 && geom2 && + ( geom1->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || + geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() )){ + + if(geom1->getTypeId() != Part::GeomArcOfEllipse::getClassTypeId()) + std::swap(geoId1,geoId2); + + // geoId1 is the arc of ellipse + geom1 = Obj->getGeometry(geoId1); + geom2 = Obj->getGeometry(geoId2); + + if( geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || + geom2->getTypeId() == Part::GeomCircle::getClassTypeId() || + geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() ) { + // in all these cases an intermediate element is needed + // TODO: INSERT COMMON CODE HERE + // in all these cases an intermediate element is needed + makeTangentToArcOfEllipseviaConstructionLine(Obj,geom1,geom2,geoId1,geoId2); + return; + } + } + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%i, %i)) " ,sketchgui->getObject()->getNameInDocument() ,geoId1, it->GeoId