From 4946eddc6ba2006e6158f073cdc099c50209d9ec Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Tue, 11 Nov 2014 19:29:45 +0100 Subject: [PATCH] Sketcher New Feature: Ellipse support - Ellipse introduction button via (center,majaxis extreme, a point in edge), ellipse is always CCW so that Z axis goes in the positive direction of the sketch - Backwards compatibility with files of previous versions of ellipse not defining a phi angle - Art by Jim (all the icons you see and the XPMs shown on creation of an ellipse) - Element Widget support for ellipses - Box selection for ellipses - Point on Ellipse constraint based on the gardener's method based on Ulrich's function proposal (radcan simplified, i.e. with simplify_radical sage function) - Tangent: Ellipse to Line based on DeepSOIC's geometric formulation (radcan simplified) Sketcher New Feature: Internal Alignment Constraint - The element to which internal alignment is applied has to be selected last. - All other elements are added in the order of priority, taking into account existing elements - Art by Jim (beautiful icons). Sketcher New Feature: Tool to show/hide/restore the internal geometry of an element - New functionality for show/hide internal geometry: toggles between hiding all unused internal geometry elements and showing all internal geometry. The restore function is implicit to the showing all internal geometry Sketcher New Feature: Arc of Ellipse support - Part::Geometry + Python implementation - ArcOfEllipse creation method - Art by Jim (all the icons you see and the XPMs shown on creation of arc of ellipse elements) - Sketcher Element widget for ArcOfEllipse. Bug fix: Select elements associated to constraints works now for foci internal alignment constraints --- src/Mod/Part/App/AppPart.cpp | 3 + src/Mod/Part/App/ArcOfEllipsePy.xml | 54 + src/Mod/Part/App/ArcOfEllipsePyImp.cpp | 233 ++++ src/Mod/Part/App/ArcPy.xml | 7 + src/Mod/Part/App/CMakeLists.txt | 3 + src/Mod/Part/App/EllipsePy.xml | 6 + src/Mod/Part/App/EllipsePyImp.cpp | 32 + src/Mod/Part/App/Geometry.cpp | 331 ++++- src/Mod/Part/App/Geometry.h | 47 +- src/Mod/Part/App/Makefile.am | 309 +++++ src/Mod/PartDesign/Gui/Workbench.cpp | 8 + src/Mod/Sketcher/App/Constraint.cpp | 35 +- src/Mod/Sketcher/App/Constraint.h | 40 +- src/Mod/Sketcher/App/ConstraintPyImp.cpp | 60 +- src/Mod/Sketcher/App/Sketch.cpp | 624 ++++++++- src/Mod/Sketcher/App/Sketch.h | 31 +- src/Mod/Sketcher/App/SketchObject.cpp | 26 +- src/Mod/Sketcher/App/SketchObjectPyImp.cpp | 4 + src/Mod/Sketcher/App/freegcs/Constraints.cpp | 1233 +++++++++++++++++ src/Mod/Sketcher/App/freegcs/Constraints.h | 126 +- src/Mod/Sketcher/App/freegcs/GCS.cpp | 226 ++- src/Mod/Sketcher/App/freegcs/GCS.h | 27 + src/Mod/Sketcher/App/freegcs/Geo.h | 22 + src/Mod/Sketcher/Gui/CommandConstraints.cpp | 424 +++++- src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 577 ++++++++ src/Mod/Sketcher/Gui/CommandSketcherTools.cpp | 280 ++++ src/Mod/Sketcher/Gui/DrawSketchHandler.cpp | 21 + src/Mod/Sketcher/Gui/EditDatumDialog.cpp | 6 +- .../Gui/PropertyConstraintListItem.cpp | 8 +- .../Sketcher/Gui/TaskSketcherConstrains.cpp | 35 +- src/Mod/Sketcher/Gui/TaskSketcherElements.cpp | 106 +- src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 185 ++- src/Mod/Sketcher/Gui/Workbench.cpp | 42 +- 33 files changed, 5024 insertions(+), 147 deletions(-) create mode 100644 src/Mod/Part/App/ArcOfEllipsePy.xml create mode 100644 src/Mod/Part/App/ArcOfEllipsePyImp.cpp create mode 100644 src/Mod/Part/App/Makefile.am diff --git a/src/Mod/Part/App/AppPart.cpp b/src/Mod/Part/App/AppPart.cpp index d00e2a431b..b751e8f611 100644 --- a/src/Mod/Part/App/AppPart.cpp +++ b/src/Mod/Part/App/AppPart.cpp @@ -66,6 +66,7 @@ #include "EllipsePy.h" #include "ArcPy.h" #include "ArcOfCirclePy.h" +#include "ArcOfEllipsePy.h" #include "BezierCurvePy.h" #include "BSplineCurvePy.h" #include "HyperbolaPy.h" @@ -172,6 +173,7 @@ void PartExport initPart() Base::Interpreter().addType(&Part::ParabolaPy ::Type,partModule,"Parabola"); Base::Interpreter().addType(&Part::ArcPy ::Type,partModule,"Arc"); Base::Interpreter().addType(&Part::ArcOfCirclePy ::Type,partModule,"ArcOfCircle"); + Base::Interpreter().addType(&Part::ArcOfEllipsePy ::Type,partModule,"ArcOfEllipse"); Base::Interpreter().addType(&Part::BezierCurvePy ::Type,partModule,"BezierCurve"); Base::Interpreter().addType(&Part::BSplineCurvePy ::Type,partModule,"BSplineCurve"); Base::Interpreter().addType(&Part::OffsetCurvePy ::Type,partModule,"OffsetCurve"); @@ -261,6 +263,7 @@ void PartExport initPart() Part::GeomBSplineCurve ::init(); Part::GeomCircle ::init(); Part::GeomArcOfCircle ::init(); + Part::GeomArcOfEllipse ::init(); Part::GeomEllipse ::init(); Part::GeomHyperbola ::init(); Part::GeomParabola ::init(); diff --git a/src/Mod/Part/App/ArcOfEllipsePy.xml b/src/Mod/Part/App/ArcOfEllipsePy.xml new file mode 100644 index 0000000000..2f0f8bf813 --- /dev/null +++ b/src/Mod/Part/App/ArcOfEllipsePy.xml @@ -0,0 +1,54 @@ + + + + + + Describes a portion of an ellipse + + + + The major radius of the ellipse. + + + + + + The minor radius of the ellipse. + + + + + + The angle between the X axis and the major axis of the ellipse. + + + + + + Center of the ellipse. + + + + + + The axis direction of the ellipse + + + + + + The internal ellipse representation + + + + + diff --git a/src/Mod/Part/App/ArcOfEllipsePyImp.cpp b/src/Mod/Part/App/ArcOfEllipsePyImp.cpp new file mode 100644 index 0000000000..341f9e7942 --- /dev/null +++ b/src/Mod/Part/App/ArcOfEllipsePyImp.cpp @@ -0,0 +1,233 @@ +/*************************************************************************** + * Copyright (c) 2014 Abdullah Tahiri +# include +# include +# include +# include +#endif + +#include "Mod/Part/App/Geometry.h" +#include "ArcOfEllipsePy.h" +#include "ArcOfEllipsePy.cpp" +#include "EllipsePy.h" +#include "OCCError.h" + +#include +#include + +using namespace Part; + +extern const char* gce_ErrorStatusText(gce_ErrorType et); + +// returns a string which represents the object e.g. when printed in python +std::string ArcOfEllipsePy::representation(void) const +{ + Handle_Geom_TrimmedCurve trim = Handle_Geom_TrimmedCurve::DownCast + (getGeomArcOfEllipsePtr()->handle()); + Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(trim->BasisCurve()); + + gp_Ax1 axis = ellipse->Axis(); + gp_Dir dir = axis.Direction(); + gp_Pnt loc = axis.Location(); + Standard_Real fMajRad = ellipse->MajorRadius(); + Standard_Real fMinRad = ellipse->MinorRadius(); + Standard_Real u1 = trim->FirstParameter(); + Standard_Real u2 = trim->LastParameter(); + + gp_Dir normal = ellipse->Axis().Direction(); + gp_Dir xdir = ellipse->XAxis().Direction(); + + gp_Ax2 xdirref(loc, normal); // this is a reference XY for the ellipse + + Standard_Real fAngleXU = -xdir.AngleWithRef(xdirref.XDirection(),normal); + + + std::stringstream str; + str << "ArcOfEllipse ("; + str << "MajorRadius : " << fMajRad << ", "; + str << "MinorRadius : " << fMinRad << ", "; + str << "AngleXU : " << fAngleXU << ", "; + str << "Position : (" << loc.X() << ", "<< loc.Y() << ", "<< loc.Z() << "), "; + str << "Direction : (" << dir.X() << ", "<< dir.Y() << ", "<< dir.Z() << "), "; + str << "Parameter : (" << u1 << ", " << u2 << ")"; + str << ")"; + + return str.str(); +} + +PyObject *ArcOfEllipsePy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper +{ + // create a new instance of ArcOfEllipsePy and the Twin object + return new ArcOfEllipsePy(new GeomArcOfEllipse); +} + +// constructor method +int ArcOfEllipsePy::PyInit(PyObject* args, PyObject* kwds) +{ + PyObject* o; + double u1, u2; + PyObject *sense=Py_True; + if (PyArg_ParseTuple(args, "O!dd|O!", &(Part::EllipsePy::Type), &o, &u1, &u2, &PyBool_Type, &sense)) { + try { + Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast + (static_cast(o)->getGeomEllipsePtr()->handle()); + GC_MakeArcOfEllipse arc(ellipse->Elips(), u1, u2, PyObject_IsTrue(sense) ? Standard_True : Standard_False); + if (!arc.IsDone()) { + PyErr_SetString(PartExceptionOCCError, gce_ErrorStatusText(arc.Status())); + return -1; + } + + getGeomArcOfEllipsePtr()->setHandle(arc.Value()); + return 0; + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + PyErr_SetString(PartExceptionOCCError, e->GetMessageString()); + return -1; + } + catch (...) { + PyErr_SetString(PartExceptionOCCError, "creation of arc failed"); + return -1; + } + } + + // All checks failed + PyErr_SetString(PyExc_TypeError, + "ArcOfEllipse constructor expects an ellipse curve and a parameter range"); + return -1; +} + +Py::Float ArcOfEllipsePy::getMajorRadius(void) const +{ + return Py::Float(getGeomArcOfEllipsePtr()->getMajorRadius()); +} + +void ArcOfEllipsePy::setMajorRadius(Py::Float arg) +{ + getGeomArcOfEllipsePtr()->setMajorRadius((double)arg); +} + +Py::Float ArcOfEllipsePy::getMinorRadius(void) const +{ + return Py::Float(getGeomArcOfEllipsePtr()->getMinorRadius()); +} + +void ArcOfEllipsePy::setMinorRadius(Py::Float arg) +{ + getGeomArcOfEllipsePtr()->setMinorRadius((double)arg); +} + +Py::Float ArcOfEllipsePy::getAngleXU(void) const +{ + return Py::Float(getGeomArcOfEllipsePtr()->getAngleXU()); +} + +void ArcOfEllipsePy::setAngleXU(Py::Float arg) +{ + getGeomArcOfEllipsePtr()->setAngleXU((double)arg); +} + +Py::Object ArcOfEllipsePy::getCenter(void) const +{ + return Py::Vector(getGeomArcOfEllipsePtr()->getCenter()); +} + +void ArcOfEllipsePy::setCenter(Py::Object arg) +{ + PyObject* p = arg.ptr(); + if (PyObject_TypeCheck(p, &(Base::VectorPy::Type))) { + Base::Vector3d loc = static_cast(p)->value(); + getGeomArcOfEllipsePtr()->setCenter(loc); + } + else if (PyObject_TypeCheck(p, &PyTuple_Type)) { + Base::Vector3d loc = Base::getVectorFromTuple(p); + getGeomArcOfEllipsePtr()->setCenter(loc); + } + else { + std::string error = std::string("type must be 'Vector', not "); + error += p->ob_type->tp_name; + throw Py::TypeError(error); + } +} + +Py::Object ArcOfEllipsePy::getAxis(void) const +{ + Handle_Geom_TrimmedCurve trim = Handle_Geom_TrimmedCurve::DownCast + (getGeomArcOfEllipsePtr()->handle()); + Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(trim->BasisCurve()); + gp_Ax1 axis = ellipse->Axis(); + gp_Dir dir = axis.Direction(); + return Py::Vector(Base::Vector3d(dir.X(), dir.Y(), dir.Z())); +} + +void ArcOfEllipsePy::setAxis(Py::Object arg) +{ + PyObject* p = arg.ptr(); + Base::Vector3d val; + if (PyObject_TypeCheck(p, &(Base::VectorPy::Type))) { + val = static_cast(p)->value(); + } + else if (PyTuple_Check(p)) { + val = Base::getVectorFromTuple(p); + } + else { + std::string error = std::string("type must be 'Vector', not "); + error += p->ob_type->tp_name; + throw Py::TypeError(error); + } + + Handle_Geom_TrimmedCurve trim = Handle_Geom_TrimmedCurve::DownCast + (getGeomArcOfEllipsePtr()->handle()); + Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(trim->BasisCurve()); + try { + gp_Ax1 axis; + axis.SetLocation(ellipse->Location()); + axis.SetDirection(gp_Dir(val.x, val.y, val.z)); + ellipse->SetAxis(axis); + } + catch (Standard_Failure) { + throw Py::Exception("cannot set axis"); + } +} + +Py::Object ArcOfEllipsePy::getEllipse(void) const +{ + Handle_Geom_TrimmedCurve trim = Handle_Geom_TrimmedCurve::DownCast + (getGeomArcOfEllipsePtr()->handle()); + Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(trim->BasisCurve()); + return Py::Object(new EllipsePy(new GeomEllipse(ellipse)), true); +} + +PyObject *ArcOfEllipsePy::getCustomAttributes(const char* attr) const +{ + return 0; +} + +int ArcOfEllipsePy::setCustomAttributes(const char* attr, PyObject *obj) +{ + return 0; +} diff --git a/src/Mod/Part/App/ArcPy.xml b/src/Mod/Part/App/ArcPy.xml index 4b13d299c4..f48eab49e0 100644 --- a/src/Mod/Part/App/ArcPy.xml +++ b/src/Mod/Part/App/ArcPy.xml @@ -21,5 +21,12 @@ const Geom_Circle & value(void) const {return *getGeom_CirclePtr();} --> + diff --git a/src/Mod/Part/App/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt index 1d17486221..b745a5a2c6 100644 --- a/src/Mod/Part/App/CMakeLists.txt +++ b/src/Mod/Part/App/CMakeLists.txt @@ -40,6 +40,7 @@ endif(FREETYPE_FOUND) generate_from_xml(ArcPy) generate_from_xml(ArcOfCirclePy) generate_from_xml(CirclePy) +generate_from_xml(ArcOfEllipsePy) generate_from_xml(EllipsePy) generate_from_xml(HyperbolaPy) generate_from_xml(ParabolaPy) @@ -148,6 +149,8 @@ SET(Python_SRCS ArcOfCirclePyImp.cpp CirclePy.xml CirclePyImp.cpp + ArcOfEllipsePy.xml + ArcOfEllipsePyImp.cpp EllipsePy.xml EllipsePyImp.cpp HyperbolaPy.xml diff --git a/src/Mod/Part/App/EllipsePy.xml b/src/Mod/Part/App/EllipsePy.xml index 35a366c024..a5777183ca 100644 --- a/src/Mod/Part/App/EllipsePy.xml +++ b/src/Mod/Part/App/EllipsePy.xml @@ -46,6 +46,12 @@ + + + The angle between the X axis and the major axis of the ellipse. + + + The eccentricity of the ellipse. diff --git a/src/Mod/Part/App/EllipsePyImp.cpp b/src/Mod/Part/App/EllipsePyImp.cpp index ede1c21e6d..929a1e0026 100644 --- a/src/Mod/Part/App/EllipsePyImp.cpp +++ b/src/Mod/Part/App/EllipsePyImp.cpp @@ -151,6 +151,38 @@ void EllipsePy::setMinorRadius(Py::Float arg) ellipse->SetMinorRadius((double)arg); } +Py::Float EllipsePy::getAngleXU(void) const +{ + Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(getGeomEllipsePtr()->handle()); + + gp_Pnt center = ellipse->Axis().Location(); + gp_Dir normal = ellipse->Axis().Direction(); + gp_Dir xdir = ellipse->XAxis().Direction(); + + gp_Ax2 xdirref(center, normal); // this is a reference system, might be CCW or CW depending on the creation method + + return Py::Float(-xdir.AngleWithRef(xdirref.XDirection(),normal)); + +} + +void EllipsePy::setAngleXU(Py::Float arg) +{ + Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(getGeomEllipsePtr()->handle()); + + + gp_Pnt center = ellipse->Axis().Location(); + gp_Dir normal = ellipse->Axis().Direction(); + + gp_Ax1 normaxis(center, normal); + + gp_Ax2 xdirref(center, normal); + + xdirref.Rotate(normaxis,arg); + + ellipse->SetPosition(xdirref); + +} + Py::Float EllipsePy::getEccentricity(void) const { Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(getGeomEllipsePtr()->handle()); diff --git a/src/Mod/Part/App/Geometry.cpp b/src/Mod/Part/App/Geometry.cpp index b0377b2175..91cf9819a4 100644 --- a/src/Mod/Part/App/Geometry.cpp +++ b/src/Mod/Part/App/Geometry.cpp @@ -78,6 +78,7 @@ # include # include # include +# include # include # include # include @@ -91,6 +92,7 @@ #include "EllipsePy.h" #include "ArcPy.h" #include "ArcOfCirclePy.h" +#include "ArcOfEllipsePy.h" #include "BezierCurvePy.h" #include "BSplineCurvePy.h" #include "HyperbolaPy.h" @@ -888,6 +890,44 @@ void GeomEllipse::setMinorRadius(double Radius) } } +double GeomEllipse::getAngleXU(void) const +{ + Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(handle()); + + gp_Pnt center = this->myCurve->Axis().Location(); + gp_Dir normal = this->myCurve->Axis().Direction(); + gp_Dir xdir = this->myCurve->XAxis().Direction(); + + + gp_Ax2 xdirref(center, normal); // this is a reference system, might be CCW or CW depending on the creation method + + return -xdir.AngleWithRef(xdirref.XDirection(),normal); + +} + +void GeomEllipse::setAngleXU(double angle) +{ + Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(handle()); + + try { + gp_Pnt center = this->myCurve->Axis().Location(); + gp_Dir normal = this->myCurve->Axis().Direction(); + + gp_Ax1 normaxis(center, normal); + + gp_Ax2 xdirref(center, normal); + + xdirref.Rotate(normaxis,angle); + + this->myCurve->SetPosition(xdirref); + + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + throw Base::Exception(e->GetMessageString()); + } +} + // Persistence implementer unsigned int GeomEllipse::getMemSize (void) const { @@ -901,7 +941,13 @@ void GeomEllipse::Save(Base::Writer& writer) const gp_Pnt center = this->myCurve->Axis().Location(); gp_Dir normal = this->myCurve->Axis().Direction(); - + gp_Dir xdir = this->myCurve->XAxis().Direction(); + + gp_Ax2 xdirref(center, normal); // this is a reference XY for the ellipse + + double AngleXU = -xdir.AngleWithRef(xdirref.XDirection(),normal); + + writer.Stream() << writer.ind() << "myCurve->MajorRadius() << "\" " << "MinorRadius=\"" << this->myCurve->MinorRadius() << "\" " + << "AngleXU=\"" << AngleXU << "\" " << "/>" << endl; } @@ -921,7 +968,7 @@ void GeomEllipse::Restore(Base::XMLReader& reader) // read the attributes of the father class GeomCurve::Restore(reader); - double CenterX,CenterY,CenterZ,NormalX,NormalY,NormalZ,MajorRadius,MinorRadius; + double CenterX,CenterY,CenterZ,NormalX,NormalY,NormalZ,MajorRadius,MinorRadius,AngleXU; // read my Element reader.readElement("Ellipse"); // get the value of my Attribute @@ -933,12 +980,25 @@ void GeomEllipse::Restore(Base::XMLReader& reader) NormalZ = reader.getAttributeAsFloat("NormalZ"); MajorRadius = reader.getAttributeAsFloat("MajorRadius"); MinorRadius = reader.getAttributeAsFloat("MinorRadius"); + + // This is for backwards compatibility + if(reader.hasAttribute("AngleXU")) + AngleXU = reader.getAttributeAsFloat("AngleXU"); + else + AngleXU = 0; // set the read geometry gp_Pnt p1(CenterX,CenterY,CenterZ); gp_Dir norm(NormalX,NormalY,NormalZ); + + gp_Ax1 normaxis(p1,norm); + + gp_Ax2 xdir(p1, norm); + + xdir.Rotate(normaxis,AngleXU); + try { - GC_MakeEllipse mc(gp_Ax2(p1, norm), MajorRadius, MinorRadius); + GC_MakeEllipse mc(xdir, MajorRadius, MinorRadius); if (!mc.IsDone()) throw Base::Exception(gce_ErrorStatusText(mc.Status())); @@ -955,6 +1015,271 @@ PyObject *GeomEllipse::getPyObject(void) return new EllipsePy((GeomEllipse*)this->clone()); } +// ------------------------------------------------- + +TYPESYSTEM_SOURCE(Part::GeomArcOfEllipse,Part::GeomCurve); + +GeomArcOfEllipse::GeomArcOfEllipse() +{ + Handle_Geom_Ellipse e = new Geom_Ellipse(gp_Elips()); + this->myCurve = new Geom_TrimmedCurve(e, e->FirstParameter(),e->LastParameter()); +} + +GeomArcOfEllipse::GeomArcOfEllipse(const Handle_Geom_Ellipse& e) +{ + this->myCurve = new Geom_TrimmedCurve(e, e->FirstParameter(),e->LastParameter()); +} + +GeomArcOfEllipse::~GeomArcOfEllipse() +{ +} + +void GeomArcOfEllipse::setHandle(const Handle_Geom_TrimmedCurve& c) +{ + Handle_Geom_Ellipse basis = Handle_Geom_Ellipse::DownCast(c->BasisCurve()); + if (basis.IsNull()) + Standard_Failure::Raise("Basis curve is not an ellipse"); + this->myCurve = Handle_Geom_TrimmedCurve::DownCast(c->Copy()); +} + +const Handle_Geom_Geometry& GeomArcOfEllipse::handle() const +{ + return myCurve; +} + +Geometry *GeomArcOfEllipse::clone(void) const +{ + GeomArcOfEllipse* copy = new GeomArcOfEllipse(); + copy->setHandle(this->myCurve); + copy->Construction = this->Construction; + return copy; +} + +Base::Vector3d GeomArcOfEllipse::getStartPoint() const +{ + gp_Pnt pnt = this->myCurve->StartPoint(); + return Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()); +} + +Base::Vector3d GeomArcOfEllipse::getEndPoint() const +{ + gp_Pnt pnt = this->myCurve->EndPoint(); + return Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()); +} + +Base::Vector3d GeomArcOfEllipse::getCenter(void) const +{ + Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(myCurve->BasisCurve()); + gp_Ax1 axis = ellipse->Axis(); + const gp_Pnt& loc = axis.Location(); + return Base::Vector3d(loc.X(),loc.Y(),loc.Z()); +} + +void GeomArcOfEllipse::setCenter(const Base::Vector3d& Center) +{ + gp_Pnt p1(Center.x,Center.y,Center.z); + Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(myCurve->BasisCurve()); + + try { + ellipse->SetLocation(p1); + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + throw Base::Exception(e->GetMessageString()); + } +} + +double GeomArcOfEllipse::getMajorRadius(void) const +{ + Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(myCurve->BasisCurve()); + return ellipse->MajorRadius(); +} + +void GeomArcOfEllipse::setMajorRadius(double Radius) +{ + Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(myCurve->BasisCurve()); + + try { + ellipse->SetMajorRadius(Radius); + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + throw Base::Exception(e->GetMessageString()); + } +} + +double GeomArcOfEllipse::getMinorRadius(void) const +{ + Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(myCurve->BasisCurve()); + return ellipse->MinorRadius(); +} + +void GeomArcOfEllipse::setMinorRadius(double Radius) +{ + Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(myCurve->BasisCurve()); + + try { + ellipse->SetMinorRadius(Radius); + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + throw Base::Exception(e->GetMessageString()); + } +} + +double GeomArcOfEllipse::getAngleXU(void) const +{ + Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(myCurve->BasisCurve()); + + gp_Pnt center = ellipse->Axis().Location(); + gp_Dir normal = ellipse->Axis().Direction(); + gp_Dir xdir = ellipse->XAxis().Direction(); + + gp_Ax2 xdirref(center, normal); // this is a reference system, might be CCW or CW depending on the creation method + + return -xdir.AngleWithRef(xdirref.XDirection(),normal); + +} + +void GeomArcOfEllipse::setAngleXU(double angle) +{ + Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(myCurve->BasisCurve()); + + try { + gp_Pnt center = ellipse->Axis().Location(); + gp_Dir normal = ellipse->Axis().Direction(); + + gp_Ax1 normaxis(center, normal); + + gp_Ax2 xdirref(center, normal); + + xdirref.Rotate(normaxis,angle); + + ellipse->SetPosition(xdirref); + + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + throw Base::Exception(e->GetMessageString()); + } +} + +void GeomArcOfEllipse::getRange(double& u, double& v) const +{ + u = myCurve->FirstParameter(); + v = myCurve->LastParameter(); +} + +void GeomArcOfEllipse::setRange(double u, double v) +{ + try { + myCurve->SetTrim(u, v); + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + throw Base::Exception(e->GetMessageString()); + } +} + +// Persistence implementer +unsigned int GeomArcOfEllipse::getMemSize (void) const +{ + return sizeof(Geom_Ellipse) + 2 *sizeof(double); +} + +void GeomArcOfEllipse::Save(Base::Writer &writer) const +{ + // save the attributes of the father class + GeomCurve::Save(writer); + + Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(this->myCurve->BasisCurve()); + + gp_Pnt center = ellipse->Axis().Location(); + gp_Dir normal = ellipse->Axis().Direction(); + gp_Dir xdir = ellipse->XAxis().Direction(); + + gp_Ax2 xdirref(center, normal); // this is a reference XY for the ellipse + + double AngleXU = -xdir.AngleWithRef(xdirref.XDirection(),normal); + + + writer.Stream() + << writer.ind() + << "MajorRadius() << "\" " + << "MinorRadius=\"" << ellipse->MinorRadius() << "\" " + << "AngleXU=\"" << AngleXU << "\" " + << "StartAngle=\"" << this->myCurve->FirstParameter() << "\" " + << "EndAngle=\"" << this->myCurve->LastParameter() << "\" " + << "/>" << endl; +} + +void GeomArcOfEllipse::Restore(Base::XMLReader &reader) +{ + // read the attributes of the father class + GeomCurve::Restore(reader); + + double CenterX,CenterY,CenterZ,NormalX,NormalY,NormalZ,MajorRadius,MinorRadius,AngleXU,StartAngle,EndAngle; + // read my Element + reader.readElement("ArcOfEllipse"); + // get the value of my Attribute + CenterX = reader.getAttributeAsFloat("CenterX"); + CenterY = reader.getAttributeAsFloat("CenterY"); + CenterZ = reader.getAttributeAsFloat("CenterZ"); + NormalX = reader.getAttributeAsFloat("NormalX"); + NormalY = reader.getAttributeAsFloat("NormalY"); + NormalZ = reader.getAttributeAsFloat("NormalZ"); + MajorRadius = reader.getAttributeAsFloat("MajorRadius"); + MinorRadius = reader.getAttributeAsFloat("MinorRadius"); + AngleXU = reader.getAttributeAsFloat("AngleXU"); + StartAngle = reader.getAttributeAsFloat("StartAngle"); + EndAngle = reader.getAttributeAsFloat("EndAngle"); + + + // set the read geometry + gp_Pnt p1(CenterX,CenterY,CenterZ); + gp_Dir norm(NormalX,NormalY,NormalZ); + + gp_Ax1 normaxis(p1,norm); + + gp_Ax2 xdir(p1, norm); + + xdir.Rotate(normaxis,AngleXU); + + try { + GC_MakeEllipse mc(xdir, MajorRadius, MinorRadius); + if (!mc.IsDone()) + throw Base::Exception(gce_ErrorStatusText(mc.Status())); + + GC_MakeArcOfEllipse ma(mc.Value()->Elips(), StartAngle, EndAngle, 1); + if (!ma.IsDone()) + throw Base::Exception(gce_ErrorStatusText(ma.Status())); + + Handle_Geom_TrimmedCurve tmpcurve = ma.Value(); + Handle_Geom_Ellipse tmpellipse = Handle_Geom_Ellipse::DownCast(tmpcurve->BasisCurve()); + Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(this->myCurve->BasisCurve()); + + ellipse->SetElips(tmpellipse->Elips()); + this->myCurve->SetTrim(tmpcurve->FirstParameter(), tmpcurve->LastParameter()); + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + throw Base::Exception(e->GetMessageString()); + } +} + +PyObject *GeomArcOfEllipse::getPyObject(void) +{ + return new ArcOfEllipsePy(static_cast(this->clone())); +} + + // ------------------------------------------------- TYPESYSTEM_SOURCE(Part::GeomHyperbola,Part::GeomCurve); diff --git a/src/Mod/Part/App/Geometry.h b/src/Mod/Part/App/Geometry.h index b066cf9d55..3d583bf392 100644 --- a/src/Mod/Part/App/Geometry.h +++ b/src/Mod/Part/App/Geometry.h @@ -244,6 +244,8 @@ public: void setMajorRadius(double Radius); double getMinorRadius(void) const; void setMinorRadius(double Radius); + double getAngleXU(void) const; + void setAngleXU(double angle); // Persistence implementer --------------------- virtual unsigned int getMemSize(void) const; @@ -258,6 +260,45 @@ private: Handle_Geom_Ellipse myCurve; }; +class PartExport GeomArcOfEllipse : public GeomCurve +{ + TYPESYSTEM_HEADER(); +public: + GeomArcOfEllipse(); + GeomArcOfEllipse(const Handle_Geom_Ellipse&); + virtual ~GeomArcOfEllipse(); + virtual Geometry *clone(void) const; + + Base::Vector3d getStartPoint() const; + Base::Vector3d getEndPoint() const; + + Base::Vector3d getCenter(void) const; + void setCenter(const Base::Vector3d& Center); + double getMajorRadius(void) const; + void setMajorRadius(double Radius); + double getMinorRadius(void) const; + void setMinorRadius(double Radius); + double getAngleXU(void) const; + void setAngleXU(double angle); + + void getRange(double& u, double& v) const; + void setRange(double u, double v); + + // Persistence implementer --------------------- + virtual unsigned int getMemSize(void) const; + virtual void Save(Base::Writer &/*writer*/) const; + virtual void Restore(Base::XMLReader &/*reader*/); + // Base implementer ---------------------------- + virtual PyObject *getPyObject(void); + + void setHandle(const Handle_Geom_TrimmedCurve&); + const Handle_Geom_Geometry& handle() const; + +private: + Handle_Geom_TrimmedCurve myCurve; +}; + + class PartExport GeomHyperbola : public GeomCurve { TYPESYSTEM_HEADER(); @@ -340,7 +381,7 @@ public: Base::Vector3d getStartPoint() const; Base::Vector3d getEndPoint() const; - void setPoints(const Base::Vector3d& p1, + void setPoints(const Base::Vector3d& p1, const Base::Vector3d& p2); // Persistence implementer --------------------- @@ -674,14 +715,14 @@ bool find2DLinesIntersection(const GeomLineSegment *lineSeg1, const GeomLineSegm PartExport bool findFilletCenter(const GeomLineSegment *lineSeg1, const GeomLineSegment *lineSeg2, double radius, Base::Vector3d ¢er); -PartExport +PartExport bool findFilletCenter(const GeomLineSegment *lineSeg1, const GeomLineSegment *lineSeg2, double radius, const Base::Vector3d& refPnt1, const Base::Vector3d& refPnt2, Base::Vector3d ¢er); PartExport double suggestFilletRadius(const GeomLineSegment *lineSeg1, const GeomLineSegment *lineSeg2, const Base::Vector3d &refPnt1, const Base::Vector3d &refPnt2); -PartExport +PartExport GeomArcOfCircle *createFilletGeometry(const GeomLineSegment *lineSeg1, const GeomLineSegment *lineSeg2, const Base::Vector3d ¢er, double radius); } diff --git a/src/Mod/Part/App/Makefile.am b/src/Mod/Part/App/Makefile.am new file mode 100644 index 0000000000..0d717e96fb --- /dev/null +++ b/src/Mod/Part/App/Makefile.am @@ -0,0 +1,309 @@ + +lib_LTLIBRARIES=libPart.la Part.la + +BUILT_SOURCES=\ + ArcPy.cpp \ + ArcOfCirclePy.cpp \ + ArcOfEllipsePy.cpp \ + BRepOffsetAPI_MakePipeShellPy.cpp \ + CirclePy.cpp \ + EllipsePy.cpp \ + HyperbolaPy.cpp \ + ParabolaPy.cpp \ + OffsetCurvePy.cpp \ + GeometryPy.cpp \ + GeometryCurvePy.cpp \ + GeometrySurfacePy.cpp \ + LinePy.cpp \ + PointPy.cpp \ + BezierCurvePy.cpp \ + BSplineCurvePy.cpp \ + PlanePy.cpp \ + ConePy.cpp \ + CylinderPy.cpp \ + SpherePy.cpp \ + ToroidPy.cpp \ + BezierSurfacePy.cpp \ + BSplineSurfacePy.cpp \ + OffsetSurfacePy.cpp \ + RectangularTrimmedSurfacePy.cpp \ + SurfaceOfExtrusionPy.cpp \ + SurfaceOfRevolutionPy.cpp \ + PartFeaturePy.cpp \ + FeaturePythonPy.cpp \ + Part2DObjectPy.cpp \ + TopoShapeCompoundPy.cpp \ + TopoShapeCompSolidPy.cpp \ + TopoShapeEdgePy.cpp \ + TopoShapeFacePy.cpp \ + TopoShapeShellPy.cpp \ + TopoShapeSolidPy.cpp \ + TopoShapeVertexPy.cpp \ + TopoShapeWirePy.cpp \ + TopoShapePy.cpp + +libPart_la_BUILT=\ + ArcPy.h \ + ArcOfCirclePy.h \ + ArcOfEllipsePy.h \ + BRepOffsetAPI_MakePipeShellPy.h \ + CirclePy.h \ + EllipsePy.h \ + HyperbolaPy.h \ + ParabolaPy.h \ + OffsetCurvePy.h \ + GeometryPy.h \ + GeometryCurvePy.h \ + GeometrySurfacePy.h \ + LinePy.h \ + PointPy.h \ + BezierCurvePy.h \ + BSplineCurvePy.h \ + PlanePy.h \ + ConePy.h \ + CylinderPy.h \ + SpherePy.h \ + ToroidPy.h \ + BezierSurfacePy.h \ + BSplineSurfacePy.h \ + OffsetSurfacePy.h \ + RectangularTrimmedSurfacePy.h \ + SurfaceOfExtrusionPy.h \ + SurfaceOfRevolutionPy.h \ + PartFeaturePy.h \ + FeaturePythonPy.h \ + Part2DObjectPy.h \ + TopoShapeCompoundPy.h \ + TopoShapeCompSolidPy.h \ + TopoShapeEdgePy.h \ + TopoShapeFacePy.h \ + TopoShapeShellPy.h \ + TopoShapeSolidPy.h \ + TopoShapeVertexPy.h \ + TopoShapeWirePy.h \ + TopoShapePy.h + +libPart_la_SOURCES=\ + AppPartPy.cpp \ + ArcPyImp.cpp \ + ArcOfCirclePyImp.cpp \ + ArcOfEllipsePyImp.cpp \ + BRepOffsetAPI_MakePipeShellPyImp.cpp \ + CirclePyImp.cpp \ + CrossSection.cpp \ + EllipsePyImp.cpp \ + HyperbolaPyImp.cpp \ + ParabolaPyImp.cpp \ + OffsetCurvePyImp.cpp \ + GeometryPyImp.cpp \ + GeometryCurvePyImp.cpp \ + GeometrySurfacePyImp.cpp \ + LinePyImp.cpp \ + PointPyImp.cpp \ + BezierCurvePyImp.cpp \ + BSplineCurvePyImp.cpp \ + PlanePyImp.cpp \ + ConePyImp.cpp \ + CylinderPyImp.cpp \ + SpherePyImp.cpp \ + ToroidPyImp.cpp \ + BezierSurfacePyImp.cpp \ + BSplineSurfacePyImp.cpp \ + OffsetSurfacePyImp.cpp \ + RectangularTrimmedSurfacePyImp.cpp \ + SurfaceOfExtrusionPyImp.cpp \ + SurfaceOfRevolutionPyImp.cpp \ + edgecluster.cpp \ + FeaturePartBoolean.cpp \ + FeaturePartBox.cpp \ + FeaturePartCircle.cpp \ + FeaturePartCurveNet.cpp \ + FeaturePartCommon.cpp \ + FeaturePartCut.cpp \ + FeaturePartFuse.cpp \ + FeaturePartImportBrep.cpp \ + FeaturePartImportIges.cpp \ + FeaturePartImportStep.cpp \ + FeaturePartPolygon.cpp \ + FeaturePartSection.cpp \ + FeatureChamfer.cpp \ + FeatureExtrusion.cpp \ + FeatureFillet.cpp \ + FeatureGeometrySet.cpp \ + FeatureRevolution.cpp \ + FeatureMirroring.cpp \ + PartFeatures.cpp \ + Geometry.cpp \ + ImportIges.cpp \ + ImportStep.cpp \ + modelRefine.cpp \ + CustomFeature.cpp \ + PartFeature.cpp \ + PartFeatureReference.cpp \ + PartFeaturePyImp.cpp \ + FeaturePythonPyImp.cpp \ + Part2DObject.cpp \ + Part2DObjectPyImp.cpp \ + PreCompiled.cpp \ + PreCompiled.h \ + PrimitiveFeature.cpp \ + ProgressIndicator.cpp \ + PropertyGeometryList.cpp \ + PropertyTopoShape.cpp \ + TopoShape.cpp \ + TopoShapeCompoundPyImp.cpp \ + TopoShapeCompSolidPyImp.cpp \ + TopoShapeEdgePyImp.cpp \ + TopoShapeFacePyImp.cpp \ + TopoShapeShellPyImp.cpp \ + TopoShapeSolidPyImp.cpp \ + TopoShapeVertexPyImp.cpp \ + TopoShapeWirePyImp.cpp \ + TopoShapePyImp.cpp + +nodist_include_HEADERS=\ + $(libPart_la_BUILT) + +include_HEADERS=\ + CrossSection.h \ + edgecluster.h \ + FeaturePartBoolean.h \ + FeaturePartBox.h \ + FeaturePartCircle.h \ + FeaturePartCurveNet.h \ + FeaturePartCommon.h \ + FeaturePartCut.h \ + FeaturePartFuse.h \ + FeaturePartImportBrep.h \ + FeaturePartImportIges.h \ + FeaturePartImportStep.h \ + FeaturePartPolygon.h \ + FeaturePartSection.h \ + FeatureChamfer.h \ + FeatureExtrusion.h \ + FeatureFillet.h \ + FeatureGeometrySet.h \ + FeatureRevolution.h \ + FeatureMirroring.h \ + PartFeatures.h \ + Geometry.h \ + ImportIges.h \ + ImportStep.h \ + modelRefine.h \ + PartFeature.h \ + PartFeatureReference.h \ + CustomFeature.h \ + Part2DObject.h \ + PrimitiveFeature.h \ + ProgressIndicator.h \ + PropertyGeometryList.h \ + PropertyTopoShape.h \ + Tools.h \ + TopoShape.h + + +# the library search path. +libPart_la_LDFLAGS = -L../../../Base -L../../../App -L/usr/X11R6/lib -L$(OCC_LIB) $(all_libraries) \ + -version-info @LIB_CURRENT@:@LIB_REVISION@:@LIB_AGE@ +libPart_la_CPPFLAGS = -DPartExport= + +libPart_la_LIBADD = \ + @BOOST_FILESYSTEM_LIB@ @BOOST_SYSTEM_LIB@ \ + -l@PYTHON_LIB@ \ + -lxerces-c \ + -lFreeCADBase \ + -lFreeCADApp \ + -lTKernel \ + -lTKFillet \ + -lTKG2d \ + -lTKG3d \ + -lTKMath \ + -lTKMesh \ + -lTKSTEP \ + -lTKSTEPAttr \ + -lTKSTEPBase \ + -lTKIGES \ + -lTKSTL \ + -lTKShHealing \ + -lTKXSBase \ + -lTKBool \ + -lTKBO \ + -lTKBRep \ + -lTKTopAlgo \ + -lTKGeomAlgo \ + -lTKGeomBase \ + -lTKOffset \ + -lTKPrim + +%.cpp: %.xml $(top_srcdir)/src/Tools/generateTemplates/templateClassPyExport.py + $(PYTHON) $(top_srcdir)/src/Tools/generate.py --outputPath $(@D) $< + +#-------------------------------------------------------------------------------------- +# Loader of libPart + +Part_la_SOURCES=\ + AppPart.cpp + +# the library search path. +Part_la_LDFLAGS = $(libPart_la_LDFLAGS) -module -avoid-version +Part_la_CPPFLAGS = $(libPart_la_CPPFLAGS) + +Part_la_LIBADD = \ + $(libPart_la_LIBADD) \ + -lPart + +Part_la_DEPENDENCIES = libPart.la + +#-------------------------------------------------------------------------------------- + +# set the include path found by configure +AM_CXXFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src $(all_includes) -I$(OCC_INC) + + +includedir = @includedir@/Mod/Part/App +libdir = $(prefix)/Mod/Part + +CLEANFILES = $(BUILT_SOURCES) $(libPart_la_BUILT) + +EXTRA_DIST = \ + OpenCascadeAll.h \ + ArcPy.xml \ + ArcOfCirclePy.xml \ + ArcOfEllipsePy.xml \ + BRepOffsetAPI_MakePipeShellPy.xml \ + CirclePy.xml \ + EllipsePy.xml \ + HyperbolaPy.xml \ + ParabolaPy.xml \ + OffsetCurvePy.xml \ + GeometryPy.xml \ + GeometryCurvePy.xml \ + GeometrySurfacePy.xml \ + LinePy.xml \ + PointPy.xml \ + BezierCurvePy.xml \ + BSplineCurvePy.xml \ + PlanePy.xml \ + ConePy.xml \ + CylinderPy.xml \ + SpherePy.xml \ + ToroidPy.xml \ + BezierSurfacePy.xml \ + BSplineSurfacePy.xml \ + OffsetSurfacePy.xml \ + RectangularTrimmedSurfacePy.xml \ + SurfaceOfExtrusionPy.xml \ + SurfaceOfRevolutionPy.xml \ + PartFeaturePy.xml \ + FeaturePythonPy.xml \ + Part2DObjectPy.xml \ + TopoShapePy.xml \ + TopoShapeCompSolidPy.xml \ + TopoShapeCompoundPy.xml \ + TopoShapeEdgePy.xml \ + TopoShapeFacePy.xml \ + TopoShapeShellPy.xml \ + TopoShapeSolidPy.xml \ + TopoShapeVertexPy.xml \ + TopoShapeWirePy.xml \ + CMakeLists.txt diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 7912f968b9..093d95958c 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -172,6 +172,10 @@ Gui::MenuItem* Workbench::setupMenuBar() const Gui::MenuItem* cons = new Gui::MenuItem(); cons->setCommand("Sketcher constraints"); SketcherGui::addSketcherWorkbenchConstraints( *cons ); + + Gui::MenuItem* consaccel = new Gui::MenuItem(); + consaccel->setCommand("Sketcher tools"); + SketcherGui::addSketcherWorkbenchTools(*consaccel); Gui::MenuItem* part = new Gui::MenuItem; root->insertItem(item, part); @@ -233,6 +237,10 @@ Gui::ToolBarItem* Workbench::setupToolBars() const cons->setCommand("Sketcher constraints"); SketcherGui::addSketcherWorkbenchConstraints( *cons ); + Gui::ToolBarItem* consaccel = new Gui::ToolBarItem(root); + consaccel->setCommand("Sketcher tools"); + SketcherGui::addSketcherWorkbenchTools( *consaccel ); + return root; } diff --git a/src/Mod/Sketcher/App/Constraint.cpp b/src/Mod/Sketcher/App/Constraint.cpp index b9d1c04056..416b2ca9d6 100644 --- a/src/Mod/Sketcher/App/Constraint.cpp +++ b/src/Mod/Sketcher/App/Constraint.cpp @@ -43,6 +43,7 @@ const int Constraint::GeoUndef = -2000; Constraint::Constraint() : Type(None), + AlignmentType(Undef), Name(""), Value(0.0), First(GeoUndef), @@ -58,6 +59,7 @@ Constraint::Constraint() Constraint::Constraint(const Constraint& from) : Type(from.Type), + AlignmentType(from.AlignmentType), Name(from.Name), Value(from.Value), First(from.First), @@ -92,18 +94,22 @@ unsigned int Constraint::getMemSize (void) const void Constraint::Save (Writer &writer) const { - writer.Stream() << writer.ind() << "" + writer.Stream() << writer.ind() << "Type==InternalAlignment) + writer.Stream() + << "InternalAlignmentType=\"" << (int)AlignmentType << "\" "; + writer.Stream() + << "Value=\"" << Value << "\" " + << "First=\"" << First << "\" " + << "FirstPos=\"" << (int) FirstPos << "\" " + << "Second=\"" << Second << "\" " + << "SecondPos=\"" << (int) SecondPos << "\" " + << "Third=\"" << Third << "\" " + << "ThirdPos=\"" << (int) ThirdPos << "\" " + << "LabelDistance=\"" << LabelDistance << "\" " + << "LabelPosition=\"" << LabelPosition << "\" />" << std::endl; } @@ -118,6 +124,11 @@ void Constraint::Restore(XMLReader &reader) Second = reader.getAttributeAsInteger("Second"); SecondPos = (PointPos) reader.getAttributeAsInteger("SecondPos"); + if(this->Type==InternalAlignment) + AlignmentType = (InternalAlignmentType) reader.getAttributeAsInteger("InternalAlignmentType"); + else + AlignmentType = Undef; + // read the third geo group if present if (reader.hasAttribute("Third")) { Third = reader.getAttributeAsInteger("Third"); diff --git a/src/Mod/Sketcher/App/Constraint.h b/src/Mod/Sketcher/App/Constraint.h index 520363a795..18adacbd29 100644 --- a/src/Mod/Sketcher/App/Constraint.h +++ b/src/Mod/Sketcher/App/Constraint.h @@ -31,21 +31,30 @@ namespace Sketcher { enum ConstraintType { - None, - Coincident, - Horizontal, - Vertical, - Parallel, - Tangent, - Distance, - DistanceX, - DistanceY, - Angle, - Perpendicular, - Radius, - Equal, - PointOnObject, - Symmetric + None = 0, + Coincident = 1, + Horizontal = 2, + Vertical = 3, + Parallel = 4, + Tangent = 5, + Distance = 6, + DistanceX = 7, + DistanceY = 8, + Angle = 9, + Perpendicular = 10, + Radius = 11, + Equal = 12, + PointOnObject = 13, + Symmetric = 14, + InternalAlignment = 15 +}; + +enum InternalAlignmentType { + Undef = 0, + EllipseMajorDiameter = 1, + EllipseMinorDiameter = 2, + EllipseFocus1 = 3, + EllipseFocus2 = 4 }; /// define if you want to use the end or start point @@ -74,6 +83,7 @@ public: public: ConstraintType Type; + InternalAlignmentType AlignmentType; std::string Name; double Value; int First; diff --git a/src/Mod/Sketcher/App/ConstraintPyImp.cpp b/src/Mod/Sketcher/App/ConstraintPyImp.cpp index 1c235cb1d7..bef00372f6 100644 --- a/src/Mod/Sketcher/App/ConstraintPyImp.cpp +++ b/src/Mod/Sketcher/App/ConstraintPyImp.cpp @@ -93,6 +93,20 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/) this->getConstraintPtr()->Type = Equal; valid = true; } + else if (strstr(ConstraintType,"InternalAlignment") != NULL) { + this->getConstraintPtr()->Type = InternalAlignment; + + valid = true; + if(strstr(ConstraintType,"EllipseMajorDiameter") != NULL) + this->getConstraintPtr()->AlignmentType=EllipseMajorDiameter; + else if(strstr(ConstraintType,"EllipseMinorDiameter") != NULL) + this->getConstraintPtr()->AlignmentType=EllipseMinorDiameter; + else { + this->getConstraintPtr()->AlignmentType=Undef; + valid = false; + } + } + if (valid) { this->getConstraintPtr()->First = FirstIndex; this->getConstraintPtr()->Second = SecondIndex; @@ -155,6 +169,20 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/) this->getConstraintPtr()->Type = PointOnObject; valid = true; } + else if (strstr(ConstraintType,"InternalAlignment") != NULL) { + this->getConstraintPtr()->Type = InternalAlignment; + + valid = true; + + if(strstr(ConstraintType,"EllipseFocus1") != NULL) + this->getConstraintPtr()->AlignmentType=EllipseFocus1; + else if(strstr(ConstraintType,"EllipseFocus2") != NULL) + this->getConstraintPtr()->AlignmentType=EllipseFocus2; + else { + this->getConstraintPtr()->AlignmentType=Undef; + valid = false; + } + } if (valid) { this->getConstraintPtr()->First = FirstIndex; this->getConstraintPtr()->FirstPos = (Sketcher::PointPos) FirstPos; @@ -340,17 +368,27 @@ std::string ConstraintPy::representation(void) const std::stringstream result; result << "getConstraintPtr()->Type) { - case None : result << "'None'>";break; - case DistanceX : result << "'DistanceX'>";break; - case DistanceY : result << "'DistanceY'>";break; - case Coincident : result << "'Coincident'>";break; - case Horizontal : result << "'Horizontal' (" << getConstraintPtr()->First << ")>";break; - case Vertical : result << "'Vertical' (" << getConstraintPtr()->First << ")>";break; - case Parallel : result << "'Parallel'>";break; - case Tangent : result << "'Tangent'>";break; - case Distance : result << "'Distance'>";break; - case Angle : result << "'Angle'>";break; - default : result << "'?'>";break; + case None : result << "'None'>";break; + case DistanceX : result << "'DistanceX'>";break; + case DistanceY : result << "'DistanceY'>";break; + case Coincident : result << "'Coincident'>";break; + case Horizontal : result << "'Horizontal' (" << getConstraintPtr()->First << ")>";break; + case Vertical : result << "'Vertical' (" << getConstraintPtr()->First << ")>";break; + case Parallel : result << "'Parallel'>";break; + case Tangent : result << "'Tangent'>";break; + case Distance : result << "'Distance'>";break; + case Angle : result << "'Angle'>";break; + case InternalAlignment : + switch(this->getConstraintPtr()->AlignmentType) { + case Undef : result << "'InternalAlignment:Undef'>";break; + case EllipseMajorDiameter : result << "'InternalAlignment:EllipseMajorDiameter'>";break; + case EllipseMinorDiameter : result << "'InternalAlignment:EllipseMinorDiameter'>";break; + case EllipseFocus1 : result << "'InternalAlignment:EllipseFocus1'>";break; + case EllipseFocus2 : result << "'InternalAlignment:EllipseFocus2'>";break; + default : result << "'InternalAlignment:?'>";break; + } + break; + default : result << "'?'>";break; } return result.str(); } diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index fa59c0e57b..7faf6470b4 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -78,6 +79,8 @@ void Sketch::clear(void) Lines.clear(); Arcs.clear(); Circles.clear(); + Ellipses.clear(); + ArcsOfEllipse.clear(); // deleting the doubles allocated with new for (std::vector::iterator it = Parameters.begin(); it != Parameters.end(); ++it) @@ -142,6 +145,8 @@ const char* nameByType(Sketch::GeoType type) return "circle"; case Sketch::Ellipse: return "ellipse"; + case Sketch::ArcOfEllipse: + return "arcofellipse"; case Sketch::None: default: return "unknown"; @@ -164,10 +169,18 @@ int Sketch::addGeometry(const Part::Geometry *geo, bool fixed) const GeomCircle *circle = dynamic_cast(geo); // create the definition struct for that geom return addCircle(*circle, fixed); + } else if (geo->getTypeId() == GeomEllipse::getClassTypeId()) { // add a ellipse + const GeomEllipse *ellipse = dynamic_cast(geo); + // create the definition struct for that geom + return addEllipse(*ellipse, fixed); } else if (geo->getTypeId() == GeomArcOfCircle::getClassTypeId()) { // add an arc const GeomArcOfCircle *aoc = dynamic_cast(geo); // create the definition struct for that geom return addArc(*aoc, fixed); + } else if (geo->getTypeId() == GeomArcOfEllipse::getClassTypeId()) { // add an arc + const GeomArcOfEllipse *aoe = dynamic_cast(geo); + // create the definition struct for that geom + return addArcOfEllipse(*aoe, fixed); } else { Base::Exception("Sketch::addGeometry(): Unknown or unsupported type added to a sketch"); return 0; @@ -341,6 +354,99 @@ int Sketch::addArc(const Part::GeomArcOfCircle &circleSegment, bool fixed) return Geoms.size()-1; } + + +int Sketch::addArcOfEllipse(const Part::GeomArcOfEllipse &ellipseSegment, bool fixed) +{ + std::vector ¶ms = fixed ? FixParameters : Parameters; + + // create our own copy + GeomArcOfEllipse *aoe = static_cast(ellipseSegment.clone()); + // create the definition struct for that geom + GeoDef def; + def.geo = aoe; + def.type = ArcOfEllipse; + + Base::Vector3d center = aoe->getCenter(); + Base::Vector3d startPnt = aoe->getStartPoint(); + Base::Vector3d endPnt = aoe->getEndPoint(); + double radmaj = aoe->getMajorRadius(); + double radmin = aoe->getMinorRadius(); + double phi = aoe->getAngleXU(); + + double dist_C_F = sqrt(radmaj*radmaj-radmin*radmin); + // solver parameters + Base::Vector3d focus1 = center+dist_C_F*Vector3d(cos(phi), sin(phi),0); //+x + + double startAngle, endAngle; + aoe->getRange(startAngle, endAngle); + + GCS::Point p1, p2, p3; + GCS::Point f1; + + params.push_back(new double(startPnt.x)); + params.push_back(new double(startPnt.y)); + p1.x = params[params.size()-2]; + p1.y = params[params.size()-1]; + + params.push_back(new double(endPnt.x)); + params.push_back(new double(endPnt.y)); + p2.x = params[params.size()-2]; + p2.y = params[params.size()-1]; + + params.push_back(new double(center.x)); + params.push_back(new double(center.y)); + p3.x = params[params.size()-2]; + p3.y = params[params.size()-1]; + + params.push_back(new double(focus1.x)); + params.push_back(new double(focus1.y)); + f1.x = params[params.size()-2]; + f1.y = params[params.size()-1]; + + def.startPointId = Points.size(); + Points.push_back(p1); + def.endPointId = Points.size(); + Points.push_back(p2); + def.midPointId = Points.size(); + Points.push_back(p3); + + Points.push_back(f1); + + + // add the radius parameters + params.push_back(new double(radmin)); + double *rmin = params[params.size()-1]; + params.push_back(new double(startAngle)); + double *a1 = params[params.size()-1]; + params.push_back(new double(endAngle)); + double *a2 = params[params.size()-1]; + + + + // set the arc for later constraints + GCS::ArcOfEllipse a; + a.start = p1; + a.end = p2; + a.center = p3; + a.focus1 = f1; + a.radmin = rmin; + a.startAngle = a1; + a.endAngle = a2; + def.index = ArcsOfEllipse.size(); + ArcsOfEllipse.push_back(a); + + // store complete set + Geoms.push_back(def); + + // arcs require an ArcRules constraint for the end points + if (!fixed) + GCSsys.addConstraintArcOfEllipseRules(a); // TODO: ArcOfEllipse implementation. + + // return the position of the newly added geometry + return Geoms.size()-1; +} + int Sketch::addCircle(const Part::GeomCircle &cir, bool fixed) { std::vector ¶ms = fixed ? FixParameters : Parameters; @@ -384,8 +490,66 @@ int Sketch::addCircle(const Part::GeomCircle &cir, bool fixed) return Geoms.size()-1; } -int Sketch::addEllipse(const Part::GeomEllipse &ellipse, bool fixed) +int Sketch::addEllipse(const Part::GeomEllipse &elip, bool fixed) { + // TODO: Ellipse + std::vector ¶ms = fixed ? FixParameters : Parameters; + + // create our own copy + GeomEllipse *elips = static_cast(elip.clone()); + // create the definition struct for that geom + GeoDef def; + def.geo = elips; + def.type = Ellipse; + + Base::Vector3d center = elips->getCenter(); + double radmaj = elips->getMajorRadius(); + double radmin = elips->getMinorRadius(); + double phi = elips->getAngleXU(); + + double dist_C_F = sqrt(radmaj*radmaj-radmin*radmin); + // solver parameters + Base::Vector3d focus1 = center+dist_C_F*Vector3d(cos(phi), sin(phi),0); //+x + //double *radmin; + + GCS::Point c; + + params.push_back(new double(center.x)); + params.push_back(new double(center.y)); + c.x = params[params.size()-2]; + c.y = params[params.size()-1]; + + def.midPointId = Points.size(); // this takes midPointId+1 + Points.push_back(c); + + GCS::Point f1; + + params.push_back(new double(focus1.x)); + params.push_back(new double(focus1.y)); + f1.x = params[params.size()-2]; + f1.y = params[params.size()-1]; + + //def.midPointId = Points.size(); + Points.push_back(f1); + + + + // add the radius parameters + params.push_back(new double(radmin)); + double *rmin = params[params.size()-1]; + + // set the ellipse for later constraints + GCS::Ellipse e; + e.focus1 = f1; + e.center = c; + e.radmin = rmin; + + def.index = Ellipses.size(); + Ellipses.push_back(e); + + // store complete set + Geoms.push_back(def); + // return the position of the newly added geometry return Geoms.size()-1; } @@ -422,7 +586,11 @@ Py::Tuple Sketch::getPyGeometry(void) const } else if (it->type == Ellipse) { GeomEllipse *ellipse = dynamic_cast(it->geo->clone()); tuple[i] = Py::asObject(new EllipsePy(ellipse)); - } else { + } else if (it->type == ArcOfEllipse) { + GeomArcOfEllipse *ellipse = dynamic_cast(it->geo->clone()); + tuple[i] = Py::asObject(new ArcOfEllipsePy(ellipse)); + } + else { // not implemented type in the sketch! } } @@ -549,6 +717,22 @@ int Sketch::addConstraint(const Constraint *constraint) rtn = addSymmetricConstraint(constraint->First,constraint->FirstPos, constraint->Second,constraint->SecondPos,constraint->Third); break; + case InternalAlignment: + switch(constraint->AlignmentType) { + case EllipseMajorDiameter: + rtn = addInternalAlignmentEllipseMajorDiameter(constraint->First,constraint->Second); + break; + case EllipseMinorDiameter: + rtn = addInternalAlignmentEllipseMinorDiameter(constraint->First,constraint->Second); + break; + case EllipseFocus1: + rtn = addInternalAlignmentEllipseFocus1(constraint->First,constraint->Second); + break; + case EllipseFocus2: + rtn = addInternalAlignmentEllipseFocus2(constraint->First,constraint->Second); + break; + } + break; case None: break; } @@ -861,6 +1045,15 @@ int Sketch::addPerpendicularConstraint(int geoId1, PointPos pos1, int geoId2) GCSsys.addConstraintPointOnLine(p2, l1, tag); return ConstraintsCounter; } + else if (Geoms[geoId2].type == Ellipse) { + // TODO: Ellipse + GCS::Ellipse &c2 = Ellipses[Geoms[geoId2].index]; + GCS::Point &p2 = Points[Geoms[geoId2].midPointId]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintPointOnEllipse(p1, c2, tag); + GCSsys.addConstraintPointOnLine(p2, l1, tag); + return ConstraintsCounter; + } } else if (Geoms[geoId1].type == Arc) { GCS::Arc &a1 = Arcs[Geoms[geoId1].index]; @@ -871,7 +1064,8 @@ int Sketch::addPerpendicularConstraint(int geoId1, PointPos pos1, int geoId2) GCSsys.addConstraintPointOnLine(a1.center, l2, tag); return ConstraintsCounter; } - else if (Geoms[geoId2].type == Arc || Geoms[geoId2].type == Circle) { + else if (Geoms[geoId2].type == Arc || Geoms[geoId2].type == Circle || Geoms[geoId2].type == Ellipse) { + // TODO: ellipse real implementation int tag = ++ConstraintsCounter; GCS::Point ¢er = Points[Geoms[geoId2].midPointId]; double *radius; @@ -879,10 +1073,15 @@ int Sketch::addPerpendicularConstraint(int geoId1, PointPos pos1, int geoId2) GCS::Arc &a2 = Arcs[Geoms[geoId2].index]; radius = a2.rad; } - else { + else if (Geoms[geoId2].type == Circle) { GCS::Circle &c2 = Circles[Geoms[geoId2].index]; radius = c2.rad; } + else { + // TODO: Ellipse + GCS::Ellipse &c2 = Ellipses[Geoms[geoId2].index]; + radius = c2.radmin; + } if (pos1 == start) GCSsys.addConstraintPerpendicularCircle2Arc(center, radius, a1, tag); else if (pos1 == end) @@ -1026,6 +1225,18 @@ int Sketch::addTangentConstraint(int geoId1, int geoId2) int tag = ++ConstraintsCounter; GCSsys.addConstraintTangent(l, c, tag); return ConstraintsCounter; + } else if (Geoms[geoId2].type == Ellipse) { + // TODO: real implementation + GCS::Ellipse &e = Ellipses[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangent(l, e, tag); + return ConstraintsCounter; + } else if (Geoms[geoId2].type == ArcOfEllipse) { + // TODO: real implementation + GCS::ArcOfEllipse &a = ArcsOfEllipse[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangent(l, a, tag); + return ConstraintsCounter; } } else if (Geoms[geoId1].type == Circle) { GCS::Circle &c = Circles[Geoms[geoId1].index]; @@ -1034,12 +1245,33 @@ int Sketch::addTangentConstraint(int geoId1, int geoId2) int tag = ++ConstraintsCounter; GCSsys.addConstraintTangent(c, c2, tag); return ConstraintsCounter; - } else if (Geoms[geoId2].type == Arc) { + } else if (Geoms[geoId2].type == Ellipse) { + // TODO: real implementation + GCS::Ellipse &e = Ellipses[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangent(e, c, tag); + return ConstraintsCounter; + } + else if (Geoms[geoId2].type == Arc) { GCS::Arc &a = Arcs[Geoms[geoId2].index]; int tag = ++ConstraintsCounter; GCSsys.addConstraintTangent(c, a, tag); return ConstraintsCounter; } + } else if (Geoms[geoId1].type == Ellipse) { + GCS::Ellipse &e = Ellipses[Geoms[geoId1].index]; + // TODO: Ellipse + if (Geoms[geoId2].type == Circle) { + GCS::Circle &c = Circles[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangent(e, c, tag); + return ConstraintsCounter; + } else if (Geoms[geoId2].type == Arc) { + GCS::Arc &a = Arcs[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangent(e, a, tag); + return ConstraintsCounter; + } } else if (Geoms[geoId1].type == Arc) { GCS::Arc &a = Arcs[Geoms[geoId1].index]; if (Geoms[geoId2].type == Circle) { @@ -1047,6 +1279,12 @@ int Sketch::addTangentConstraint(int geoId1, int geoId2) int tag = ++ConstraintsCounter; GCSsys.addConstraintTangent(c, a, tag); return ConstraintsCounter; + } else if (Geoms[geoId2].type == Ellipse) { + // TODO: Ellipse + GCS::Ellipse &e = Ellipses[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangent(e, a, tag); + return ConstraintsCounter; } else if (Geoms[geoId2].type == Arc) { GCS::Arc &a2 = Arcs[Geoms[geoId2].index]; int tag = ++ConstraintsCounter; @@ -1096,6 +1334,14 @@ int Sketch::addTangentConstraint(int geoId1, PointPos pos1, int geoId2) GCSsys.addConstraintTangent(l1, c2, tag); return ConstraintsCounter; } + else if (Geoms[geoId2].type == Ellipse) { + // TODO: Ellipse + GCS::Ellipse &e = Ellipses[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintPointOnEllipse(p1, e, tag); + GCSsys.addConstraintTangent(l1, e, tag); + return ConstraintsCounter; + } } else if (Geoms[geoId1].type == Arc) { GCS::Arc &a1 = Arcs[Geoms[geoId1].index]; @@ -1125,6 +1371,19 @@ int Sketch::addTangentConstraint(int geoId1, PointPos pos1, int geoId2) GCSsys.addConstraintTangentArc2Circle(a1, c2, tag); return ConstraintsCounter; } + } else if (Geoms[geoId2].type == Ellipse) { + // TODO: Ellipse + GCS::Ellipse &e = Ellipses[Geoms[geoId2].index]; + if (pos1 == start) { + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangentEllipse2Arc(e, a1, tag); + return ConstraintsCounter; + } + else if (pos1 == end) { + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangentArc2Ellipse(a1, e, tag); + return ConstraintsCounter; + } } } return -1; @@ -1198,6 +1457,35 @@ int Sketch::addTangentConstraint(int geoId1, PointPos pos1, int geoId2, PointPos else return -1; } + if (Geoms[geoId2].type == ArcOfEllipse) { + GCS::ArcOfEllipse &a2 = ArcsOfEllipse[Geoms[geoId2].index]; + if (pos2 == start) { + if (pos1 == start) { + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangentLine2ArcOfEllipse(l1.p2, l1.p1, l1, a2, tag); + return ConstraintsCounter; + } + else if (pos1 == end) { + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangentLine2ArcOfEllipse(l1.p1, l1.p2, l1, a2, tag); + return ConstraintsCounter; + } + } + else if (pos2 == end) { + if (pos1 == start) { + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangentArcOfEllipse2Line(a2, l1, l1.p1, l1.p2, tag); + return ConstraintsCounter; + } + else if (pos1 == end) { + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangentArcOfEllipse2Line(a2, l1, l1.p2, l1.p1, tag); + return ConstraintsCounter; + } + } + else + return -1; + } } else if (Geoms[geoId1].type == Arc) { GCS::Arc &a1 = Arcs[Geoms[geoId1].index]; @@ -1309,7 +1597,7 @@ int Sketch::addDistanceConstraint(int geoId1, PointPos pos1, int geoId2, PointPo return -1; } -int Sketch::addRadiusConstraint(int geoId, double value) +int Sketch::addRadiusConstraint(int geoId, double value, int radiusnumber) { geoId = checkGeoId(geoId); @@ -1448,6 +1736,18 @@ int Sketch::addEqualConstraint(int geoId1, int geoId2) else std::swap(geoId1, geoId2); } + // TODO: Ellipse + if (Geoms[geoId2].type == Ellipse) { + if (Geoms[geoId1].type == Ellipse) { + GCS::Ellipse &e1 = Ellipses[Geoms[geoId1].index]; + GCS::Ellipse &e2 = Ellipses[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintEqualRadii(e1, e2, tag); + return ConstraintsCounter; + } + else + std::swap(geoId1, geoId2); + } if (Geoms[geoId1].type == Circle) { GCS::Circle &c1 = Circles[Geoms[geoId1].index]; @@ -1502,6 +1802,18 @@ int Sketch::addPointOnObjectConstraint(int geoId1, PointPos pos1, int geoId2) GCSsys.addConstraintPointOnCircle(p1, c, tag); return ConstraintsCounter; } + else if (Geoms[geoId2].type == Ellipse) { + GCS::Ellipse &e = Ellipses[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintPointOnEllipse(p1, e, tag); + return ConstraintsCounter; + } + else if (Geoms[geoId2].type == ArcOfEllipse) { + GCS::ArcOfEllipse &a = ArcsOfEllipse[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintPointOnArcOfEllipse(p1, a, tag); + return ConstraintsCounter; + } } return -1; } @@ -1555,6 +1867,167 @@ int Sketch::addSymmetricConstraint(int geoId1, PointPos pos1, int geoId2, PointP return -1; } +int Sketch::addInternalAlignmentEllipseMajorDiameter(int geoId1, int geoId2) +{ + std::swap(geoId1, geoId2); + + geoId1 = checkGeoId(geoId1); + geoId2 = checkGeoId(geoId2); + + if (Geoms[geoId1].type != Ellipse && Geoms[geoId1].type != ArcOfEllipse) + return -1; + if (Geoms[geoId2].type != Line) + return -1; + + int pointId1 = getPointId(geoId2, start); + int pointId2 = getPointId(geoId2, end); + + if (pointId1 >= 0 && pointId1 < int(Points.size()) && + pointId2 >= 0 && pointId2 < int(Points.size())) { + GCS::Point &p1 = Points[pointId1]; + GCS::Point &p2 = Points[pointId2]; + + if(Geoms[geoId1].type == Ellipse) { + GCS::Ellipse &e1 = Ellipses[Geoms[geoId1].index]; + + // constraints + // 1. start point with ellipse -a + // 2. end point with ellipse +a + int tag = ++ConstraintsCounter; + GCSsys.addConstraintInternalAlignmentEllipseMajorDiameter(e1, p1, p2, tag); + return ConstraintsCounter; + + } + else { + GCS::ArcOfEllipse &a1 = ArcsOfEllipse[Geoms[geoId1].index]; + + int tag = ++ConstraintsCounter; + GCSsys.addConstraintInternalAlignmentEllipseMajorDiameter(a1, p1, p2, tag); + return ConstraintsCounter; + } + } + return -1; +} + +int Sketch::addInternalAlignmentEllipseMinorDiameter(int geoId1, int geoId2) +{ + std::swap(geoId1, geoId2); + + geoId1 = checkGeoId(geoId1); + geoId2 = checkGeoId(geoId2); + + if (Geoms[geoId1].type != Ellipse && Geoms[geoId1].type != ArcOfEllipse) + return -1; + if (Geoms[geoId2].type != Line) + return -1; + + int pointId1 = getPointId(geoId2, start); + int pointId2 = getPointId(geoId2, end); + + if (pointId1 >= 0 && pointId1 < int(Points.size()) && + pointId2 >= 0 && pointId2 < int(Points.size())) { + GCS::Point &p1 = Points[pointId1]; + GCS::Point &p2 = Points[pointId2]; + + if(Geoms[geoId1].type == Ellipse) { + GCS::Ellipse &e1 = Ellipses[Geoms[geoId1].index]; + + // constraints + // 1. start point with ellipse -a + // 2. end point with ellipse +a + int tag = ++ConstraintsCounter; + GCSsys.addConstraintInternalAlignmentEllipseMinorDiameter(e1, p1, p2, tag); + return ConstraintsCounter; + } + else { + GCS::ArcOfEllipse &a1 = ArcsOfEllipse[Geoms[geoId1].index]; + + int tag = ++ConstraintsCounter; + GCSsys.addConstraintInternalAlignmentEllipseMinorDiameter(a1, p1, p2, tag); + return ConstraintsCounter; + } + } + return -1; +} + +int Sketch::addInternalAlignmentEllipseFocus1(int geoId1, int geoId2) +{ + std::swap(geoId1, geoId2); + + geoId1 = checkGeoId(geoId1); + geoId2 = checkGeoId(geoId2); + + if (Geoms[geoId1].type != Ellipse && Geoms[geoId1].type != ArcOfEllipse) + return -1; + if (Geoms[geoId2].type != Point) + return -1; + + int pointId1 = getPointId(geoId2, start); + + if (pointId1 >= 0 && pointId1 < int(Points.size())) { + GCS::Point &p1 = Points[pointId1]; + + if(Geoms[geoId1].type == Ellipse) { + GCS::Ellipse &e1 = Ellipses[Geoms[geoId1].index]; + + // constraints + // 1. start point with ellipse -a + // 2. end point with ellipse +a + int tag = ++ConstraintsCounter; + GCSsys.addConstraintInternalAlignmentEllipseFocus1(e1, p1, tag); + return ConstraintsCounter; + } + else { + GCS::ArcOfEllipse &a1 = ArcsOfEllipse[Geoms[geoId1].index]; + + int tag = ++ConstraintsCounter; + GCSsys.addConstraintInternalAlignmentEllipseFocus1(a1, p1, tag); + return ConstraintsCounter; + } + } + return -1; +} + + +int Sketch::addInternalAlignmentEllipseFocus2(int geoId1, int geoId2) +{ + std::swap(geoId1, geoId2); + + geoId1 = checkGeoId(geoId1); + geoId2 = checkGeoId(geoId2); + + if (Geoms[geoId1].type != Ellipse && Geoms[geoId1].type != ArcOfEllipse) + return -1; + if (Geoms[geoId2].type != Point) + return -1; + + int pointId1 = getPointId(geoId2, start); + + if (pointId1 >= 0 && pointId1 < int(Points.size())) { + GCS::Point &p1 = Points[pointId1]; + + if(Geoms[geoId1].type == Ellipse) { + GCS::Ellipse &e1 = Ellipses[Geoms[geoId1].index]; + + // constraints + // 1. start point with ellipse -a + // 2. end point with ellipse +a + int tag = ++ConstraintsCounter; + GCSsys.addConstraintInternalAlignmentEllipseFocus2(e1, p1, tag); + return ConstraintsCounter; + } + else { + GCS::ArcOfEllipse &a1 = ArcsOfEllipse[Geoms[geoId1].index]; + + int tag = ++ConstraintsCounter; + GCSsys.addConstraintInternalAlignmentEllipseFocus2(a1, p1, tag); + return ConstraintsCounter; + } + } + return -1; +} + + bool Sketch::updateGeometry() { int i=0; @@ -1589,6 +2062,25 @@ bool Sketch::updateGeometry() ); aoc->setRadius(*myArc.rad); aoc->setRange(*myArc.startAngle, *myArc.endAngle); + } else if (it->type == ArcOfEllipse) { + GCS::ArcOfEllipse &myArc = ArcsOfEllipse[it->index]; + + GeomArcOfEllipse *aoe = dynamic_cast(it->geo); + + Base::Vector3d center = Vector3d(*Points[it->midPointId].x, *Points[it->midPointId].y, 0.0); + Base::Vector3d f1 = Vector3d(*Points[it->midPointId+1].x, *Points[it->midPointId+1].y, 0.0); + double radmin = *ArcsOfEllipse[it->index].radmin; + + Base::Vector3d fd=f1-center; + double radmaj = sqrt(fd*fd+radmin*radmin); + + double phi = atan2(fd.y,fd.x); + + aoe->setCenter(center); + aoe->setMajorRadius(radmaj); + aoe->setMinorRadius(radmin); + aoe->setAngleXU(phi); + aoe->setRange(*myArc.startAngle, *myArc.endAngle); } else if (it->type == Circle) { GeomCircle *circ = dynamic_cast(it->geo); circ->setCenter(Vector3d(*Points[it->midPointId].x, @@ -1596,6 +2088,23 @@ bool Sketch::updateGeometry() 0.0) ); circ->setRadius(*Circles[it->index].rad); + } else if (it->type == Ellipse) { + // TODO: Ellipse + GeomEllipse *ellipse = dynamic_cast(it->geo); + + Base::Vector3d center = Vector3d(*Points[it->midPointId].x, *Points[it->midPointId].y, 0.0); + Base::Vector3d f1 = Vector3d(*Points[it->midPointId+1].x, *Points[it->midPointId+1].y, 0.0); + double radmin = *Ellipses[it->index].radmin; + + Base::Vector3d fd=f1-center; + double radmaj = sqrt(fd*fd+radmin*radmin); + + double phi = atan2(fd.y,fd.x); + + ellipse->setCenter(center); + ellipse->setMajorRadius(radmaj); + ellipse->setMinorRadius(radmin); + ellipse->setAngleXU(phi); } } catch (Base::Exception e) { Base::Console().Error("Updating geometry: Error build geometry(%d): %s\n", @@ -1771,6 +2280,72 @@ int Sketch::initMove(int geoId, PointPos pos, bool fine) GCSsys.rescaleConstraint(i-1, 0.01); GCSsys.rescaleConstraint(i, 0.01); } + } else if (Geoms[geoId].type == Ellipse) { + // TODO: Ellipse + GCS::Point ¢er = Points[Geoms[geoId].midPointId]; + GCS::Point p0,p1; + if (pos == mid) { + MoveParameters.resize(2); // cx,cy + p0.x = &MoveParameters[0]; + p0.y = &MoveParameters[1]; + *p0.x = *center.x; + *p0.y = *center.y; + GCSsys.addConstraintP2PCoincident(p0,center,-1); + } else if (pos == none) { + // TODO: Ellipse + MoveParameters.resize(4); // x,y,cx,cy + GCS::Ellipse &e = Ellipses[Geoms[geoId].index]; + p0.x = &MoveParameters[0]; + p0.y = &MoveParameters[1]; + *p0.x = *center.x; + *p0.y = *center.y + *e.radmin; + GCSsys.addConstraintPointOnEllipse(p0,e,-1); + p1.x = &MoveParameters[2]; + p1.y = &MoveParameters[3]; + *p1.x = *center.x; + *p1.y = *center.y; + int i=GCSsys.addConstraintP2PCoincident(p1,center,-1); + GCSsys.rescaleConstraint(i-1, 0.01); + GCSsys.rescaleConstraint(i, 0.01); + } + } else if (Geoms[geoId].type == ArcOfEllipse) { + // TODO: ArcOfEllipse + GCS::Point ¢er = Points[Geoms[geoId].midPointId]; + GCS::Point p0,p1; + if (pos == mid) { + MoveParameters.resize(2); // cx,cy + p0.x = &MoveParameters[0]; + p0.y = &MoveParameters[1]; + *p0.x = *center.x; + *p0.y = *center.y; + GCSsys.addConstraintP2PCoincident(p0,center,-1); + } else if (pos == start || pos == end || pos == none) { + // TODO: Ellipse + MoveParameters.resize(4); // x,y,cx,cy + if (pos == start || pos == end) { + GCS::Point &p = (pos == start) ? Points[Geoms[geoId].startPointId] + : Points[Geoms[geoId].endPointId];; + p0.x = &MoveParameters[0]; + p0.y = &MoveParameters[1]; + *p0.x = *p.x; + *p0.y = *p.y; + GCSsys.addConstraintP2PCoincident(p0,p,-1); + } else if (pos == none) { + GCS::ArcOfEllipse &a = ArcsOfEllipse[Geoms[geoId].index]; + p0.x = &MoveParameters[0]; + p0.y = &MoveParameters[1]; + *p0.x = *center.x; + *p0.y = *center.y + *a.radmin; + GCSsys.addConstraintPointOnArcOfEllipse(p0,a,-1); + } + p1.x = &MoveParameters[2]; + p1.y = &MoveParameters[3]; + *p1.x = *center.x; + *p1.y = *center.y; + int i=GCSsys.addConstraintP2PCoincident(p1,center,-1); + GCSsys.rescaleConstraint(i-1, 0.01); + GCSsys.rescaleConstraint(i, 0.01); + } } else if (Geoms[geoId].type == Arc) { GCS::Point ¢er = Points[Geoms[geoId].midPointId]; GCS::Point p0,p1; @@ -1858,6 +2433,16 @@ int Sketch::movePoint(int geoId, PointPos pos, Base::Vector3d toPoint, bool rela MoveParameters[0] = toPoint.x; MoveParameters[1] = toPoint.y; } + } else if (Geoms[geoId].type == Ellipse) { + if (pos == mid || pos == none) { + MoveParameters[0] = toPoint.x; + MoveParameters[1] = toPoint.y; + } + } else if (Geoms[geoId].type == ArcOfEllipse) { + if (pos == start || pos == end || pos == mid || pos == none) { + MoveParameters[0] = toPoint.x; + MoveParameters[1] = toPoint.y; + } } return solve(); @@ -1886,6 +2471,33 @@ int Sketch::getPointId(int geoId, PointPos pos) const return -1; } +int Sketch::getVisiblePointId(int geoId, PointPos pos) const +{ + // do a range check first + if (geoId < 0 || geoId >= (int)Geoms.size()) + return -1; + + int invisiblepoints = 0; + int i; + + // calculate the number of points in the solver that are not visible in the UI + for(i=0;i #include #include "Constraint.h" - -#include "freegcs/GCS.h" + +#include "freegcs/GCS.h" #include @@ -82,6 +82,8 @@ public: /// retrieves the index of a point int getPointId(int geoId, PointPos pos) const; + int getVisiblePointId(int geoId, PointPos pos) const; + /// retrieves a point Base::Vector3d getPoint(int geoId, PointPos pos); @@ -119,8 +121,10 @@ public: int addArc(const Part::GeomArcOfCircle &circleSegment, bool fixed=false); /// add a circle int addCircle(const Part::GeomCircle &circle, bool fixed=false); - /// add a ellipse + /// add an ellipse int addEllipse(const Part::GeomEllipse &ellipse, bool fixed=false); + /// add an arc of ellipse + int addArcOfEllipse(const Part::GeomArcOfEllipse &ellipseSegment, bool fixed=false); //@} @@ -163,11 +167,14 @@ public: int addTangentConstraint(int geoId1, PointPos pos1, int geoId2); int addTangentConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2); /// add a radius constraint on a circle or an arc - int addRadiusConstraint(int geoId, double value); + int addRadiusConstraint(int geoId, double value, int radiusnumber=0); /// add an angle constraint on a line or between two lines int addAngleConstraint(int geoId, double value); int addAngleConstraint(int geoId1, int geoId2, double value); int addAngleConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, double value); + /// add ellipse XDir axis angle constraint with respect to XAxis or a lines + int addEllipseAngleXUConstraint(int geoId, double value); + int addEllipseAngleXUConstraint(int geoId1, int geoId2, double value); /// add an equal length or radius constraints between two lines or between circles and arcs int addEqualConstraint(int geoId1, int geoId2); /// add a point on line constraint @@ -177,14 +184,24 @@ public: /// add a symmetric constraint between three points, the last point is in the middle of the first two int addSymmetricConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, int geoId3, PointPos pos3); //@} - + + /// Internal Alignment constraints + //@{ + /// add InternalAlignmentEllipseMajorDiameter to a line and an ellipse + int addInternalAlignmentEllipseMajorDiameter(int geoId1, int geoId2); + int addInternalAlignmentEllipseMinorDiameter(int geoId1, int geoId2); + int addInternalAlignmentEllipseFocus1(int geoId1, int geoId2); + int addInternalAlignmentEllipseFocus2(int geoId1, int geoId2); + //@} + enum GeoType { None = 0, Point = 1, // 1 Point(start), 2 Parameters(x,y) Line = 2, // 2 Points(start,end), 4 Parameters(x1,y1,x2,y2) Arc = 3, // 3 Points(start,end,mid), (4)+5 Parameters((x1,y1,x2,y2),x,y,r,a1,a2) Circle = 4, // 1 Point(mid), 3 Parameters(x,y,r) - Ellipse = 5 + Ellipse = 5, // 1 Point(mid), 5 Parameters(x,y,r1,r2,phi) phi=angle xaxis of elipse with respect of sketch xaxis// TODO: Ellipse + ArcOfEllipse = 6 }; float SolveTime; @@ -217,6 +234,8 @@ protected: std::vector Lines; std::vector Arcs; std::vector Circles; + std::vector Ellipses; + std::vector ArcsOfEllipse; bool isInitMove; bool isFine; diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 05e2f9b485..a49a346b13 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -257,6 +257,10 @@ Base::Vector3d SketchObject::getPoint(int GeoId, PointPos PosId) const const Part::GeomCircle *circle = dynamic_cast(geo); if (PosId == mid) return circle->getCenter(); + } else if (geo->getTypeId() == Part::GeomEllipse::getClassTypeId()) { + const Part::GeomEllipse *ellipse = dynamic_cast(geo); + if (PosId == mid) + return ellipse->getCenter(); } else if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { const Part::GeomArcOfCircle *aoc = dynamic_cast(geo); if (PosId == start) @@ -265,6 +269,14 @@ Base::Vector3d SketchObject::getPoint(int GeoId, PointPos PosId) const return aoc->getEndPoint(); else if (PosId == mid) return aoc->getCenter(); + } else if (geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { + const Part::GeomArcOfEllipse *aoc = dynamic_cast(geo); + if (PosId == start) + return aoc->getStartPoint(); + else if (PosId == end) + return aoc->getEndPoint(); + else if (PosId == mid) + return aoc->getCenter(); } return Base::Vector3d(); @@ -944,7 +956,9 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point) return 0; } - + } else if (geo->getTypeId() == Part::GeomEllipse::getClassTypeId()) { + // TODO: Ellipse Trim support + return 0; } else if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { const Part::GeomArcOfCircle *aoc = dynamic_cast(geo); Base::Vector3d center = aoc->getCenter(); @@ -1490,6 +1504,9 @@ void SketchObject::rebuildVertexIndex(void) } else if ((*it)->getTypeId() == Part::GeomCircle::getClassTypeId()) { VertexId2GeoId.push_back(i); VertexId2PosId.push_back(mid); + } else if ((*it)->getTypeId() == Part::GeomEllipse::getClassTypeId()) { + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(mid); } else if ((*it)->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { VertexId2GeoId.push_back(i); VertexId2PosId.push_back(start); @@ -1497,6 +1514,13 @@ void SketchObject::rebuildVertexIndex(void) VertexId2PosId.push_back(end); VertexId2GeoId.push_back(i); VertexId2PosId.push_back(mid); + } else if ((*it)->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(start); + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(end); + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(mid); } } } diff --git a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp index c4029076ca..df890c2ae5 100644 --- a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp +++ b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp @@ -90,7 +90,9 @@ PyObject* SketchObjectPy::addGeometry(PyObject *args) } else if (geo->getTypeId() == Part::GeomPoint::getClassTypeId() || geo->getTypeId() == Part::GeomCircle::getClassTypeId() || + geo->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() || + geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { ret = this->getSketchObjectPtr()->addGeometry(geo); } @@ -131,7 +133,9 @@ PyObject* SketchObjectPy::addGeometry(PyObject *args) } else if (geo->getTypeId() == Part::GeomPoint::getClassTypeId() || geo->getTypeId() == Part::GeomCircle::getClassTypeId() || + geo->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() || + geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { geoList.push_back(geo); } diff --git a/src/Mod/Sketcher/App/freegcs/Constraints.cpp b/src/Mod/Sketcher/App/freegcs/Constraints.cpp index e8de23beee..4d2df2f1ac 100644 --- a/src/Mod/Sketcher/App/freegcs/Constraints.cpp +++ b/src/Mod/Sketcher/App/freegcs/Constraints.cpp @@ -912,4 +912,1237 @@ double ConstraintTangentCircumf::grad(double *param) return scale * deriv; } +// ConstraintPointOnEllipse +ConstraintPointOnEllipse::ConstraintPointOnEllipse(Point &p, Ellipse &e) +{ + pvec.push_back(p.x); + pvec.push_back(p.y); + pvec.push_back(e.center.x); + pvec.push_back(e.center.y); + pvec.push_back(e.focus1.x); + pvec.push_back(e.focus1.y); + pvec.push_back(e.radmin); + origpvec = pvec; + rescale(); +} + +ConstraintPointOnEllipse::ConstraintPointOnEllipse(Point &p, ArcOfEllipse &a) +{ + pvec.push_back(p.x); + pvec.push_back(p.y); + pvec.push_back(a.center.x); + pvec.push_back(a.center.y); + pvec.push_back(a.focus1.x); + pvec.push_back(a.focus1.y); + pvec.push_back(a.radmin); + origpvec = pvec; + rescale(); +} + +ConstraintType ConstraintPointOnEllipse::getTypeId() +{ + return P2OnEllipse; +} + +void ConstraintPointOnEllipse::rescale(double coef) +{ + scale = coef * 1; +} + +double ConstraintPointOnEllipse::error() +{ + double X_0 = *p1x(); + double Y_0 = *p1y(); + double X_c = *cx(); + double Y_c = *cy(); + double X_F1 = *f1x(); + double Y_F1 = *f1y(); + double b = *rmin(); + + double err=sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2)) + sqrt(pow(X_0 + + X_F1 - 2*X_c, 2) + pow(Y_0 + Y_F1 - 2*Y_c, 2)) - 2*sqrt(pow(b, 2) + + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)); + return scale * err; +} + +double ConstraintPointOnEllipse::grad(double *param) +{ + double deriv=0.; + if (param == p1x() || param == p1y() || + param == f1x() || param == f1y() || + param == cx() || param == cy() || + param == rmin()) { + + double X_0 = *p1x(); + double Y_0 = *p1y(); + double X_c = *cx(); + double Y_c = *cy(); + double X_F1 = *f1x(); + double Y_F1 = *f1y(); + double b = *rmin(); + + if (param == p1x()) + deriv += (X_0 - X_F1)/sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2)) + + (X_0 + X_F1 - 2*X_c)/sqrt(pow(X_0 + X_F1 - 2*X_c, 2) + pow(Y_0 + Y_F1 - + 2*Y_c, 2)); + if (param == p1y()) + deriv += (Y_0 - Y_F1)/sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2)) + + (Y_0 + Y_F1 - 2*Y_c)/sqrt(pow(X_0 + X_F1 - 2*X_c, 2) + pow(Y_0 + Y_F1 - + 2*Y_c, 2)); + if (param == f1x()) + deriv += -(X_0 - X_F1)/sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2)) - + 2*(X_F1 - X_c)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)) + + (X_0 + X_F1 - 2*X_c)/sqrt(pow(X_0 + X_F1 - 2*X_c, 2) + pow(Y_0 + Y_F1 + - 2*Y_c, 2)); + if (param == f1y()) + deriv +=-(Y_0 - Y_F1)/sqrt(pow(X_0 - X_F1, 2) + pow(Y_0 - Y_F1, 2)) - + 2*(Y_F1 - Y_c)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)) + + (Y_0 + Y_F1 - 2*Y_c)/sqrt(pow(X_0 + X_F1 - 2*X_c, 2) + pow(Y_0 + Y_F1 + - 2*Y_c, 2)); + if (param == cx()) + deriv += 2*(X_F1 - X_c)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2)) - 2*(X_0 + X_F1 - 2*X_c)/sqrt(pow(X_0 + X_F1 - 2*X_c, 2) + + pow(Y_0 + Y_F1 - 2*Y_c, 2)); + if (param == cy()) + deriv +=2*(Y_F1 - Y_c)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2)) - 2*(Y_0 + Y_F1 - 2*Y_c)/sqrt(pow(X_0 + X_F1 - 2*X_c, 2) + + pow(Y_0 + Y_F1 - 2*Y_c, 2)); + if (param == rmin()) + deriv += -2*b/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2)); + } + return scale * deriv; +} + +// ConstraintEllipseTangentLine +ConstraintEllipseTangentLine::ConstraintEllipseTangentLine(Line &l, Ellipse &e) +{ + pvec.push_back(l.p1.x); + pvec.push_back(l.p1.y); + pvec.push_back(l.p2.x); + pvec.push_back(l.p2.y); + pvec.push_back(e.center.x); + pvec.push_back(e.center.y); + pvec.push_back(e.focus1.x); + pvec.push_back(e.focus1.y); + pvec.push_back(e.radmin); + origpvec = pvec; + rescale(); +} + +ConstraintEllipseTangentLine::ConstraintEllipseTangentLine(Line &l, ArcOfEllipse &a) +{ + pvec.push_back(l.p1.x); + pvec.push_back(l.p1.y); + pvec.push_back(l.p2.x); + pvec.push_back(l.p2.y); + pvec.push_back(a.center.x); + pvec.push_back(a.center.y); + pvec.push_back(a.focus1.x); + pvec.push_back(a.focus1.y); + pvec.push_back(a.radmin); + origpvec = pvec; + rescale(); +} + +ConstraintType ConstraintEllipseTangentLine::getTypeId() +{ + return TangentEllipseLine; +} + +void ConstraintEllipseTangentLine::rescale(double coef) +{ + scale = coef * 1; +} + +double ConstraintEllipseTangentLine::error() +{ + double X_1 = *p1x(); + double Y_1 = *p1y(); + double X_2 = *p2x(); + double Y_2 = *p2y(); + double X_c = *cx(); + double Y_c = *cy(); + double X_F1 = *f1x(); + double Y_F1 = *f1y(); + double b = *rmin(); + + double err=-2*(sqrt(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2) + pow(Y_1, 2) - + 2*Y_1*Y_2 + pow(Y_2, 2))*sqrt(pow(X_F1, 2) - 2*X_F1*X_c + pow(X_c, 2) + + pow(Y_F1, 2) - 2*Y_F1*Y_c + pow(Y_c, 2) + pow(b, 2)) - sqrt(pow(X_1, + 2)*(pow(X_c, 2) + pow(Y_c, 2)) - 2*X_1*X_2*(pow(X_c, 2) + pow(Y_c, 2)) + + pow(X_2, 2)*(pow(X_c, 2) + pow(Y_c, 2)) + pow(X_F1, 2)*(pow(X_1, 2) - + 2*X_1*X_2 + pow(X_2, 2)) - 2*X_F1*(pow(X_1, 2)*X_c - 2*X_1*X_2*X_c + + pow(X_2, 2)*X_c) + pow(Y_1, 2)*(pow(X_2, 2) - 2*X_2*X_c + pow(X_c, 2) + + pow(Y_c, 2)) + 2*Y_1*(X_1*X_2*Y_c - pow(X_2, 2)*Y_c - X_F1*(X_1*Y_c - + X_2*Y_c)) + pow(Y_2, 2)*(pow(X_1, 2) - 2*X_1*X_c + pow(X_c, 2) + + pow(Y_c, 2)) - 2*Y_2*(pow(X_1, 2)*Y_c - X_1*X_2*Y_c - X_F1*(X_1*Y_c - + X_2*Y_c) + Y_1*(-X_1*X_c + X_2*(X_1 - X_c) + pow(X_c, 2) + pow(Y_c, 2))) + + pow(Y_F1, 2)*(pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)) - + 2*Y_F1*(pow(Y_1, 2)*Y_c - Y_1*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2)) + + pow(Y_2, 2)*Y_c + Y_2*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2) - + 2*Y_1*Y_c))))/sqrt(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2) + pow(Y_1, 2) - + 2*Y_1*Y_2 + pow(Y_2, 2)); + return scale * err; +} + +double ConstraintEllipseTangentLine::grad(double *param) +{ + double deriv=0.; + if (param == p1x() || param == p1y() || + param == p2x() || param == p2y() || + param == f1x() || param == f1y() || + param == cx() || param == cy() || + param == rmin()) { + + double X_1 = *p1x(); + double Y_1 = *p1y(); + double X_2 = *p2x(); + double Y_2 = *p2y(); + double X_c = *cx(); + double Y_c = *cy(); + double X_F1 = *f1x(); + double Y_F1 = *f1y(); + double b = *rmin(); + + // DeepSOIC equation + // http://forum.freecadweb.org/viewtopic.php?f=10&t=7520&start=140 + // Partials: + + if (param == p1x()) + deriv += 2*(X_1 - X_2)*(sqrt(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2) + + pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2))*sqrt(pow(X_F1, 2) - 2*X_F1*X_c + + pow(X_c, 2) + pow(Y_F1, 2) - 2*Y_F1*Y_c + pow(Y_c, 2) + pow(b, 2)) - + sqrt(pow(X_1, 2)*(pow(X_c, 2) + pow(Y_c, 2)) - 2*X_1*X_2*(pow(X_c, 2) + + pow(Y_c, 2)) + pow(X_2, 2)*(pow(X_c, 2) + pow(Y_c, 2)) + pow(X_F1, + 2)*(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2)) - 2*X_F1*(pow(X_1, 2)*X_c - + 2*X_1*X_2*X_c + pow(X_2, 2)*X_c) + pow(Y_1, 2)*(pow(X_2, 2) - 2*X_2*X_c + + pow(X_c, 2) + pow(Y_c, 2)) + 2*Y_1*(X_1*X_2*Y_c - pow(X_2, 2)*Y_c - + X_F1*(X_1*Y_c - X_2*Y_c)) + pow(Y_2, 2)*(pow(X_1, 2) - 2*X_1*X_c + + pow(X_c, 2) + pow(Y_c, 2)) - 2*Y_2*(pow(X_1, 2)*Y_c - X_1*X_2*Y_c - + X_F1*(X_1*Y_c - X_2*Y_c) + Y_1*(-X_1*X_c + X_2*(X_1 - X_c) + pow(X_c, 2) + + pow(Y_c, 2))) + pow(Y_F1, 2)*(pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)) - + 2*Y_F1*(pow(Y_1, 2)*Y_c - Y_1*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2)) + + pow(Y_2, 2)*Y_c + Y_2*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2) - + 2*Y_1*Y_c))))/pow(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2) + pow(Y_1, 2) - + 2*Y_1*Y_2 + pow(Y_2, 2), 3.0/2.0) - 2*((X_1 - X_2)*sqrt(pow(X_F1, 2) - + 2*X_F1*X_c + pow(X_c, 2) + pow(Y_F1, 2) - 2*Y_F1*Y_c + pow(Y_c, 2) + + pow(b, 2))/sqrt(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2) + pow(Y_1, 2) - + 2*Y_1*Y_2 + pow(Y_2, 2)) - (X_1*(pow(X_c, 2) + pow(Y_c, 2)) - + X_2*(pow(X_c, 2) + pow(Y_c, 2)) + pow(X_F1, 2)*(X_1 - X_2) - + 2*X_F1*(X_1*X_c - X_2*X_c) + Y_1*(X_2*Y_c - X_F1*Y_c) + pow(Y_2, 2)*(X_1 + - X_c) - Y_2*(2*X_1*Y_c - X_2*Y_c - X_F1*Y_c + Y_1*(X_2 - X_c)) + + Y_F1*(Y_1*(X_F1 - X_c) - Y_2*(X_F1 - X_c)))/sqrt(pow(X_1, 2)*(pow(X_c, + 2) + pow(Y_c, 2)) - 2*X_1*X_2*(pow(X_c, 2) + pow(Y_c, 2)) + pow(X_2, + 2)*(pow(X_c, 2) + pow(Y_c, 2)) + pow(X_F1, 2)*(pow(X_1, 2) - 2*X_1*X_2 + + pow(X_2, 2)) - 2*X_F1*(pow(X_1, 2)*X_c - 2*X_1*X_2*X_c + pow(X_2, + 2)*X_c) + pow(Y_1, 2)*(pow(X_2, 2) - 2*X_2*X_c + pow(X_c, 2) + pow(Y_c, + 2)) + 2*Y_1*(X_1*X_2*Y_c - pow(X_2, 2)*Y_c - X_F1*(X_1*Y_c - X_2*Y_c)) + + pow(Y_2, 2)*(pow(X_1, 2) - 2*X_1*X_c + pow(X_c, 2) + pow(Y_c, 2)) - + 2*Y_2*(pow(X_1, 2)*Y_c - X_1*X_2*Y_c - X_F1*(X_1*Y_c - X_2*Y_c) + + Y_1*(-X_1*X_c + X_2*(X_1 - X_c) + pow(X_c, 2) + pow(Y_c, 2))) + + pow(Y_F1, 2)*(pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)) - 2*Y_F1*(pow(Y_1, + 2)*Y_c - Y_1*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2)) + pow(Y_2, 2)*Y_c + + Y_2*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2) - 2*Y_1*Y_c))))/sqrt(pow(X_1, + 2) - 2*X_1*X_2 + pow(X_2, 2) + pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)); + if (param == p1y()) + deriv += 2*(Y_1 - Y_2)*(sqrt(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2) + + pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2))*sqrt(pow(X_F1, 2) - 2*X_F1*X_c + + pow(X_c, 2) + pow(Y_F1, 2) - 2*Y_F1*Y_c + pow(Y_c, 2) + pow(b, 2)) - + sqrt(pow(X_1, 2)*(pow(X_c, 2) + pow(Y_c, 2)) - 2*X_1*X_2*(pow(X_c, 2) + + pow(Y_c, 2)) + pow(X_2, 2)*(pow(X_c, 2) + pow(Y_c, 2)) + pow(X_F1, + 2)*(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2)) - 2*X_F1*(pow(X_1, 2)*X_c - + 2*X_1*X_2*X_c + pow(X_2, 2)*X_c) + pow(Y_1, 2)*(pow(X_2, 2) - 2*X_2*X_c + + pow(X_c, 2) + pow(Y_c, 2)) + 2*Y_1*(X_1*X_2*Y_c - pow(X_2, 2)*Y_c - + X_F1*(X_1*Y_c - X_2*Y_c)) + pow(Y_2, 2)*(pow(X_1, 2) - 2*X_1*X_c + + pow(X_c, 2) + pow(Y_c, 2)) - 2*Y_2*(pow(X_1, 2)*Y_c - X_1*X_2*Y_c - + X_F1*(X_1*Y_c - X_2*Y_c) + Y_1*(-X_1*X_c + X_2*(X_1 - X_c) + pow(X_c, 2) + + pow(Y_c, 2))) + pow(Y_F1, 2)*(pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)) - + 2*Y_F1*(pow(Y_1, 2)*Y_c - Y_1*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2)) + + pow(Y_2, 2)*Y_c + Y_2*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2) - + 2*Y_1*Y_c))))/pow(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2) + pow(Y_1, 2) - + 2*Y_1*Y_2 + pow(Y_2, 2), 3.0/2.0) - 2*((Y_1 - Y_2)*sqrt(pow(X_F1, 2) - + 2*X_F1*X_c + pow(X_c, 2) + pow(Y_F1, 2) - 2*Y_F1*Y_c + pow(Y_c, 2) + + pow(b, 2))/sqrt(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2) + pow(Y_1, 2) - + 2*Y_1*Y_2 + pow(Y_2, 2)) - (X_1*X_2*Y_c - pow(X_2, 2)*Y_c - + X_F1*(X_1*Y_c - X_2*Y_c) + Y_1*(pow(X_2, 2) - 2*X_2*X_c + pow(X_c, 2) + + pow(Y_c, 2)) - Y_2*(-X_1*X_c + X_2*(X_1 - X_c) + pow(X_c, 2) + pow(Y_c, + 2)) + pow(Y_F1, 2)*(Y_1 - Y_2) + Y_F1*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - + X_2) - 2*Y_1*Y_c + 2*Y_2*Y_c))/sqrt(pow(X_1, 2)*(pow(X_c, 2) + pow(Y_c, + 2)) - 2*X_1*X_2*(pow(X_c, 2) + pow(Y_c, 2)) + pow(X_2, 2)*(pow(X_c, 2) + + pow(Y_c, 2)) + pow(X_F1, 2)*(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2)) - + 2*X_F1*(pow(X_1, 2)*X_c - 2*X_1*X_2*X_c + pow(X_2, 2)*X_c) + pow(Y_1, + 2)*(pow(X_2, 2) - 2*X_2*X_c + pow(X_c, 2) + pow(Y_c, 2)) + + 2*Y_1*(X_1*X_2*Y_c - pow(X_2, 2)*Y_c - X_F1*(X_1*Y_c - X_2*Y_c)) + + pow(Y_2, 2)*(pow(X_1, 2) - 2*X_1*X_c + pow(X_c, 2) + pow(Y_c, 2)) - + 2*Y_2*(pow(X_1, 2)*Y_c - X_1*X_2*Y_c - X_F1*(X_1*Y_c - X_2*Y_c) + + Y_1*(-X_1*X_c + X_2*(X_1 - X_c) + pow(X_c, 2) + pow(Y_c, 2))) + + pow(Y_F1, 2)*(pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)) - 2*Y_F1*(pow(Y_1, + 2)*Y_c - Y_1*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2)) + pow(Y_2, 2)*Y_c + + Y_2*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2) - 2*Y_1*Y_c))))/sqrt(pow(X_1, + 2) - 2*X_1*X_2 + pow(X_2, 2) + pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)); + if (param == p2x()) + deriv += -2*(X_1 - X_2)*(sqrt(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2) + + pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2))*sqrt(pow(X_F1, 2) - 2*X_F1*X_c + + pow(X_c, 2) + pow(Y_F1, 2) - 2*Y_F1*Y_c + pow(Y_c, 2) + pow(b, 2)) - + sqrt(pow(X_1, 2)*(pow(X_c, 2) + pow(Y_c, 2)) - 2*X_1*X_2*(pow(X_c, 2) + + pow(Y_c, 2)) + pow(X_2, 2)*(pow(X_c, 2) + pow(Y_c, 2)) + pow(X_F1, + 2)*(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2)) - 2*X_F1*(pow(X_1, 2)*X_c - + 2*X_1*X_2*X_c + pow(X_2, 2)*X_c) + pow(Y_1, 2)*(pow(X_2, 2) - 2*X_2*X_c + + pow(X_c, 2) + pow(Y_c, 2)) + 2*Y_1*(X_1*X_2*Y_c - pow(X_2, 2)*Y_c - + X_F1*(X_1*Y_c - X_2*Y_c)) + pow(Y_2, 2)*(pow(X_1, 2) - 2*X_1*X_c + + pow(X_c, 2) + pow(Y_c, 2)) - 2*Y_2*(pow(X_1, 2)*Y_c - X_1*X_2*Y_c - + X_F1*(X_1*Y_c - X_2*Y_c) + Y_1*(-X_1*X_c + X_2*(X_1 - X_c) + pow(X_c, 2) + + pow(Y_c, 2))) + pow(Y_F1, 2)*(pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)) - + 2*Y_F1*(pow(Y_1, 2)*Y_c - Y_1*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2)) + + pow(Y_2, 2)*Y_c + Y_2*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2) - + 2*Y_1*Y_c))))/pow(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2) + pow(Y_1, 2) - + 2*Y_1*Y_2 + pow(Y_2, 2), 3.0/2.0) + 2*((X_1 - X_2)*sqrt(pow(X_F1, 2) - + 2*X_F1*X_c + pow(X_c, 2) + pow(Y_F1, 2) - 2*Y_F1*Y_c + pow(Y_c, 2) + + pow(b, 2))/sqrt(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2) + pow(Y_1, 2) - + 2*Y_1*Y_2 + pow(Y_2, 2)) - (X_1*(pow(X_c, 2) + pow(Y_c, 2)) - + X_2*(pow(X_c, 2) + pow(Y_c, 2)) + pow(X_F1, 2)*(X_1 - X_2) - + 2*X_F1*(X_1*X_c - X_2*X_c) - pow(Y_1, 2)*(X_2 - X_c) - Y_1*(X_1*Y_c - + 2*X_2*Y_c + X_F1*Y_c) + Y_2*(-X_1*Y_c + X_F1*Y_c + Y_1*(X_1 - X_c)) + + Y_F1*(Y_1*(X_F1 - X_c) - Y_2*(X_F1 - X_c)))/sqrt(pow(X_1, 2)*(pow(X_c, + 2) + pow(Y_c, 2)) - 2*X_1*X_2*(pow(X_c, 2) + pow(Y_c, 2)) + pow(X_2, + 2)*(pow(X_c, 2) + pow(Y_c, 2)) + pow(X_F1, 2)*(pow(X_1, 2) - 2*X_1*X_2 + + pow(X_2, 2)) - 2*X_F1*(pow(X_1, 2)*X_c - 2*X_1*X_2*X_c + pow(X_2, + 2)*X_c) + pow(Y_1, 2)*(pow(X_2, 2) - 2*X_2*X_c + pow(X_c, 2) + pow(Y_c, + 2)) + 2*Y_1*(X_1*X_2*Y_c - pow(X_2, 2)*Y_c - X_F1*(X_1*Y_c - X_2*Y_c)) + + pow(Y_2, 2)*(pow(X_1, 2) - 2*X_1*X_c + pow(X_c, 2) + pow(Y_c, 2)) - + 2*Y_2*(pow(X_1, 2)*Y_c - X_1*X_2*Y_c - X_F1*(X_1*Y_c - X_2*Y_c) + + Y_1*(-X_1*X_c + X_2*(X_1 - X_c) + pow(X_c, 2) + pow(Y_c, 2))) + + pow(Y_F1, 2)*(pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)) - 2*Y_F1*(pow(Y_1, + 2)*Y_c - Y_1*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2)) + pow(Y_2, 2)*Y_c + + Y_2*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2) - 2*Y_1*Y_c))))/sqrt(pow(X_1, + 2) - 2*X_1*X_2 + pow(X_2, 2) + pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)); + if (param == p2y()) + deriv += -2*(Y_1 - Y_2)*(sqrt(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2) + + pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2))*sqrt(pow(X_F1, 2) - 2*X_F1*X_c + + pow(X_c, 2) + pow(Y_F1, 2) - 2*Y_F1*Y_c + pow(Y_c, 2) + pow(b, 2)) - + sqrt(pow(X_1, 2)*(pow(X_c, 2) + pow(Y_c, 2)) - 2*X_1*X_2*(pow(X_c, 2) + + pow(Y_c, 2)) + pow(X_2, 2)*(pow(X_c, 2) + pow(Y_c, 2)) + pow(X_F1, + 2)*(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2)) - 2*X_F1*(pow(X_1, 2)*X_c - + 2*X_1*X_2*X_c + pow(X_2, 2)*X_c) + pow(Y_1, 2)*(pow(X_2, 2) - 2*X_2*X_c + + pow(X_c, 2) + pow(Y_c, 2)) + 2*Y_1*(X_1*X_2*Y_c - pow(X_2, 2)*Y_c - + X_F1*(X_1*Y_c - X_2*Y_c)) + pow(Y_2, 2)*(pow(X_1, 2) - 2*X_1*X_c + + pow(X_c, 2) + pow(Y_c, 2)) - 2*Y_2*(pow(X_1, 2)*Y_c - X_1*X_2*Y_c - + X_F1*(X_1*Y_c - X_2*Y_c) + Y_1*(-X_1*X_c + X_2*(X_1 - X_c) + pow(X_c, 2) + + pow(Y_c, 2))) + pow(Y_F1, 2)*(pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)) - + 2*Y_F1*(pow(Y_1, 2)*Y_c - Y_1*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2)) + + pow(Y_2, 2)*Y_c + Y_2*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2) - + 2*Y_1*Y_c))))/pow(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2) + pow(Y_1, 2) - + 2*Y_1*Y_2 + pow(Y_2, 2), 3.0/2.0) + 2*((Y_1 - Y_2)*sqrt(pow(X_F1, 2) - + 2*X_F1*X_c + pow(X_c, 2) + pow(Y_F1, 2) - 2*Y_F1*Y_c + pow(Y_c, 2) + + pow(b, 2))/sqrt(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2) + pow(Y_1, 2) - + 2*Y_1*Y_2 + pow(Y_2, 2)) - (pow(X_1, 2)*Y_c - X_1*X_2*Y_c - + X_F1*(X_1*Y_c - X_2*Y_c) + Y_1*(-X_1*X_c + X_2*(X_1 - X_c) + pow(X_c, 2) + + pow(Y_c, 2)) - Y_2*(pow(X_1, 2) - 2*X_1*X_c + pow(X_c, 2) + pow(Y_c, + 2)) + pow(Y_F1, 2)*(Y_1 - Y_2) + Y_F1*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - + X_2) - 2*Y_1*Y_c + 2*Y_2*Y_c))/sqrt(pow(X_1, 2)*(pow(X_c, 2) + pow(Y_c, + 2)) - 2*X_1*X_2*(pow(X_c, 2) + pow(Y_c, 2)) + pow(X_2, 2)*(pow(X_c, 2) + + pow(Y_c, 2)) + pow(X_F1, 2)*(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2)) - + 2*X_F1*(pow(X_1, 2)*X_c - 2*X_1*X_2*X_c + pow(X_2, 2)*X_c) + pow(Y_1, + 2)*(pow(X_2, 2) - 2*X_2*X_c + pow(X_c, 2) + pow(Y_c, 2)) + + 2*Y_1*(X_1*X_2*Y_c - pow(X_2, 2)*Y_c - X_F1*(X_1*Y_c - X_2*Y_c)) + + pow(Y_2, 2)*(pow(X_1, 2) - 2*X_1*X_c + pow(X_c, 2) + pow(Y_c, 2)) - + 2*Y_2*(pow(X_1, 2)*Y_c - X_1*X_2*Y_c - X_F1*(X_1*Y_c - X_2*Y_c) + + Y_1*(-X_1*X_c + X_2*(X_1 - X_c) + pow(X_c, 2) + pow(Y_c, 2))) + + pow(Y_F1, 2)*(pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)) - 2*Y_F1*(pow(Y_1, + 2)*Y_c - Y_1*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2)) + pow(Y_2, 2)*Y_c + + Y_2*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2) - 2*Y_1*Y_c))))/sqrt(pow(X_1, + 2) - 2*X_1*X_2 + pow(X_2, 2) + pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)); + if (param == f1x()) + deriv += -2*((X_F1 - X_c)*sqrt(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2) + + pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2))/sqrt(pow(X_F1, 2) - 2*X_F1*X_c + + pow(X_c, 2) + pow(Y_F1, 2) - 2*Y_F1*Y_c + pow(Y_c, 2) + pow(b, 2)) + + (pow(X_1, 2)*X_c - 2*X_1*X_2*X_c + pow(X_2, 2)*X_c - X_F1*(pow(X_1, 2) - + 2*X_1*X_2 + pow(X_2, 2)) + Y_1*(X_1*Y_c - X_2*Y_c) - Y_2*(X_1*Y_c - + X_2*Y_c) - Y_F1*(Y_1*(X_1 - X_2) - Y_2*(X_1 - X_2)))/sqrt(pow(X_1, + 2)*(pow(X_c, 2) + pow(Y_c, 2)) - 2*X_1*X_2*(pow(X_c, 2) + pow(Y_c, 2)) + + pow(X_2, 2)*(pow(X_c, 2) + pow(Y_c, 2)) + pow(X_F1, 2)*(pow(X_1, 2) - + 2*X_1*X_2 + pow(X_2, 2)) - 2*X_F1*(pow(X_1, 2)*X_c - 2*X_1*X_2*X_c + + pow(X_2, 2)*X_c) + pow(Y_1, 2)*(pow(X_2, 2) - 2*X_2*X_c + pow(X_c, 2) + + pow(Y_c, 2)) + 2*Y_1*(X_1*X_2*Y_c - pow(X_2, 2)*Y_c - X_F1*(X_1*Y_c - + X_2*Y_c)) + pow(Y_2, 2)*(pow(X_1, 2) - 2*X_1*X_c + pow(X_c, 2) + + pow(Y_c, 2)) - 2*Y_2*(pow(X_1, 2)*Y_c - X_1*X_2*Y_c - X_F1*(X_1*Y_c - + X_2*Y_c) + Y_1*(-X_1*X_c + X_2*(X_1 - X_c) + pow(X_c, 2) + pow(Y_c, 2))) + + pow(Y_F1, 2)*(pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)) - + 2*Y_F1*(pow(Y_1, 2)*Y_c - Y_1*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2)) + + pow(Y_2, 2)*Y_c + Y_2*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2) - + 2*Y_1*Y_c))))/sqrt(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2) + pow(Y_1, 2) - + 2*Y_1*Y_2 + pow(Y_2, 2)); + if (param == f1y()) + deriv +=-2*((Y_F1 - Y_c)*sqrt(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2) + + pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2))/sqrt(pow(X_F1, 2) - 2*X_F1*X_c + + pow(X_c, 2) + pow(Y_F1, 2) - 2*Y_F1*Y_c + pow(Y_c, 2) + pow(b, 2)) + + (pow(Y_1, 2)*Y_c - Y_1*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2)) + + pow(Y_2, 2)*Y_c + Y_2*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2) - + 2*Y_1*Y_c) - Y_F1*(pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)))/sqrt(pow(X_1, + 2)*(pow(X_c, 2) + pow(Y_c, 2)) - 2*X_1*X_2*(pow(X_c, 2) + pow(Y_c, 2)) + + pow(X_2, 2)*(pow(X_c, 2) + pow(Y_c, 2)) + pow(X_F1, 2)*(pow(X_1, 2) - + 2*X_1*X_2 + pow(X_2, 2)) - 2*X_F1*(pow(X_1, 2)*X_c - 2*X_1*X_2*X_c + + pow(X_2, 2)*X_c) + pow(Y_1, 2)*(pow(X_2, 2) - 2*X_2*X_c + pow(X_c, 2) + + pow(Y_c, 2)) + 2*Y_1*(X_1*X_2*Y_c - pow(X_2, 2)*Y_c - X_F1*(X_1*Y_c - + X_2*Y_c)) + pow(Y_2, 2)*(pow(X_1, 2) - 2*X_1*X_c + pow(X_c, 2) + + pow(Y_c, 2)) - 2*Y_2*(pow(X_1, 2)*Y_c - X_1*X_2*Y_c - X_F1*(X_1*Y_c - + X_2*Y_c) + Y_1*(-X_1*X_c + X_2*(X_1 - X_c) + pow(X_c, 2) + pow(Y_c, 2))) + + pow(Y_F1, 2)*(pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)) - + 2*Y_F1*(pow(Y_1, 2)*Y_c - Y_1*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2)) + + pow(Y_2, 2)*Y_c + Y_2*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2) - + 2*Y_1*Y_c))))/sqrt(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2) + pow(Y_1, 2) - + 2*Y_1*Y_2 + pow(Y_2, 2)); + if (param == cx()) + deriv += 2*((X_F1 - X_c)*sqrt(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2) + + pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2))/sqrt(pow(X_F1, 2) - 2*X_F1*X_c + + pow(X_c, 2) + pow(Y_F1, 2) - 2*Y_F1*Y_c + pow(Y_c, 2) + pow(b, 2)) + + (pow(X_1, 2)*X_c - 2*X_1*X_2*X_c + pow(X_2, 2)*X_c - X_F1*(pow(X_1, 2) - + 2*X_1*X_2 + pow(X_2, 2)) - pow(Y_1, 2)*(X_2 - X_c) + Y_1*Y_2*(X_1 + X_2 + - 2*X_c) - pow(Y_2, 2)*(X_1 - X_c) - Y_F1*(Y_1*(X_1 - X_2) - Y_2*(X_1 - + X_2)))/sqrt(pow(X_1, 2)*(pow(X_c, 2) + pow(Y_c, 2)) - + 2*X_1*X_2*(pow(X_c, 2) + pow(Y_c, 2)) + pow(X_2, 2)*(pow(X_c, 2) + + pow(Y_c, 2)) + pow(X_F1, 2)*(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2)) - + 2*X_F1*(pow(X_1, 2)*X_c - 2*X_1*X_2*X_c + pow(X_2, 2)*X_c) + pow(Y_1, + 2)*(pow(X_2, 2) - 2*X_2*X_c + pow(X_c, 2) + pow(Y_c, 2)) + + 2*Y_1*(X_1*X_2*Y_c - pow(X_2, 2)*Y_c - X_F1*(X_1*Y_c - X_2*Y_c)) + + pow(Y_2, 2)*(pow(X_1, 2) - 2*X_1*X_c + pow(X_c, 2) + pow(Y_c, 2)) - + 2*Y_2*(pow(X_1, 2)*Y_c - X_1*X_2*Y_c - X_F1*(X_1*Y_c - X_2*Y_c) + + Y_1*(-X_1*X_c + X_2*(X_1 - X_c) + pow(X_c, 2) + pow(Y_c, 2))) + + pow(Y_F1, 2)*(pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)) - 2*Y_F1*(pow(Y_1, + 2)*Y_c - Y_1*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2)) + pow(Y_2, 2)*Y_c + + Y_2*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2) - 2*Y_1*Y_c))))/sqrt(pow(X_1, + 2) - 2*X_1*X_2 + pow(X_2, 2) + pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)); + if (param == cy()) + deriv += 2*((Y_F1 - Y_c)*sqrt(pow(X_1, 2) - 2*X_1*X_2 + pow(X_2, 2) + + pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2))/sqrt(pow(X_F1, 2) - 2*X_F1*X_c + + pow(X_c, 2) + pow(Y_F1, 2) - 2*Y_F1*Y_c + pow(Y_c, 2) + pow(b, 2)) + + (pow(X_1, 2)*Y_c - 2*X_1*X_2*Y_c + pow(X_2, 2)*Y_c + pow(Y_1, 2)*Y_c + + Y_1*(X_1*X_2 - pow(X_2, 2) - X_F1*(X_1 - X_2)) + pow(Y_2, 2)*Y_c - + Y_2*(pow(X_1, 2) - X_1*X_2 - X_F1*(X_1 - X_2) + 2*Y_1*Y_c) - + Y_F1*(pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)))/sqrt(pow(X_1, 2)*(pow(X_c, + 2) + pow(Y_c, 2)) - 2*X_1*X_2*(pow(X_c, 2) + pow(Y_c, 2)) + pow(X_2, + 2)*(pow(X_c, 2) + pow(Y_c, 2)) + pow(X_F1, 2)*(pow(X_1, 2) - 2*X_1*X_2 + + pow(X_2, 2)) - 2*X_F1*(pow(X_1, 2)*X_c - 2*X_1*X_2*X_c + pow(X_2, + 2)*X_c) + pow(Y_1, 2)*(pow(X_2, 2) - 2*X_2*X_c + pow(X_c, 2) + pow(Y_c, + 2)) + 2*Y_1*(X_1*X_2*Y_c - pow(X_2, 2)*Y_c - X_F1*(X_1*Y_c - X_2*Y_c)) + + pow(Y_2, 2)*(pow(X_1, 2) - 2*X_1*X_c + pow(X_c, 2) + pow(Y_c, 2)) - + 2*Y_2*(pow(X_1, 2)*Y_c - X_1*X_2*Y_c - X_F1*(X_1*Y_c - X_2*Y_c) + + Y_1*(-X_1*X_c + X_2*(X_1 - X_c) + pow(X_c, 2) + pow(Y_c, 2))) + + pow(Y_F1, 2)*(pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)) - 2*Y_F1*(pow(Y_1, + 2)*Y_c - Y_1*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2)) + pow(Y_2, 2)*Y_c + + Y_2*(-X_1*X_c + X_2*X_c + X_F1*(X_1 - X_2) - 2*Y_1*Y_c))))/sqrt(pow(X_1, + 2) - 2*X_1*X_2 + pow(X_2, 2) + pow(Y_1, 2) - 2*Y_1*Y_2 + pow(Y_2, 2)); + if (param == rmin()) + deriv += -2*b/sqrt(pow(X_F1, 2) - 2*X_F1*X_c + pow(X_c, 2) + pow(Y_F1, + 2) - 2*Y_F1*Y_c + pow(Y_c, 2) + pow(b, 2)); + } + return scale * deriv; +} + +// ConstraintInternalAlignmentPoint2Ellipse +ConstraintInternalAlignmentPoint2Ellipse::ConstraintInternalAlignmentPoint2Ellipse(Ellipse &e, Point &p1, InternalAlignmentType alignmentType) +{ + pvec.push_back(p1.x); + pvec.push_back(p1.y); + pvec.push_back(e.center.x); + pvec.push_back(e.center.y); + pvec.push_back(e.focus1.x); + pvec.push_back(e.focus1.y); + pvec.push_back(e.radmin); + origpvec = pvec; + rescale(); + AlignmentType=alignmentType; +} + +ConstraintInternalAlignmentPoint2Ellipse::ConstraintInternalAlignmentPoint2Ellipse(ArcOfEllipse &a, Point &p1, InternalAlignmentType alignmentType) +{ + pvec.push_back(p1.x); + pvec.push_back(p1.y); + pvec.push_back(a.center.x); + pvec.push_back(a.center.y); + pvec.push_back(a.focus1.x); + pvec.push_back(a.focus1.y); + pvec.push_back(a.radmin); + origpvec = pvec; + rescale(); + AlignmentType=alignmentType; +} + +ConstraintType ConstraintInternalAlignmentPoint2Ellipse::getTypeId() +{ + return InternalAlignmentPoint2Ellipse; +} + +void ConstraintInternalAlignmentPoint2Ellipse::rescale(double coef) +{ + scale = coef * 1; +} + +double ConstraintInternalAlignmentPoint2Ellipse::error() +{ + // so first is to select the point (X_0,Y_0) in line to calculate + double X_1 = *p1x(); + double Y_1 = *p1y(); + double X_c = *cx(); + double Y_c = *cy(); + double X_F1 = *f1x(); + double Y_F1 = *f1y(); + double b = *rmin(); + + switch(AlignmentType) + { + case EllipsePositiveMajorX: + return scale * (X_1 - X_c - (X_F1 - X_c)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2))/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))); + break; + case EllipsePositiveMajorY: + return scale * (Y_1 - Y_c - (Y_F1 - Y_c)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2))/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))); + break; + case EllipseNegativeMajorX: + return scale * (X_1 - X_c + (X_F1 - X_c)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2))/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))); + break; + case EllipseNegativeMajorY: + return scale * (Y_1 - Y_c + (Y_F1 - Y_c)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2))/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))); + break; + case EllipsePositiveMinorX: + return scale * (X_1 - X_c + b*(Y_F1 - Y_c)/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2))); + break; + case EllipsePositiveMinorY: + return scale * (Y_1 - Y_c - b*(X_F1 - X_c)/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2))); + break; + case EllipseNegativeMinorX: + return scale * (X_1 - X_c - b*(Y_F1 - Y_c)/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2))); + break; + case EllipseNegativeMinorY: + return scale * (Y_1 - Y_c + b*(X_F1 - X_c)/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2))); + break; + case EllipseFocus2X: + return scale * (X_1 + X_F1 - 2*X_c); + break; + case EllipseFocus2Y: + return scale * (Y_1 + Y_F1 - 2*Y_c); + break; + default: + return 0; + } +} + +double ConstraintInternalAlignmentPoint2Ellipse::grad(double *param) +{ + double deriv=0.; + if (param == p1x() || param == p1y() || + param == f1x() || param == f1y() || + param == cx() || param == cy() || + param == rmin()) { + + double X_1 = *p1x(); + double Y_1 = *p1y(); + double X_c = *cx(); + double Y_c = *cy(); + double X_F1 = *f1x(); + double Y_F1 = *f1y(); + double b = *rmin(); + + if (param == p1x()) + switch(AlignmentType) + { + case EllipsePositiveMajorX: + deriv += 1; + break; + case EllipsePositiveMajorY: + deriv += 0; + break; + case EllipseNegativeMajorX: + deriv += 1; + break; + case EllipseNegativeMajorY: + deriv += 0; + break; + case EllipsePositiveMinorX: + deriv += 1; + break; + case EllipsePositiveMinorY: + deriv += 0; + break; + case EllipseNegativeMinorX: + deriv += 1; + break; + case EllipseNegativeMinorY: + deriv += 0; + break; + case EllipseFocus2X: + deriv += 1; + break; + case EllipseFocus2Y: + deriv += 0; + break; + default: + deriv+=0; + } + if (param == p1y()) + switch(AlignmentType) + { + case EllipsePositiveMajorX: + deriv += 0; + break; + case EllipsePositiveMajorY: + deriv += 1; + break; + case EllipseNegativeMajorX: + deriv += 0; + break; + case EllipseNegativeMajorY: + deriv += 1; + break; + case EllipsePositiveMinorX: + deriv += 0; + break; + case EllipsePositiveMinorY: + deriv += 1; + break; + case EllipseNegativeMinorX: + deriv += 0; + break; + case EllipseNegativeMinorY: + deriv += 1; + break; + case EllipseFocus2X: + deriv += 0; + break; + case EllipseFocus2Y: + deriv += 1; + break; + default: + deriv+=0; + } + if (param == f1x()) + switch(AlignmentType) + { + case EllipsePositiveMajorX: + deriv += -pow(X_F1 - X_c, 2)/(sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2))*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))) + + pow(X_F1 - X_c, 2)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2))/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L) - + sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))/sqrt(pow(X_F1 + - X_c, 2) + pow(Y_F1 - Y_c, 2)); + break; + case EllipsePositiveMajorY: + deriv += -(X_F1 - X_c)*(Y_F1 - Y_c)/(sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2))*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))) + + (X_F1 - X_c)*(Y_F1 - Y_c)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2))/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L); + break; + case EllipseNegativeMajorX: + deriv += pow(X_F1 - X_c, 2)/(sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2))*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))) - + pow(X_F1 - X_c, 2)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2))/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L) + + sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))/sqrt(pow(X_F1 + - X_c, 2) + pow(Y_F1 - Y_c, 2)); + break; + case EllipseNegativeMajorY: + deriv += (X_F1 - X_c)*(Y_F1 - Y_c)/(sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2))*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))) - + (X_F1 - X_c)*(Y_F1 - Y_c)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2))/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L); + break; + case EllipsePositiveMinorX: + deriv += -b*(X_F1 - X_c)*(Y_F1 - Y_c)/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2), 3.0L/2.0L); + break; + case EllipsePositiveMinorY: + deriv += b*pow(X_F1 - X_c, 2)/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2), 3.0L/2.0L) - b/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)); + break; + case EllipseNegativeMinorX: + deriv += b*(X_F1 - X_c)*(Y_F1 - Y_c)/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2), 3.0L/2.0L); + break; + case EllipseNegativeMinorY: + deriv += -b*pow(X_F1 - X_c, 2)/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2), 3.0L/2.0L) + b/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)); + break; + case EllipseFocus2X: + deriv += 1; + break; + case EllipseFocus2Y: + deriv+=0; + break; + default: + deriv+=0; + } + if (param == f1y()) + switch(AlignmentType) + { + case EllipsePositiveMajorX: + deriv += -(X_F1 - X_c)*(Y_F1 - Y_c)/(sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2))*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))) + + (X_F1 - X_c)*(Y_F1 - Y_c)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2))/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L); + break; + case EllipsePositiveMajorY: + deriv += -pow(Y_F1 - Y_c, 2)/(sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2))*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))) + + pow(Y_F1 - Y_c, 2)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2))/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L) - + sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))/sqrt(pow(X_F1 + - X_c, 2) + pow(Y_F1 - Y_c, 2)); + break; + case EllipseNegativeMajorX: + deriv += (X_F1 - X_c)*(Y_F1 - Y_c)/(sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2))*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))) - + (X_F1 - X_c)*(Y_F1 - Y_c)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2))/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L); + break; + case EllipseNegativeMajorY: + deriv += pow(Y_F1 - Y_c, 2)/(sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2))*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))) - + pow(Y_F1 - Y_c, 2)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2))/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L) + + sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))/sqrt(pow(X_F1 + - X_c, 2) + pow(Y_F1 - Y_c, 2)); + break; + case EllipsePositiveMinorX: + deriv += -b*pow(Y_F1 - Y_c, 2)/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2), 3.0L/2.0L) + b/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)); + break; + case EllipsePositiveMinorY: + deriv += b*(X_F1 - X_c)*(Y_F1 - Y_c)/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2), 3.0L/2.0L); + break; + case EllipseNegativeMinorX: + deriv += b*pow(Y_F1 - Y_c, 2)/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2), 3.0L/2.0L) - b/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)); + break; + case EllipseNegativeMinorY: + deriv += -b*(X_F1 - X_c)*(Y_F1 - Y_c)/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2), 3.0L/2.0L); + break; + case EllipseFocus2X: + deriv += 0; + break; + case EllipseFocus2Y: + deriv += 1; + break; + default: + deriv+=0; + } + if (param == cx()) + switch(AlignmentType) + { + case EllipsePositiveMajorX: + deriv += pow(X_F1 - X_c, 2)/(sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2))*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))) - + pow(X_F1 - X_c, 2)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2))/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L) - 1 + + sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))/sqrt(pow(X_F1 + - X_c, 2) + pow(Y_F1 - Y_c, 2)); + break; + case EllipsePositiveMajorY: + deriv += (X_F1 - X_c)*(Y_F1 - Y_c)/(sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2))*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))) - + (X_F1 - X_c)*(Y_F1 - Y_c)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2))/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L); + break; + case EllipseNegativeMajorX: + deriv += -pow(X_F1 - X_c, 2)/(sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2))*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))) + + pow(X_F1 - X_c, 2)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2))/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L) - 1 - + sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))/sqrt(pow(X_F1 + - X_c, 2) + pow(Y_F1 - Y_c, 2)); + break; + case EllipseNegativeMajorY: + deriv += -(X_F1 - X_c)*(Y_F1 - Y_c)/(sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2))*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))) + + (X_F1 - X_c)*(Y_F1 - Y_c)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2))/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L); + break; + case EllipsePositiveMinorX: + deriv += b*(X_F1 - X_c)*(Y_F1 - Y_c)/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2), 3.0L/2.0L) - 1; + break; + case EllipsePositiveMinorY: + deriv += -b*pow(X_F1 - X_c, 2)/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2), 3.0L/2.0L) + b/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)); + break; + case EllipseNegativeMinorX: + deriv += -b*(X_F1 - X_c)*(Y_F1 - Y_c)/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2), 3.0L/2.0L) - 1; + break; + case EllipseNegativeMinorY: + deriv += b*pow(X_F1 - X_c, 2)/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2), 3.0L/2.0L) - b/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)); + break; + case EllipseFocus2X: + deriv += -2; + break; + case EllipseFocus2Y: + deriv+=0; + break; + default: + deriv+=0; + } + if (param == cy()) + switch(AlignmentType) + { + case EllipsePositiveMajorX: + deriv += (X_F1 - X_c)*(Y_F1 - Y_c)/(sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2))*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))) - + (X_F1 - X_c)*(Y_F1 - Y_c)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2))/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L); + break; + case EllipsePositiveMajorY: + deriv += pow(Y_F1 - Y_c, 2)/(sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2))*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))) - + pow(Y_F1 - Y_c, 2)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2))/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L) - 1 + + sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))/sqrt(pow(X_F1 + - X_c, 2) + pow(Y_F1 - Y_c, 2)); + break; + case EllipseNegativeMajorX: + deriv += -(X_F1 - X_c)*(Y_F1 - Y_c)/(sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2))*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))) + + (X_F1 - X_c)*(Y_F1 - Y_c)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2))/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L); + break; + case EllipseNegativeMajorY: + deriv += -pow(Y_F1 - Y_c, 2)/(sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2))*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))) + + pow(Y_F1 - Y_c, 2)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2))/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L) - 1 - + sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))/sqrt(pow(X_F1 + - X_c, 2) + pow(Y_F1 - Y_c, 2)); + break; + case EllipsePositiveMinorX: + deriv += b*pow(Y_F1 - Y_c, 2)/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2), 3.0L/2.0L) - b/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)); + break; + case EllipsePositiveMinorY: + deriv += -b*(X_F1 - X_c)*(Y_F1 - Y_c)/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2), 3.0L/2.0L) - 1; + break; + case EllipseNegativeMinorX: + deriv += -b*pow(Y_F1 - Y_c, 2)/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2), 3.0L/2.0L) + b/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)); + break; + case EllipseNegativeMinorY: + deriv += b*(X_F1 - X_c)*(Y_F1 - Y_c)/pow(pow(X_F1 - X_c, 2) + pow(Y_F1 + - Y_c, 2), 3.0L/2.0L) - 1; + break; + case EllipseFocus2X: + deriv += 0; + break; + case EllipseFocus2Y: + deriv += -2; + break; + default: + deriv+=0; + } + if (param == rmin()) + switch(AlignmentType) + { + case EllipsePositiveMajorX: + deriv += -b*(X_F1 - X_c)/(sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2))*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))); + break; + case EllipsePositiveMajorY: + deriv += -b*(Y_F1 - Y_c)/(sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2))*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))); + break; + case EllipseNegativeMajorX: + deriv += b*(X_F1 - X_c)/(sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2))*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))); + break; + case EllipseNegativeMajorY: + deriv += b*(Y_F1 - Y_c)/(sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2))*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2))); + break; + case EllipsePositiveMinorX: + deriv += (Y_F1 - Y_c)/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)); + break; + case EllipsePositiveMinorY: + deriv += -(X_F1 - X_c)/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)); + break; + case EllipseNegativeMinorX: + deriv += -(Y_F1 - Y_c)/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)); + break; + case EllipseNegativeMinorY: + deriv += (X_F1 - X_c)/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)); + break; + case EllipseFocus2X: + deriv += 0; + break; + case EllipseFocus2Y: + deriv += 0; + break; + default: + deriv+=0; + } + } + return scale * deriv; +} + +// ConstraintEqualMajorAxesEllipse + ConstraintEqualMajorAxesEllipse:: ConstraintEqualMajorAxesEllipse(Ellipse &e1, Ellipse &e2) +{ + pvec.push_back(e1.center.x); + pvec.push_back(e1.center.y); + pvec.push_back(e1.focus1.x); + pvec.push_back(e1.focus1.y); + pvec.push_back(e1.radmin); + pvec.push_back(e2.center.x); + pvec.push_back(e2.center.y); + pvec.push_back(e2.focus1.x); + pvec.push_back(e2.focus1.y); + pvec.push_back(e2.radmin); + origpvec = pvec; + rescale(); +} + +ConstraintType ConstraintEqualMajorAxesEllipse::getTypeId() +{ + return EqualMajorAxesEllipse; +} + +void ConstraintEqualMajorAxesEllipse::rescale(double coef) +{ + scale = coef * 1; +} + +double ConstraintEqualMajorAxesEllipse::error() +{ + double E1X_c = *e1cx(); + double E1Y_c = *e1cy(); + double E1X_F1 = *e1f1x(); + double E1Y_F1 = *e1f1y(); + double E1b = *e1rmin(); + double E2X_c = *e2cx(); + double E2Y_c = *e2cy(); + double E2X_F1 = *e2f1x(); + double E2Y_F1 = *e2f1y(); + double E2b = *e2rmin(); + + double err=sqrt(pow(E1X_F1, 2) - 2*E1X_F1*E1X_c + pow(E1X_c, 2) + + pow(E1Y_F1, 2) - 2*E1Y_F1*E1Y_c + pow(E1Y_c, 2) + pow(E1b, 2)) - + sqrt(pow(E2X_F1, 2) - 2*E2X_F1*E2X_c + pow(E2X_c, 2) + pow(E2Y_F1, 2) - + 2*E2Y_F1*E2Y_c + pow(E2Y_c, 2) + pow(E2b, 2)); + return scale * err; +} + +double ConstraintEqualMajorAxesEllipse::grad(double *param) +{ + double deriv=0.; + if (param == e1f1x() || param == e1f1y() || + param == e1cx() || param == e1cy() || + param == e1rmin() || + param == e2f1x() || param == e2f1y() || + param == e2cx() || param == e2cy() || + param == e2rmin()) { + + double E1X_c = *e1cx(); + double E1Y_c = *e1cy(); + double E1X_F1 = *e1f1x(); + double E1Y_F1 = *e1f1y(); + double E1b = *e1rmin(); + double E2X_c = *e2cx(); + double E2Y_c = *e2cy(); + double E2X_F1 = *e2f1x(); + double E2Y_F1 = *e2f1y(); + double E2b = *e2rmin(); + + if (param == e1cx()) + deriv += -(E1X_F1 - E1X_c)/sqrt(pow(E1X_F1, 2) - 2*E1X_F1*E1X_c + + pow(E1X_c, 2) + pow(E1Y_F1, 2) - 2*E1Y_F1*E1Y_c + pow(E1Y_c, 2) + + pow(E1b, 2)); + if (param == e2cx()) + deriv += (E2X_F1 - E2X_c)/sqrt(pow(E2X_F1, 2) - 2*E2X_F1*E2X_c + + pow(E2X_c, 2) + pow(E2Y_F1, 2) - 2*E2Y_F1*E2Y_c + pow(E2Y_c, 2) + + pow(E2b, 2)); + if (param == e1cy()) + deriv += -(E1Y_F1 - E1Y_c)/sqrt(pow(E1X_F1, 2) - 2*E1X_F1*E1X_c + + pow(E1X_c, 2) + pow(E1Y_F1, 2) - 2*E1Y_F1*E1Y_c + pow(E1Y_c, 2) + + pow(E1b, 2)); + if (param == e2cy()) + deriv +=(E2Y_F1 - E2Y_c)/sqrt(pow(E2X_F1, 2) - 2*E2X_F1*E2X_c + + pow(E2X_c, 2) + pow(E2Y_F1, 2) - 2*E2Y_F1*E2Y_c + pow(E2Y_c, 2) + + pow(E2b, 2)); + if (param == e1f1x()) + deriv += (E1X_F1 - E1X_c)/sqrt(pow(E1X_F1, 2) - 2*E1X_F1*E1X_c + + pow(E1X_c, 2) + pow(E1Y_F1, 2) - 2*E1Y_F1*E1Y_c + pow(E1Y_c, 2) + + pow(E1b, 2)); + if (param == e2f1x()) + deriv +=-(E2X_F1 - E2X_c)/sqrt(pow(E2X_F1, 2) - 2*E2X_F1*E2X_c + + pow(E2X_c, 2) + pow(E2Y_F1, 2) - 2*E2Y_F1*E2Y_c + pow(E2Y_c, 2) + + pow(E2b, 2)); + if (param == e1f1y()) + deriv += (E1Y_F1 - E1Y_c)/sqrt(pow(E1X_F1, 2) - 2*E1X_F1*E1X_c + + pow(E1X_c, 2) + pow(E1Y_F1, 2) - 2*E1Y_F1*E1Y_c + pow(E1Y_c, 2) + + pow(E1b, 2)); + if (param == e2f1y()) + deriv +=-(E2Y_F1 - E2Y_c)/sqrt(pow(E2X_F1, 2) - 2*E2X_F1*E2X_c + + pow(E2X_c, 2) + pow(E2Y_F1, 2) - 2*E2Y_F1*E2Y_c + pow(E2Y_c, 2) + + pow(E2b, 2)); + if (param == e1rmin()) + deriv += E1b/sqrt(pow(E1X_F1, 2) - 2*E1X_F1*E1X_c + pow(E1X_c, 2) + + pow(E1Y_F1, 2) - 2*E1Y_F1*E1Y_c + pow(E1Y_c, 2) + pow(E1b, 2)); + if (param == e2rmin()) + deriv += -E2b/sqrt(pow(E2X_F1, 2) - 2*E2X_F1*E2X_c + pow(E2X_c, 2) + + pow(E2Y_F1, 2) - 2*E2Y_F1*E2Y_c + pow(E2Y_c, 2) + pow(E2b, 2)); + } + return scale * deriv; +} + +// EllipticalArcRangeToEndPoints +ConstraintEllipticalArcRangeToEndPoints::ConstraintEllipticalArcRangeToEndPoints(Point &p, ArcOfEllipse &a, double *angle_t) +{ + pvec.push_back(p.x); + pvec.push_back(p.y); + pvec.push_back(angle_t); + pvec.push_back(a.center.x); + pvec.push_back(a.center.y); + pvec.push_back(a.focus1.x); + pvec.push_back(a.focus1.y); + pvec.push_back(a.radmin); + origpvec = pvec; + rescale(); +} + +ConstraintType ConstraintEllipticalArcRangeToEndPoints::getTypeId() +{ + return EllipticalArcRangeToEndPoints; +} + +void ConstraintEllipticalArcRangeToEndPoints::rescale(double coef) +{ + scale = coef * 1; +} + +double ConstraintEllipticalArcRangeToEndPoints::error() +{ + double X_0 = *p1x(); + double Y_0 = *p1y(); + double X_c = *cx(); + double Y_c = *cy(); + double X_F1 = *f1x(); + double Y_F1 = *f1y(); + double b = *rmin(); + double alpha_t = *angle(); + + double err=atan((((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - Y_c)*(Y_F1 - + Y_c))*sin(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2)) - (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*cos(alpha_t)/b)/(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - Y_c)*(Y_F1 - + Y_c))*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2)) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*sin(alpha_t)/b)); + return scale * err; +} + +double ConstraintEllipticalArcRangeToEndPoints::grad(double *param) +{ + double deriv=0.; + if (param == p1x() || param == p1y() || + param == f1x() || param == f1y() || + param == cx() || param == cy() || + param == rmin() || param == angle()) { + + double X_0 = *p1x(); + double Y_0 = *p1y(); + double X_c = *cx(); + double Y_c = *cy(); + double X_F1 = *f1x(); + double Y_F1 = *f1y(); + double b = *rmin(); + double alpha_t = *angle(); + + if (param == p1x()) + deriv += -(-((X_F1 - X_c)*sin(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, + 2) + pow(Y_F1 - Y_c, 2)) + (Y_F1 - Y_c)*cos(alpha_t)/b)/(((X_0 - + X_c)*(X_F1 - X_c) + (Y_0 - Y_c)*(Y_F1 - Y_c))*cos(alpha_t)/sqrt(pow(b, + 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)) + (-(X_0 - X_c)*(Y_F1 - + Y_c) + (X_F1 - X_c)*(Y_0 - Y_c))*sin(alpha_t)/b) + ((X_F1 - + X_c)*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2)) - (Y_F1 - Y_c)*sin(alpha_t)/b)*(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - + Y_c)*(Y_F1 - Y_c))*sin(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2)) - (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*cos(alpha_t)/b)/pow(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - Y_c)*(Y_F1 + - Y_c))*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - + Y_c, 2)) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*sin(alpha_t)/b, 2))/(pow(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - + Y_c)*(Y_F1 - Y_c))*sin(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2)) - (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*cos(alpha_t)/b, 2)/pow(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - + Y_c)*(Y_F1 - Y_c))*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2)) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*sin(alpha_t)/b, 2) + 1); + if (param == p1y()) + deriv += -(-((Y_F1 - Y_c)*sin(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, + 2) + pow(Y_F1 - Y_c, 2)) - (X_F1 - X_c)*cos(alpha_t)/b)/(((X_0 - + X_c)*(X_F1 - X_c) + (Y_0 - Y_c)*(Y_F1 - Y_c))*cos(alpha_t)/sqrt(pow(b, + 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)) + (-(X_0 - X_c)*(Y_F1 - + Y_c) + (X_F1 - X_c)*(Y_0 - Y_c))*sin(alpha_t)/b) + ((Y_F1 - + Y_c)*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2)) + (X_F1 - X_c)*sin(alpha_t)/b)*(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - + Y_c)*(Y_F1 - Y_c))*sin(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2)) - (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*cos(alpha_t)/b)/pow(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - Y_c)*(Y_F1 + - Y_c))*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - + Y_c, 2)) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*sin(alpha_t)/b, 2))/(pow(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - + Y_c)*(Y_F1 - Y_c))*sin(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2)) - (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*cos(alpha_t)/b, 2)/pow(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - + Y_c)*(Y_F1 - Y_c))*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2)) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*sin(alpha_t)/b, 2) + 1); + if (param == f1x()) + deriv += -((((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - Y_c)*(Y_F1 - + Y_c))*sin(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2)) - (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*cos(alpha_t)/b)*((X_0 - X_c)*cos(alpha_t)/sqrt(pow(b, 2) + + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)) - (X_F1 - X_c)*((X_0 - + X_c)*(X_F1 - X_c) + (Y_0 - Y_c)*(Y_F1 - Y_c))*cos(alpha_t)/pow(pow(b, 2) + + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L) + (Y_0 - + Y_c)*sin(alpha_t)/b)/pow(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - Y_c)*(Y_F1 - + Y_c))*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2)) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*sin(alpha_t)/b, 2) - ((X_0 - X_c)*sin(alpha_t)/sqrt(pow(b, 2) + + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)) - (X_F1 - X_c)*((X_0 - + X_c)*(X_F1 - X_c) + (Y_0 - Y_c)*(Y_F1 - Y_c))*sin(alpha_t)/pow(pow(b, 2) + + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L) - (Y_0 - + Y_c)*cos(alpha_t)/b)/(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - Y_c)*(Y_F1 - + Y_c))*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2)) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*sin(alpha_t)/b))/(pow(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - + Y_c)*(Y_F1 - Y_c))*sin(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2)) - (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*cos(alpha_t)/b, 2)/pow(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - + Y_c)*(Y_F1 - Y_c))*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2)) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*sin(alpha_t)/b, 2) + 1); + if (param == f1y()) + deriv +=-((((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - Y_c)*(Y_F1 - + Y_c))*sin(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2)) - (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*cos(alpha_t)/b)*((Y_0 - Y_c)*cos(alpha_t)/sqrt(pow(b, 2) + + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)) - (Y_F1 - Y_c)*((X_0 - + X_c)*(X_F1 - X_c) + (Y_0 - Y_c)*(Y_F1 - Y_c))*cos(alpha_t)/pow(pow(b, 2) + + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L) - (X_0 - + X_c)*sin(alpha_t)/b)/pow(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - Y_c)*(Y_F1 - + Y_c))*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2)) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*sin(alpha_t)/b, 2) - ((Y_0 - Y_c)*sin(alpha_t)/sqrt(pow(b, 2) + + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)) - (Y_F1 - Y_c)*((X_0 - + X_c)*(X_F1 - X_c) + (Y_0 - Y_c)*(Y_F1 - Y_c))*sin(alpha_t)/pow(pow(b, 2) + + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L) + (X_0 - + X_c)*cos(alpha_t)/b)/(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - Y_c)*(Y_F1 - + Y_c))*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2)) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*sin(alpha_t)/b))/(pow(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - + Y_c)*(Y_F1 - Y_c))*sin(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2)) - (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*cos(alpha_t)/b, 2)/pow(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - + Y_c)*(Y_F1 - Y_c))*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2)) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*sin(alpha_t)/b, 2) + 1); + if (param == cx()) + deriv += ((((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - Y_c)*(Y_F1 - + Y_c))*sin(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2)) - (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*cos(alpha_t)/b)*(-(X_F1 - X_c)*((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - + Y_c)*(Y_F1 - Y_c))*cos(alpha_t)/pow(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2), 3.0L/2.0L) + (X_0 + X_F1 - + 2*X_c)*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - + Y_c, 2)) + (Y_0 - Y_F1)*sin(alpha_t)/b)/pow(((X_0 - X_c)*(X_F1 - X_c) + + (Y_0 - Y_c)*(Y_F1 - Y_c))*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, + 2) + pow(Y_F1 - Y_c, 2)) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - + X_c)*(Y_0 - Y_c))*sin(alpha_t)/b, 2) - (-(X_F1 - X_c)*((X_0 - X_c)*(X_F1 + - X_c) + (Y_0 - Y_c)*(Y_F1 - Y_c))*sin(alpha_t)/pow(pow(b, 2) + pow(X_F1 + - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L) + (X_0 + X_F1 - + 2*X_c)*sin(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - + Y_c, 2)) - (Y_0 - Y_F1)*cos(alpha_t)/b)/(((X_0 - X_c)*(X_F1 - X_c) + + (Y_0 - Y_c)*(Y_F1 - Y_c))*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, + 2) + pow(Y_F1 - Y_c, 2)) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - + X_c)*(Y_0 - Y_c))*sin(alpha_t)/b))/(pow(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 + - Y_c)*(Y_F1 - Y_c))*sin(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2)) - (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*cos(alpha_t)/b, 2)/pow(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - + Y_c)*(Y_F1 - Y_c))*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2)) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*sin(alpha_t)/b, 2) + 1); + if (param == cy()) + deriv +=((((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - Y_c)*(Y_F1 - + Y_c))*sin(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2)) - (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*cos(alpha_t)/b)*(-(Y_F1 - Y_c)*((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - + Y_c)*(Y_F1 - Y_c))*cos(alpha_t)/pow(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2), 3.0L/2.0L) + (Y_0 + Y_F1 - + 2*Y_c)*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - + Y_c, 2)) - (X_0 - X_F1)*sin(alpha_t)/b)/pow(((X_0 - X_c)*(X_F1 - X_c) + + (Y_0 - Y_c)*(Y_F1 - Y_c))*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, + 2) + pow(Y_F1 - Y_c, 2)) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - + X_c)*(Y_0 - Y_c))*sin(alpha_t)/b, 2) - (-(Y_F1 - Y_c)*((X_0 - X_c)*(X_F1 + - X_c) + (Y_0 - Y_c)*(Y_F1 - Y_c))*sin(alpha_t)/pow(pow(b, 2) + pow(X_F1 + - X_c, 2) + pow(Y_F1 - Y_c, 2), 3.0L/2.0L) + (Y_0 + Y_F1 - + 2*Y_c)*sin(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - + Y_c, 2)) + (X_0 - X_F1)*cos(alpha_t)/b)/(((X_0 - X_c)*(X_F1 - X_c) + + (Y_0 - Y_c)*(Y_F1 - Y_c))*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, + 2) + pow(Y_F1 - Y_c, 2)) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - + X_c)*(Y_0 - Y_c))*sin(alpha_t)/b))/(pow(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 + - Y_c)*(Y_F1 - Y_c))*sin(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2)) - (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*cos(alpha_t)/b, 2)/pow(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - + Y_c)*(Y_F1 - Y_c))*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2)) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*sin(alpha_t)/b, 2) + 1); + if (param == rmin()) + deriv += ((((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - Y_c)*(Y_F1 - + Y_c))*sin(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2)) - (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*cos(alpha_t)/b)*(b*((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - Y_c)*(Y_F1 - + Y_c))*cos(alpha_t)/pow(pow(b, 2) + pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, + 2), 3.0L/2.0L) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*sin(alpha_t)/pow(b, 2))/pow(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - + Y_c)*(Y_F1 - Y_c))*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2)) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*sin(alpha_t)/b, 2) - (b*((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - + Y_c)*(Y_F1 - Y_c))*sin(alpha_t)/pow(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2), 3.0L/2.0L) - (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - + X_c)*(Y_0 - Y_c))*cos(alpha_t)/pow(b, 2))/(((X_0 - X_c)*(X_F1 - X_c) + + (Y_0 - Y_c)*(Y_F1 - Y_c))*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, + 2) + pow(Y_F1 - Y_c, 2)) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - + X_c)*(Y_0 - Y_c))*sin(alpha_t)/b))/(pow(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 + - Y_c)*(Y_F1 - Y_c))*sin(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2)) - (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*cos(alpha_t)/b, 2)/pow(((X_0 - X_c)*(X_F1 - X_c) + (Y_0 - + Y_c)*(Y_F1 - Y_c))*cos(alpha_t)/sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2)) + (-(X_0 - X_c)*(Y_F1 - Y_c) + (X_F1 - X_c)*(Y_0 - + Y_c))*sin(alpha_t)/b, 2) + 1); + if (param == angle()) + deriv += 1; + } + return scale * deriv; +} + +double ConstraintEllipticalArcRangeToEndPoints::maxStep(MAP_pD_D &dir, double lim) +{ + // step(angle()) <= pi/18 = 10° + MAP_pD_D::iterator it = dir.find(angle()); + if (it != dir.end()) { + double step = std::abs(it->second); + if (step > M_PI/18.) + lim = std::min(lim, (M_PI/18.) / step); + } + return lim; +} + } //namespace GCS diff --git a/src/Mod/Sketcher/App/freegcs/Constraints.h b/src/Mod/Sketcher/App/freegcs/Constraints.h index a4bfdd410b..e08e47bff0 100644 --- a/src/Mod/Sketcher/App/freegcs/Constraints.h +++ b/src/Mod/Sketcher/App/freegcs/Constraints.h @@ -46,7 +46,26 @@ namespace GCS Perpendicular = 9, L2LAngle = 10, MidpointOnLine = 11, - TangentCircumf = 12 + TangentCircumf = 12, + P2OnEllipse = 13, + TangentEllipseLine = 14, + Point2EllipseDistance = 15, + InternalAlignmentPoint2Ellipse = 16, + EqualMajorAxesEllipse = 17, + EllipticalArcRangeToEndPoints = 18 + }; + + enum InternalAlignmentType { + EllipsePositiveMajorX = 0, + EllipsePositiveMajorY = 1, + EllipseNegativeMajorX = 2, + EllipseNegativeMajorY = 3, + EllipsePositiveMinorX = 4, + EllipsePositiveMinorY = 5, + EllipseNegativeMinorX = 6, + EllipseNegativeMinorY = 7, + EllipseFocus2X = 8, + EllipseFocus2Y = 9 }; class Constraint @@ -159,6 +178,7 @@ namespace GCS virtual double error(); virtual double grad(double *); virtual double maxStep(MAP_pD_D &dir, double lim=1.); + double abs(double darea); }; // PointOnLine @@ -304,6 +324,110 @@ namespace GCS virtual double error(); virtual double grad(double *); }; + // PointOnEllipse + class ConstraintPointOnEllipse : public Constraint + { + private: + inline double* p1x() { return pvec[0]; } + inline double* p1y() { return pvec[1]; } + inline double* cx() { return pvec[2]; } + inline double* cy() { return pvec[3]; } + inline double* f1x() { return pvec[4]; } + inline double* f1y() { return pvec[5]; } + inline double* rmin() { return pvec[6]; } + public: + ConstraintPointOnEllipse(Point &p, Ellipse &e); + ConstraintPointOnEllipse(Point &p, ArcOfEllipse &a); + virtual ConstraintType getTypeId(); + virtual void rescale(double coef=1.); + virtual double error(); + virtual double grad(double *); + }; + + class ConstraintEllipseTangentLine : public Constraint + { + private: + inline double* p1x() { return pvec[0]; } + inline double* p1y() { return pvec[1]; } + inline double* p2x() { return pvec[2]; } + inline double* p2y() { return pvec[3]; } + inline double* cx() { return pvec[4]; } + inline double* cy() { return pvec[5]; } + inline double* f1x() { return pvec[6]; } + inline double* f1y() { return pvec[7]; } + inline double* rmin() { return pvec[8]; } + public: + ConstraintEllipseTangentLine(Line &l, Ellipse &e); + ConstraintEllipseTangentLine(Line &l, ArcOfEllipse &a); + virtual ConstraintType getTypeId(); + virtual void rescale(double coef=1.); + virtual double error(); + virtual double grad(double *); + }; + + class ConstraintInternalAlignmentPoint2Ellipse : public Constraint + { + private: + inline double* p1x() { return pvec[0]; } + inline double* p1y() { return pvec[1]; } + inline double* cx() { return pvec[2]; } + inline double* cy() { return pvec[3]; } + inline double* f1x() { return pvec[4]; } + inline double* f1y() { return pvec[5]; } + inline double* rmin() { return pvec[6]; } + public: + ConstraintInternalAlignmentPoint2Ellipse(Ellipse &e, Point &p1, InternalAlignmentType alignmentType); + ConstraintInternalAlignmentPoint2Ellipse(ArcOfEllipse &e, Point &p1, InternalAlignmentType alignmentType); + virtual ConstraintType getTypeId(); + virtual void rescale(double coef=1.); + virtual double error(); + virtual double grad(double *); + private: + InternalAlignmentType AlignmentType; + }; + + class ConstraintEqualMajorAxesEllipse : public Constraint + { + private: + inline double* e1cx() { return pvec[0]; } + inline double* e1cy() { return pvec[1]; } + inline double* e1f1x() { return pvec[2]; } + inline double* e1f1y() { return pvec[3]; } + inline double* e1rmin() { return pvec[4]; } + inline double* e2cx() { return pvec[5]; } + inline double* e2cy() { return pvec[6]; } + inline double* e2f1x() { return pvec[7]; } + inline double* e2f1y() { return pvec[8]; } + inline double* e2rmin() { return pvec[9]; } + public: + ConstraintEqualMajorAxesEllipse(Ellipse &e1, Ellipse &e2); + virtual ConstraintType getTypeId(); + virtual void rescale(double coef=1.); + virtual double error(); + virtual double grad(double *); + }; + + // EllipticalArcRangeToEndPoints + class ConstraintEllipticalArcRangeToEndPoints : public Constraint + { + private: + inline double* p1x() { return pvec[0]; } + inline double* p1y() { return pvec[1]; } + inline double* angle() { return pvec[2]; } + inline double* cx() { return pvec[3]; } + inline double* cy() { return pvec[4]; } + inline double* f1x() { return pvec[5]; } + inline double* f1y() { return pvec[6]; } + inline double* rmin() { return pvec[7]; } + public: + ConstraintEllipticalArcRangeToEndPoints(Point &p, ArcOfEllipse &a, double *angle_t); + virtual ConstraintType getTypeId(); + virtual void rescale(double coef=1.); + virtual double error(); + virtual double grad(double *); + virtual double maxStep(MAP_pD_D &dir, double lim=1.); + }; + } //namespace GCS diff --git a/src/Mod/Sketcher/App/freegcs/GCS.cpp b/src/Mod/Sketcher/App/freegcs/GCS.cpp index 7c6625a7ec..477b94bf0d 100644 --- a/src/Mod/Sketcher/App/freegcs/GCS.cpp +++ b/src/Mod/Sketcher/App/freegcs/GCS.cpp @@ -27,6 +27,16 @@ #include "qp_eq.h" #include +#define _GCS_DEBUG 1 + +#ifdef _GCS_DEBUG +#include +#include +#include +#include +#include +#endif // _GCS_DEBUG + #include #include @@ -481,6 +491,42 @@ int System::addConstraintPointOnCircle(Point &p, Circle &c, int tagId) return addConstraintP2PDistance(p, c.center, c.rad, tagId); } +int System::addConstraintPointOnEllipse(Point &p, Ellipse &e, int tagId) +{ + // TODO: Implement real constraint => Done + + Constraint *constr = new ConstraintPointOnEllipse(p, e); + constr->setTag(tagId); + return addConstraint(constr); +} + +int System::addConstraintEllipticalArcRangeToEndPoints(Point &p, ArcOfEllipse &a, double *angle, int tagId) +{ + Constraint *constr = new ConstraintEllipticalArcRangeToEndPoints(p,a,angle); + constr->setTag(tagId); + return addConstraint(constr); +} + + +int System::addConstraintArcOfEllipseRules(ArcOfEllipse &a, int tagId) +{ + /* addConstraintP2PAngle(a.center, a.start, a.startAngle, tagId); + return addConstraintP2PAngle(a.center, a.end, a.endAngle, tagId);*/ + + addConstraintEllipticalArcRangeToEndPoints(a.start,a,a.startAngle, tagId); + addConstraintEllipticalArcRangeToEndPoints(a.end,a,a.endAngle, tagId); + + addConstraintPointOnArcOfEllipse(a.start, a, tagId); + return addConstraintPointOnArcOfEllipse(a.end, a, tagId); +} + +int System::addConstraintPointOnArcOfEllipse(Point &p, ArcOfEllipse &a, int tagId) +{ + Constraint *constr = new ConstraintPointOnEllipse(p, a); + constr->setTag(tagId); + return addConstraint(constr); +} + int System::addConstraintPointOnArc(Point &p, Arc &a, int tagId) { return addConstraintP2PDistance(p, a.center, a.rad, tagId); @@ -552,6 +598,39 @@ int System::addConstraintTangent(Line &l, Circle &c, int tagId) return addConstraintP2LDistance(c.center, l, c.rad, tagId); } +int System::addConstraintTangent(Line &l, Ellipse &e, int tagId) +{ + // TODO: real ellipse implementation => Done + Constraint *constr = new ConstraintEllipseTangentLine(l, e); + constr->setTag(tagId); + return addConstraint(constr); +} + +int System::addConstraintTangent(Line &l, ArcOfEllipse &a, int tagId) +{ + // TODO: real ellipse implementation => Done + Constraint *constr = new ConstraintEllipseTangentLine(l, a); + constr->setTag(tagId); + return addConstraint(constr); +} + +int System::addConstraintTangent(Ellipse &e, Circle &c, int tagId) +{ + // TODO: elipse + /*double dx = *(c.center.x) - *(e.center.x); + double dy = *(c.center.y) - *(e.center.y); + double d = sqrt(dx*dx + dy*dy);*/ + + /*Constraint *constr = new ConstraintPoint2EllipseDistance(c.center,e,c.rad); + constr->setTag(tagId); + return addConstraint(constr); */ + + + //return addConstraintTangentCircumf(e.center, c.center, e.radmaj, c.rad, + // (d < *e.radmaj || d < *c.rad), tagId); + return 0; +} + int System::addConstraintTangent(Line &l, Arc &a, int tagId) { return addConstraintP2LDistance(a.center, l, a.rad, tagId); @@ -584,6 +663,19 @@ int System::addConstraintTangent(Circle &c, Arc &a, int tagId) (d < *c.rad || d < *a.rad), tagId); } +int System::addConstraintTangent(Ellipse &e, Arc &a, int tagId) +{ + // TODO: elipse + /*double dx = *(a.center.x) - *(e.center.x); + double dy = *(a.center.y) - *(e.center.y); + double d = sqrt(dx*dx + dy*dy);Constraint *constr = new ConstraintEllipseTangentLine(l, e); + constr->setTag(tagId); + return addConstraint(constr); + return addConstraintTangentCircumf(e.center, a.center, e.radmaj, a.rad, + (d < *e.radmaj || d < *a.rad), tagId);*/ + return 0; +} + int System::addConstraintTangentLine2Arc(Point &p1, Point &p2, Arc &a, int tagId) { addConstraintP2PCoincident(p2, a.start, tagId); @@ -598,6 +690,18 @@ int System::addConstraintTangentArc2Line(Arc &a, Point &p1, Point &p2, int tagId return addConstraintP2PAngle(p1, p2, a.endAngle, incrAngle, tagId); } +int System::addConstraintTangentLine2ArcOfEllipse(Point &p1, Point &p2, Line &l, ArcOfEllipse &a, int tagId) +{ + addConstraintP2PCoincident(p2, a.start, tagId); + return addConstraintTangent(l, a, tagId); +} + +int System::addConstraintTangentArcOfEllipse2Line(ArcOfEllipse &a, Line &l, Point &p1, Point &p2, int tagId) +{ + addConstraintP2PCoincident(p1, a.end, tagId); + return addConstraintTangent(l, a, tagId); +} + int System::addConstraintTangentCircle2Arc(Circle &c, Arc &a, int tagId) { addConstraintPointOnCircle(a.start, c, tagId); @@ -609,6 +713,19 @@ int System::addConstraintTangentCircle2Arc(Circle &c, Arc &a, int tagId) return addConstraintP2PAngle(c.center, a.start, a.startAngle, M_PI, tagId); } +int System::addConstraintTangentEllipse2Arc(Ellipse &e, Arc &a, int tagId) +{ + // TODO: Ellipse + /*addConstraintPointOnEllipse(a.start, e, tagId); + double dx = *(a.start.x) - *(e.center.x); + double dy = *(a.start.y) - *(e.center.y); + if (dx * cos(*(a.startAngle)) + dy * sin(*(a.startAngle)) > 0) + return addConstraintP2PAngle(e.center, a.start, a.startAngle, 0, tagId); + else + return addConstraintP2PAngle(e.center, a.start, a.startAngle, M_PI, tagId);*/ + return 0; +} + int System::addConstraintTangentArc2Circle(Arc &a, Circle &c, int tagId) { addConstraintPointOnCircle(a.end, c, tagId); @@ -620,6 +737,19 @@ int System::addConstraintTangentArc2Circle(Arc &a, Circle &c, int tagId) return addConstraintP2PAngle(c.center, a.end, a.endAngle, M_PI, tagId); } +int System::addConstraintTangentArc2Ellipse(Arc &a, Ellipse &e, int tagId) +{ + // TODO: Ellipse + /*addConstraintPointOnEllipse(a.end, e, tagId); + double dx = *(a.end.x) - *(e.center.x); + double dy = *(a.end.y) - *(e.center.y); + if (dx * cos(*(a.endAngle)) + dy * sin(*(a.endAngle)) > 0) + return addConstraintP2PAngle(e.center, a.end, a.endAngle, 0, tagId); + else + return addConstraintP2PAngle(e.center, a.end, a.endAngle, M_PI, tagId);*/ + return 0; +} + int System::addConstraintTangentArc2Arc(Arc &a1, bool reverse1, Arc &a2, bool reverse2, int tagId) { @@ -656,6 +786,17 @@ int System::addConstraintEqualRadius(Circle &c1, Circle &c2, int tagId) return addConstraintEqual(c1.rad, c2.rad, tagId); } +int System::addConstraintEqualRadii(Ellipse &e1, Ellipse &e2, int tagId) +{ + // TODO: Ellipse + //addConstraintEqual(e1.radmaj, e2.radmaj, tagId); + addConstraintEqual(e1.radmin, e2.radmin, tagId); + + Constraint *constr = new ConstraintEqualMajorAxesEllipse(e1,e2); + constr->setTag(tagId); + return addConstraint(constr); +} + int System::addConstraintEqualRadius(Circle &c1, Arc &a2, int tagId) { return addConstraintEqual(c1.rad, a2.rad, tagId); @@ -678,6 +819,74 @@ int System::addConstraintP2PSymmetric(Point &p1, Point &p2, Point &p, int tagId) return addConstraintPointOnLine(p, p1, p2, tagId); } +int System::addConstraintInternalAlignmentPoint2Ellipse(Ellipse &e, Point &p1, InternalAlignmentType alignmentType, int tagId) +{ + Constraint *constr = new ConstraintInternalAlignmentPoint2Ellipse(e, p1, alignmentType); + constr->setTag(tagId); + return addConstraint(constr); +} + +int System::addConstraintInternalAlignmentEllipseMajorDiameter(Ellipse &e, Point &p1, Point &p2, int tagId) +{ + addConstraintInternalAlignmentPoint2Ellipse(e,p1,EllipsePositiveMajorX,tagId); + addConstraintInternalAlignmentPoint2Ellipse(e,p1,EllipsePositiveMajorY,tagId); + addConstraintInternalAlignmentPoint2Ellipse(e,p2,EllipseNegativeMajorX,tagId); + return addConstraintInternalAlignmentPoint2Ellipse(e,p2,EllipseNegativeMajorY,tagId); +} + +int System::addConstraintInternalAlignmentEllipseMinorDiameter(Ellipse &e, Point &p1, Point &p2, int tagId) +{ + addConstraintInternalAlignmentPoint2Ellipse(e,p1,EllipsePositiveMinorX,tagId); + addConstraintInternalAlignmentPoint2Ellipse(e,p1,EllipsePositiveMinorY,tagId); + addConstraintInternalAlignmentPoint2Ellipse(e,p2,EllipseNegativeMinorX,tagId); + return addConstraintInternalAlignmentPoint2Ellipse(e,p2,EllipseNegativeMinorY,tagId); +} + +int System::addConstraintInternalAlignmentEllipseFocus1(Ellipse &e, Point &p1, int tagId) +{ + return addConstraintP2PCoincident(e.focus1,p1); +} + +int System::addConstraintInternalAlignmentEllipseFocus2(Ellipse &e, Point &p1, int tagId) +{ + addConstraintInternalAlignmentPoint2Ellipse(e,p1,EllipseFocus2X,tagId); + return addConstraintInternalAlignmentPoint2Ellipse(e,p1,EllipseFocus2Y,tagId); +} + +int System::addConstraintInternalAlignmentPoint2Ellipse(ArcOfEllipse &a, Point &p1, InternalAlignmentType alignmentType, int tagId) +{ + Constraint *constr = new ConstraintInternalAlignmentPoint2Ellipse(a, p1, alignmentType); + constr->setTag(tagId); + return addConstraint(constr); +} + +int System::addConstraintInternalAlignmentEllipseMajorDiameter(ArcOfEllipse &a, Point &p1, Point &p2, int tagId) +{ + addConstraintInternalAlignmentPoint2Ellipse(a,p1,EllipsePositiveMajorX,tagId); + addConstraintInternalAlignmentPoint2Ellipse(a,p1,EllipsePositiveMajorY,tagId); + addConstraintInternalAlignmentPoint2Ellipse(a,p2,EllipseNegativeMajorX,tagId); + return addConstraintInternalAlignmentPoint2Ellipse(a,p2,EllipseNegativeMajorY,tagId); +} + +int System::addConstraintInternalAlignmentEllipseMinorDiameter(ArcOfEllipse &a, Point &p1, Point &p2, int tagId) +{ + addConstraintInternalAlignmentPoint2Ellipse(a,p1,EllipsePositiveMinorX,tagId); + addConstraintInternalAlignmentPoint2Ellipse(a,p1,EllipsePositiveMinorY,tagId); + addConstraintInternalAlignmentPoint2Ellipse(a,p2,EllipseNegativeMinorX,tagId); + return addConstraintInternalAlignmentPoint2Ellipse(a,p2,EllipseNegativeMinorY,tagId); +} + +int System::addConstraintInternalAlignmentEllipseFocus1(ArcOfEllipse &a, Point &p1, int tagId) +{ + return addConstraintP2PCoincident(a.focus1,p1); +} + +int System::addConstraintInternalAlignmentEllipseFocus2(ArcOfEllipse &a, Point &p1, int tagId) +{ + addConstraintInternalAlignmentPoint2Ellipse(a,p1,EllipseFocus2X,tagId); + return addConstraintInternalAlignmentPoint2Ellipse(a,p1,EllipseFocus2Y,tagId); +} + void System::rescaleConstraint(int id, double coeff) { if (id >= clist.size() || id < 0) @@ -1465,12 +1674,27 @@ int System::diagnose() J(count-1,j) = (*constr)->grad(plist[j]); } } - + + #ifdef _GCS_DEBUG + // Debug code starts + std::stringstream stream; + + stream << "["; + stream << J ; + stream << "]"; + + const std::string tmp = stream.str(); + + Base::Console().Warning(tmp.c_str()); + // Debug code ends + #endif + if (J.rows() > 0) { Eigen::FullPivHouseholderQR qrJT(J.topRows(count).transpose()); Eigen::MatrixXd Q = qrJT.matrixQ (); int paramsNum = qrJT.rows(); int constrNum = qrJT.cols(); + //qrJT.setThreshold(0); int rank = qrJT.rank(); Eigen::MatrixXd R; diff --git a/src/Mod/Sketcher/App/freegcs/GCS.h b/src/Mod/Sketcher/App/freegcs/GCS.h index f592b92ea0..3d99da2c9b 100644 --- a/src/Mod/Sketcher/App/freegcs/GCS.h +++ b/src/Mod/Sketcher/App/freegcs/GCS.h @@ -125,6 +125,10 @@ namespace GCS int addConstraintCoordinateY(Point &p, double *y, int tagId=0); int addConstraintArcRules(Arc &a, int tagId=0); int addConstraintPointOnCircle(Point &p, Circle &c, int tagId=0); + int addConstraintPointOnEllipse(Point &p, Ellipse &e, int tagId=0); + int addConstraintEllipticalArcRangeToEndPoints(Point &p, ArcOfEllipse &a, double *angle, int tagId=0); + int addConstraintArcOfEllipseRules(ArcOfEllipse &a, int tagId=0); + int addConstraintPointOnArcOfEllipse(Point &p, ArcOfEllipse &a, int tagId=0); int addConstraintPointOnArc(Point &p, Arc &a, int tagId=0); int addConstraintPerpendicularLine2Arc(Point &p1, Point &p2, Arc &a, int tagId=0); @@ -137,24 +141,47 @@ namespace GCS int addConstraintPerpendicularArc2Arc(Arc &a1, bool reverse1, Arc &a2, bool reverse2, int tagId=0); int addConstraintTangent(Line &l, Circle &c, int tagId=0); + int addConstraintTangent(Line &l, Ellipse &e, int tagId=0); + int addConstraintTangent(Line &l, ArcOfEllipse &a, int tagId=0); + int addConstraintTangent(Ellipse &e, Circle &c, int tagId=0); int addConstraintTangent(Line &l, Arc &a, int tagId=0); int addConstraintTangent(Circle &c1, Circle &c2, int tagId=0); int addConstraintTangent(Arc &a1, Arc &a2, int tagId=0); int addConstraintTangent(Circle &c, Arc &a, int tagId=0); + int addConstraintTangent(Ellipse &e, Arc &a, int tagId=0); + int addConstraintTangentLine2ArcOfEllipse(Point &p1, Point &p2, Line &l, ArcOfEllipse &a, int tagId=0); + int addConstraintTangentArcOfEllipse2Line(ArcOfEllipse &a, Line &l, Point &p1, Point &p2, int tagId=0); int addConstraintTangentLine2Arc(Point &p1, Point &p2, Arc &a, int tagId=0); int addConstraintTangentArc2Line(Arc &a, Point &p1, Point &p2, int tagId=0); int addConstraintTangentCircle2Arc(Circle &c, Arc &a, int tagId=0); + int addConstraintTangentEllipse2Arc(Ellipse &e, Arc &a, int tagId=0); int addConstraintTangentArc2Circle(Arc &a, Circle &c, int tagId=0); + int addConstraintTangentArc2Ellipse(Arc &a, Ellipse &e, int tagId=0); int addConstraintTangentArc2Arc(Arc &a1, bool reverse1, Arc &a2, bool reverse2, int tagId=0); int addConstraintCircleRadius(Circle &c, double *radius, int tagId=0); + int addConstraintEllipseAngleXU(Ellipse &e, double *angle, int tagId=0); int addConstraintArcRadius(Arc &a, double *radius, int tagId=0); int addConstraintEqualLength(Line &l1, Line &l2, double *length, int tagId=0); int addConstraintEqualRadius(Circle &c1, Circle &c2, int tagId=0); + int addConstraintEqualRadii(Ellipse &e1, Ellipse &e2, int tagId=0); int addConstraintEqualRadius(Circle &c1, Arc &a2, int tagId=0); int addConstraintEqualRadius(Arc &a1, Arc &a2, int tagId=0); int addConstraintP2PSymmetric(Point &p1, Point &p2, Line &l, int tagId=0); int addConstraintP2PSymmetric(Point &p1, Point &p2, Point &p, int tagId=0); + + // internal alignment constraints + int addConstraintInternalAlignmentPoint2Ellipse(Ellipse &e, Point &p1, InternalAlignmentType alignmentType, int tagId=0); + int addConstraintInternalAlignmentEllipseMajorDiameter(Ellipse &e, Point &p1, Point &p2, int tagId=0); + int addConstraintInternalAlignmentEllipseMinorDiameter(Ellipse &e, Point &p1, Point &p2, int tagId=0); + int addConstraintInternalAlignmentEllipseFocus1(Ellipse &e, Point &p1, int tagId=0); + int addConstraintInternalAlignmentEllipseFocus2(Ellipse &e, Point &p1, int tagId=0); + int addConstraintInternalAlignmentPoint2Ellipse(ArcOfEllipse &a, Point &p1, InternalAlignmentType alignmentType, int tagId=0); + int addConstraintInternalAlignmentEllipseMajorDiameter(ArcOfEllipse &a, Point &p1, Point &p2, int tagId=0); + int addConstraintInternalAlignmentEllipseMinorDiameter(ArcOfEllipse &a, Point &p1, Point &p2, int tagId=0); + int addConstraintInternalAlignmentEllipseFocus1(ArcOfEllipse &a, Point &p1, int tagId=0); + int addConstraintInternalAlignmentEllipseFocus2(ArcOfEllipse &a, Point &p1, int tagId=0); + void rescaleConstraint(int id, double coeff); void declareUnknowns(VEC_pD ¶ms); diff --git a/src/Mod/Sketcher/App/freegcs/Geo.h b/src/Mod/Sketcher/App/freegcs/Geo.h index 24ed45f1b6..b44daa73ce 100644 --- a/src/Mod/Sketcher/App/freegcs/Geo.h +++ b/src/Mod/Sketcher/App/freegcs/Geo.h @@ -65,6 +65,28 @@ namespace GCS Point center; double *rad; }; + + class Ellipse + { + public: + Ellipse(){ radmin = 0;} + Point center; + Point focus1; //+x + double *radmin; + }; + + class ArcOfEllipse + { + public: + ArcOfEllipse(){startAngle=0;endAngle=0;radmin = 0;} + double *startAngle; + double *endAngle; + double *radmin; + Point start; + Point end; + Point center; + Point focus1; //+x + }; } //namespace GCS diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 4dc2d0a25c..347067c800 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -147,8 +147,8 @@ bool isSimpleVertex(const Sketcher::SketchObject* Obj, int GeoId, PointPos PosId if (geo->getTypeId() == Part::GeomPoint::getClassTypeId()) return true; else if (PosId == Sketcher::mid && - (geo->getTypeId() == Part::GeomCircle::getClassTypeId() || - geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId())) + (geo->getTypeId() == Part::GeomCircle::getClassTypeId() || // TODO: ellipse + geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId())) return true; else return false; @@ -802,8 +802,10 @@ void CmdSketcherConstrainPointOnObject::activated(int iMsg) // Currently only accepts line segments and circles if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId() || - geom->getTypeId() == Part::GeomCircle::getClassTypeId() || - geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() ) { + geom->getTypeId() == Part::GeomCircle::getClassTypeId() || // TODO: ellipse + geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() || + geom->getTypeId() == Part::GeomEllipse::getClassTypeId() || + geom->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() ) { openCommand("add point on object constraint"); Gui::Command::doCommand( @@ -1287,7 +1289,7 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) } else if (geo2->getTypeId() != Part::GeomLineSegment::getClassTypeId() && geo2->getTypeId() != Part::GeomArcOfCircle::getClassTypeId() && - geo2->getTypeId() != Part::GeomCircle::getClassTypeId()) { + geo2->getTypeId() != Part::GeomCircle::getClassTypeId()) { // TODO: ellipse QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("The selected edge should be an arc, line or circle.")); return; @@ -1490,7 +1492,7 @@ void CmdSketcherConstrainRadius::activated(int iMsg) double radius = arc->getRadius(); geoIdRadiusMap.push_back(std::make_pair(GeoId, radius)); } - else if (geom && geom->getTypeId() == Part::GeomCircle::getClassTypeId()) { + else if (geom && geom->getTypeId() == Part::GeomCircle::getClassTypeId()) { // TODO: ellipse const Part::GeomCircle *circle = dynamic_cast(geom); double radius = circle->getRadius(); geoIdRadiusMap.push_back(std::make_pair(GeoId, radius)); @@ -1615,7 +1617,6 @@ bool CmdSketcherConstrainRadius::isActive(void) return isCreateConstraintActive( getActiveGuiDocument() ); } - DEF_STD_CMD_A(CmdSketcherConstrainAngle); CmdSketcherConstrainAngle::CmdSketcherConstrainAngle() @@ -1764,7 +1765,6 @@ bool CmdSketcherConstrainAngle::isActive(void) return isCreateConstraintActive( getActiveGuiDocument() ); } - DEF_STD_CMD_A(CmdSketcherConstrainEqual); CmdSketcherConstrainEqual::CmdSketcherConstrainEqual() @@ -1838,7 +1838,7 @@ void CmdSketcherConstrainEqual::activated(int iMsg) lineSel = true; else if (geo->getTypeId() != Part::GeomArcOfCircle::getClassTypeId()) arcSel = true; - else if (geo->getTypeId() != Part::GeomCircle::getClassTypeId()) + else if (geo->getTypeId() != Part::GeomCircle::getClassTypeId()) // TODO: ellipse circSel = true; else { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), @@ -2027,7 +2027,412 @@ bool CmdSketcherConstrainSymmetric::isActive(void) return isCreateConstraintActive( getActiveGuiDocument() ); } +DEF_STD_CMD_A(CmdSketcherConstrainInternalAlignment); +CmdSketcherConstrainInternalAlignment::CmdSketcherConstrainInternalAlignment() + :Command("Sketcher_ConstrainInternalAlignment") +{ + sAppModule = "Sketcher"; + sGroup = QT_TR_NOOP("Sketcher"); + sMenuText = QT_TR_NOOP("Constrain InternalAlignment"); + sToolTipText = QT_TR_NOOP("Constraint an element to be aligned with the internal geometry of another element"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Constraint_InternalAlignment"; + sAccel = "Ctrl+A"; + eType = ForEdit; +} + +void CmdSketcherConstrainInternalAlignment::activated(int iMsg) +{ + // get the selection + std::vector selection = getSelection().getSelectionEx(); + + // only one sketch with its subelements are allowed to be selected + if (selection.size() != 1) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select at least one ellipse and one edge from the sketch.")); + return; + } + + // get the needed lists and objects + const std::vector &SubNames = selection[0].getSubNames(); + Sketcher::SketchObject* Obj = dynamic_cast(selection[0].getObject()); + + // go through the selected subelements + if (SubNames.size() < 2) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select at least one ellipse and one edge from the sketch.")); + return; + } + + std::vector pointids; + std::vector lineids; + std::vector ellipseids; + std::vector arcsofellipseids; + + bool hasAlreadyExternal = false; + + for (std::vector::const_iterator it=SubNames.begin(); it != SubNames.end(); ++it) { + + int GeoId; + Sketcher::PointPos PosId; + getIdsFromName(*it, Obj, GeoId, PosId); + + if (GeoId < 0) { + if (GeoId == -1 || GeoId == -2) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Sketch axes cannot be used in internal alignment constraint")); + return; + } + else if (hasAlreadyExternal) { + checkBothExternal(-1,-2); // just for printing the error message + return; + } + else + hasAlreadyExternal = true; + } + + const Part::Geometry *geo = Obj->getGeometry(GeoId); + + if (geo->getTypeId() == Part::GeomPoint::getClassTypeId()) + pointids.push_back(GeoId); + else if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) + lineids.push_back(GeoId); + else if (geo->getTypeId() == Part::GeomEllipse::getClassTypeId()) + ellipseids.push_back(GeoId); + else if (geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) + arcsofellipseids.push_back(GeoId); + else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select two or more compatible edges")); + return; + } + } + + int GeoId; + Sketcher::PointPos PosId; + getIdsFromName(SubNames[SubNames.size()-1], Obj, GeoId, PosId); // last selected element + + const Part::Geometry *geo = Obj->getGeometry(GeoId); + + // Currently it is only supported for ellipses + if(geo->getTypeId() == Part::GeomEllipse::getClassTypeId()) { + + // Priority list + // EllipseMajorDiameter = 1, + // EllipseMinorDiameter = 2, + // EllipseFocus1 = 3, + // EllipseFocus2 = 4 + + if(ellipseids.size()>1){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("You can not internally constraint an ellipse on other ellipse. Select only one ellipse.")); + return; + } + + if (pointids.size()>2) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Maximum 2 points are supported.")); + return; + } + + if (lineids.size()>2) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Maximum 2 lines are supported.")); + return; + } + + // look for which internal constraints are already applied + bool major=false; + bool minor=false; + bool focus1=false; + bool focus2=false; + bool extra_elements=false; + + const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues(); + + for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin(); + it != vals.end(); ++it) { + if((*it)->Type == Sketcher::InternalAlignment && (*it)->First == GeoId) + { + switch((*it)->AlignmentType){ + case Sketcher::EllipseMajorDiameter: + major=true; + break; + case Sketcher::EllipseMinorDiameter: + minor=true; + break; + case Sketcher::EllipseFocus1: + focus1=true; + break; + case Sketcher::EllipseFocus2: + focus2=true; + break; + } + } + } + + if(major && minor && focus1 && focus2) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Nothing to constraint"), + QObject::tr("Currently all internal geometry of the ellipse is already exposed.")); + return; + } + + if((!(focus1 && focus2) && pointids.size()>=1) || // if some element is missing and we are adding an element of that type + (!(major && minor) && lineids.size()>=1) ){ + + openCommand("add internal alignment constraint"); + + if(pointids.size()>=1) + { + if(!focus1) { + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseFocus1',%d,%d,%d)) ", + selection[0].getFeatName(),pointids[0],Sketcher::start,ellipseids[0]); + } + else if(!focus2) { + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseFocus2',%d,%d,%d)) ", + selection[0].getFeatName(),pointids[0],Sketcher::start,ellipseids[0]); + focus2=true; + } + else + extra_elements=true; + } + + if(pointids.size()==2) + { + if(!focus2) { + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseFocus2',%d,%d,%d)) ", + selection[0].getFeatName(),pointids[1],Sketcher::start,ellipseids[0]); + } + else + extra_elements=true; + } + + if(lineids.size()>=1) + { + if(!major) { + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseMajorDiameter',%d,%d)) ", + selection[0].getFeatName(),lineids[0],ellipseids[0]); + + const Part::GeomLineSegment *geo = static_cast(Obj->getGeometry(lineids[0])); + + if(!geo->Construction) + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",selection[0].getFeatName(),lineids[0]); + + } + else if(!minor) { + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseMinorDiameter',%d,%d)) ", + selection[0].getFeatName(),lineids[0],ellipseids[0]); + + const Part::GeomLineSegment *geo = static_cast(Obj->getGeometry(lineids[0])); + + if(!geo->Construction) + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",selection[0].getFeatName(),lineids[0]); + + minor=true; + } + else + extra_elements=true; + } + if(lineids.size()==2) + { + if(!minor){ + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseMinorDiameter',%d,%d)) ", + selection[0].getFeatName(),lineids[1],ellipseids[0]); + + const Part::GeomLineSegment *geo = static_cast(Obj->getGeometry(lineids[1])); + + if(!geo->Construction) + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",selection[0].getFeatName(),lineids[1]); + } + else + extra_elements=true; + } + + // finish the transaction and update + commitCommand(); + updateActive(); + + if(extra_elements){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Extra elements"), + QObject::tr("More elements than possible for the given ellipse were provided. These were ignored.")); + } + + // clear the selection (convenience) + getSelection().clearSelection(); + } + else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Extra elements"), + QObject::tr("More elements than possible for the given ellipse were provided. These were ignored.")); + } + } + else if(geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { + + // Priority list + // EllipseMajorDiameter = 1, + // EllipseMinorDiameter = 2, + // EllipseFocus1 = 3, + // EllipseFocus2 = 4 + + if(arcsofellipseids.size()>1){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("You can not internally constraint an arc of ellipse on other arc of ellipse. Select only one arc of ellipse.")); + return; + } + + if(ellipseids.size()>0){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("You can not internally constraint an ellipse on an arc of ellipse. Select only one ellipse or arc of ellipse.")); + return; + } + + if (pointids.size()>2) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Maximum 2 points are supported.")); + return; + } + + if (lineids.size()>2) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Maximum 2 lines are supported.")); + return; + } + + // look for which internal constraints are already applied + bool major=false; + bool minor=false; + bool focus1=false; + bool focus2=false; + bool extra_elements=false; + + const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues(); + + for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin(); + it != vals.end(); ++it) { + if((*it)->Type == Sketcher::InternalAlignment && (*it)->First == GeoId) + { + switch((*it)->AlignmentType){ + case Sketcher::EllipseMajorDiameter: + major=true; + break; + case Sketcher::EllipseMinorDiameter: + minor=true; + break; + case Sketcher::EllipseFocus1: + focus1=true; + break; + case Sketcher::EllipseFocus2: + focus2=true; + break; + } + } + } + + if(major && minor && focus1 && focus2) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Nothing to constraint"), + QObject::tr("Currently all internal geometry of the arc of ellipse is already exposed.")); + return; + } + + if((!(focus1 && focus2) && pointids.size()>=1) || // if some element is missing and we are adding an element of that type + (!(major && minor) && lineids.size()>=1) ){ + + openCommand("add internal alignment constraint"); + + if(pointids.size()>=1) + { + if(!focus1) { + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseFocus1',%d,%d,%d)) ", + selection[0].getFeatName(),pointids[0],Sketcher::start,arcsofellipseids[0]); + } + else if(!focus2) { + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseFocus2',%d,%d,%d)) ", + selection[0].getFeatName(),pointids[0],Sketcher::start,arcsofellipseids[0]); + focus2=true; + } + else + extra_elements=true; + } + + if(pointids.size()==2) + { + if(!focus2) { + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseFocus2',%d,%d,%d)) ", + selection[0].getFeatName(),pointids[1],Sketcher::start,arcsofellipseids[0]); + } + else + extra_elements=true; + } + + if(lineids.size()>=1) + { + if(!major) { + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseMajorDiameter',%d,%d)) ", + selection[0].getFeatName(),lineids[0],arcsofellipseids[0]); + + const Part::GeomLineSegment *geo = static_cast(Obj->getGeometry(lineids[0])); + + if(!geo->Construction) + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",selection[0].getFeatName(),lineids[0]); + + } + else if(!minor) { + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseMinorDiameter',%d,%d)) ", + selection[0].getFeatName(),lineids[0],arcsofellipseids[0]); + + const Part::GeomLineSegment *geo = static_cast(Obj->getGeometry(lineids[0])); + + if(!geo->Construction) + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",selection[0].getFeatName(),lineids[0]); + + minor=true; + } + else + extra_elements=true; + } + if(lineids.size()==2) + { + if(!minor){ + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseMinorDiameter',%d,%d)) ", + selection[0].getFeatName(),lineids[1],arcsofellipseids[0]); + + const Part::GeomLineSegment *geo = static_cast(Obj->getGeometry(lineids[1])); + + if(!geo->Construction) + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",selection[0].getFeatName(),lineids[1]); + } + else + extra_elements=true; + } + + // finish the transaction and update + commitCommand(); + updateActive(); + + if(extra_elements){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Extra elements"), + QObject::tr("More elements than possible for the given ellipse were provided. These were ignored.")); + } + + // clear the selection (convenience) + getSelection().clearSelection(); + } + else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Extra elements"), + QObject::tr("More elements than possible for the given arc of ellipse were provided. These were ignored.")); + } + } + else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Currently internal geometry is only supported for ellipse or arc of ellipse. The last selected element must be an ellipse or an arc of ellipse.")); + } +} + +bool CmdSketcherConstrainInternalAlignment::isActive(void) +{ + return isCreateConstraintActive( getActiveGuiDocument() ); +} void CreateSketcherCommandsConstraints(void) { @@ -2048,4 +2453,5 @@ void CreateSketcherCommandsConstraints(void) rcCmdMgr.addCommand(new CmdSketcherConstrainEqual()); rcCmdMgr.addCommand(new CmdSketcherConstrainPointOnObject()); rcCmdMgr.addCommand(new CmdSketcherConstrainSymmetric()); + rcCmdMgr.addCommand(new CmdSketcherConstrainInternalAlignment()); } diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index 82cb3de2aa..889baf358e 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -1793,7 +1793,580 @@ bool CmdSketcherCreateCircle::isActive(void) { return isCreateGeoActive(getActiveGuiDocument()); } +// ====================================================================================== +/* XPM */ +static const char *cursor_createellipse[]={ +"32 32 3 1", +"+ c white", +"# c red", +". c None", +"......+.........................", +"......+.........................", +"......+.........................", +"......+.........................", +"......+.........................", +"................................", +"+++++...+++++...................", +"................................", +"......+.........................", +"......+.........................", +"......+.........................", +"......+.........................", +"......+.........................", +"......+..............#####......", +"..................###.....#.....", +"...............###.......##.....", +".............##..........##.....", +"...........##............##.....", +"..........##.....###....##......", +".........##.....#.#.....#.......", +"........##.....###....##........", +"........##...........##.........", +".......##..........###..........", +"......##........####............", +"......#.....####................", +"......######....................", +"................................", +"................................", +"................................", +"................................", +"................................", +"................................"}; + +class DrawSketchHandlerEllipse : public DrawSketchHandler +{ +public: + DrawSketchHandlerEllipse() : Mode(STATUS_SEEK_First),EditCurve(34){} + virtual ~DrawSketchHandlerEllipse(){} + /// mode table + enum SelectMode { + STATUS_SEEK_First, /**< enum value ----. */ + STATUS_SEEK_Second, /**< enum value ----. */ + STATUS_SEEK_Third, /**< enum value ----. */ + STATUS_Close + }; + + virtual void activated(ViewProviderSketch *sketchgui) + { + setCursor(QPixmap(cursor_createellipse),7,7); + } + + virtual void mouseMove(Base::Vector2D onSketchPos) + { + if (Mode==STATUS_SEEK_First) { + setPositionText(onSketchPos); + if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) { // TODO: ellipse prio 1 + renderSuggestConstraintsCursor(sugConstr1); + return; + } + } + else if (Mode==STATUS_SEEK_Second) { + double rx0 = onSketchPos.fX - EditCurve[0].fX; + double ry0 = onSketchPos.fY - EditCurve[0].fY; + for (int i=0; i < 16; i++) { + double angle = i*M_PI/16.0; + double rx = rx0 * cos(angle) + ry0 * sin(angle); + double ry = -rx0 * sin(angle) + ry0 * cos(angle); + EditCurve[1+i] = Base::Vector2D(EditCurve[0].fX + rx, EditCurve[0].fY + ry); + EditCurve[17+i] = Base::Vector2D(EditCurve[0].fX - rx, EditCurve[0].fY - ry); + } + EditCurve[33] = EditCurve[1]; + + // Display radius for user + float radius = (onSketchPos - EditCurve[0]).Length(); + + SbString text; + text.sprintf(" (%.1fR,%.1fR)", radius,radius); + setPositionText(onSketchPos, text); + + sketchgui->drawEdit(EditCurve); + if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f), + AutoConstraint::CURVE)) { + renderSuggestConstraintsCursor(sugConstr2); + return; + } + } + else if (Mode==STATUS_SEEK_Third) { + double rx0 = EditCurve[1].fX - EditCurve[0].fX; // first semidiameter + double ry0 = EditCurve[1].fY - EditCurve[0].fY; // first semidiameter + + // angle between the major axis of the ellipse and the X axis + double a = (EditCurve[1]-EditCurve[0]).Length(); + double phi = atan2f(EditCurve[1].fY-EditCurve[0].fY,EditCurve[1].fX-EditCurve[0].fX); + + // This is the angle at cursor point + double angleatpoint = acos((onSketchPos.fX-EditCurve[0].fX+(onSketchPos.fY-EditCurve[0].fY)*tan(phi))/(a*(cos(phi)+tan(phi)*sin(phi)))); + double b=(onSketchPos.fY-EditCurve[0].fY-a*cos(angleatpoint)*sin(phi))/(sin(angleatpoint)*cos(phi)); + + for (int i=1; i < 16; i++) { + double angle = i*M_PI/16.0; + double rx = a * cos(angle) * cos(phi) - b * sin(angle) * sin(phi); + double ry = a * cos(angle) * sin(phi) + b * sin(angle) * cos(phi); + EditCurve[1+i] = Base::Vector2D(EditCurve[0].fX + rx, EditCurve[0].fY + ry); + EditCurve[17+i] = Base::Vector2D(EditCurve[0].fX - rx, EditCurve[0].fY - ry); + } + EditCurve[33] = EditCurve[1]; + EditCurve[17] = EditCurve[16]; + + // Display radius for user + SbString text; + text.sprintf(" (%.1fR,%.1fR)", a, b); + setPositionText(onSketchPos, text); + + sketchgui->drawEdit(EditCurve); + if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f), + AutoConstraint::CURVE)) { + renderSuggestConstraintsCursor(sugConstr2); + return; + } + } + applyCursor(); + } + + virtual bool pressButton(Base::Vector2D onSketchPos) + { + if (Mode==STATUS_SEEK_First){ + EditCurve[0] = onSketchPos; + Mode = STATUS_SEEK_Second; + } + else if(Mode==STATUS_SEEK_Second) { + EditCurve[1] = onSketchPos; + Mode = STATUS_SEEK_Third; + } + else { + EditCurve[2] = onSketchPos; + Mode = STATUS_Close; + } + return true; + } + + virtual bool releaseButton(Base::Vector2D onSketchPos) + { + if (Mode==STATUS_Close) { + unsetCursor(); + resetPositionText(); + + // angle between the major axis of the ellipse and the X axis + double a = (EditCurve[1]-EditCurve[0]).Length(); + double phi = atan2f(EditCurve[1].fY-EditCurve[0].fY,EditCurve[1].fX-EditCurve[0].fX); + + // This is the angle at cursor point + double angleatpoint = acos((EditCurve[2].fX-EditCurve[0].fX+(EditCurve[2].fY-EditCurve[0].fY)*tan(phi))/(a*(cos(phi)+tan(phi)*sin(phi)))); + double b=(EditCurve[2].fY-EditCurve[0].fY-a*cos(angleatpoint)*sin(phi))/(sin(angleatpoint)*cos(phi)); + + Base::Vector2D majAxisDir,minAxisDir,minAxisPoint,majAxisPoint; + // We always create a CCW ellipse, because we want our XY reference system to be in the +X +Y direction + // Our normal will then always be in the +Z axis (local +Z axis of the sketcher) + + if(a>b) + { + // force second semidiameter to be perpendicular to first semidiamater + majAxisDir = EditCurve[1] - EditCurve[0]; + Base::Vector2D perp(-majAxisDir.fY,majAxisDir.fX); + perp.Normalize(); + perp.Scale(abs(b)); + minAxisPoint = EditCurve[0]+perp; + majAxisPoint = EditCurve[0]+majAxisDir; + } + else { + // force second semidiameter to be perpendicular to first semidiamater + minAxisDir = EditCurve[1] - EditCurve[0]; + Base::Vector2D perp(minAxisDir.fY,-minAxisDir.fX); + perp.Normalize(); + perp.Scale(abs(b)); + majAxisPoint = EditCurve[0]+perp; + minAxisPoint = EditCurve[0]+minAxisDir; + } + + Gui::Command::openCommand("Add sketch ellipse"); + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.addGeometry(Part.Ellipse" + "(App.Vector(%f,%f,0),App.Vector(%f,%f,0),App.Vector(%f,%f,0)))", + sketchgui->getObject()->getNameInDocument(), + majAxisPoint.fX, majAxisPoint.fY, + minAxisPoint.fX, minAxisPoint.fY, + EditCurve[0].fX, EditCurve[0].fY); + + Gui::Command::commitCommand(); + Gui::Command::updateActive(); + + // add auto constraints for the center point + if (sugConstr1.size() > 0) { + createAutoConstraints(sugConstr1, getHighestCurveIndex(), Sketcher::mid); + sugConstr1.clear(); + } + + // add suggested constraints for circumference + if (sugConstr2.size() > 0) { + //createAutoConstraints(sugConstr2, getHighestCurveIndex(), Sketcher::none); + sugConstr2.clear(); + } + + EditCurve.clear(); + sketchgui->drawEdit(EditCurve); + sketchgui->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider + } + return true; + } +protected: + SelectMode Mode; + std::vector EditCurve; + std::vector sugConstr1, sugConstr2; + +}; + +DEF_STD_CMD_A(CmdSketcherCreateEllipse); + +CmdSketcherCreateEllipse::CmdSketcherCreateEllipse() + : Command("Sketcher_CreateEllipse") +{ + sAppModule = "Sketcher"; + sGroup = QT_TR_NOOP("Sketcher"); + sMenuText = QT_TR_NOOP("Create ellipse"); + sToolTipText = QT_TR_NOOP("Create an ellipse in the sketch"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Sketcher_CreateEllipse"; + eType = ForEdit; +} + +void CmdSketcherCreateEllipse::activated(int iMsg) +{ + ActivateHandler(getActiveGuiDocument(),new DrawSketchHandlerEllipse() ); +} + +bool CmdSketcherCreateEllipse::isActive(void) +{ + return isCreateGeoActive(getActiveGuiDocument()); +} + +// ====================================================================================== + +/* XPM */ +static const char *cursor_createarcofellipse[]={ +"32 32 3 1", +"+ c white", +"# c red", +". c None", +"......+.........................", +"......+.........................", +"......+.........................", +"......+.........................", +"......+.........................", +"................................", +"+++++...+++++...................", +"................................", +"......+.........................", +"......+.........................", +"......+................##.......", +"......+..............##.........", +"......+............##...........", +"......+...........##............", +"................##..............", +"...............##...............", +"..............##................", +".............###................", +"............##.........###......", +"...........##.........#.#.......", +"...........##.........###.......", +"..........##....................", +".........##.....................", +"........##......................", +"........##......................", +"........##......................", +"........#.....####..............", +"........######..................", +"................................", +"................................", +"................................", +"................................"}; + +class DrawSketchHandlerArcOfEllipse : public DrawSketchHandler +{ +public: + DrawSketchHandlerArcOfEllipse() : Mode(STATUS_SEEK_First),EditCurve(34){} + virtual ~DrawSketchHandlerArcOfEllipse(){} + /// mode table + enum SelectMode { + STATUS_SEEK_First, /**< enum value ----. */ + STATUS_SEEK_Second, /**< enum value ----. */ + STATUS_SEEK_Third, /**< enum value ----. */ + STATUS_SEEK_Fourth, /**< enum value ----. */ + STATUS_Close + }; + + virtual void activated(ViewProviderSketch *sketchgui) + { + setCursor(QPixmap(cursor_createarcofellipse),7,7); + } + + virtual void mouseMove(Base::Vector2D onSketchPos) + { + if (Mode==STATUS_SEEK_First) { + setPositionText(onSketchPos); + if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) { // TODO: ellipse prio 1 + renderSuggestConstraintsCursor(sugConstr1); + return; + } + } + else if (Mode==STATUS_SEEK_Second) { + double rx0 = onSketchPos.fX - EditCurve[0].fX; + double ry0 = onSketchPos.fY - EditCurve[0].fY; + for (int i=0; i < 16; i++) { + double angle = i*M_PI/16.0; + double rx = rx0 * cos(angle) + ry0 * sin(angle); + double ry = -rx0 * sin(angle) + ry0 * cos(angle); + EditCurve[1+i] = Base::Vector2D(EditCurve[0].fX + rx, EditCurve[0].fY + ry); + EditCurve[17+i] = Base::Vector2D(EditCurve[0].fX - rx, EditCurve[0].fY - ry); + } + EditCurve[33] = EditCurve[1]; + + // Display radius for user + float radius = (onSketchPos - EditCurve[0]).Length(); + + SbString text; + text.sprintf(" (%.1fR,%.1fR)", radius,radius); + setPositionText(onSketchPos, text); + + sketchgui->drawEdit(EditCurve); + if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f), + AutoConstraint::CURVE)) { + renderSuggestConstraintsCursor(sugConstr2); + return; + } + } + else if (Mode==STATUS_SEEK_Third) { + double rx0 = EditCurve[1].fX - EditCurve[0].fX; // first semidiameter + double ry0 = EditCurve[1].fY - EditCurve[0].fY; // first semidiameter + + // angle between the major axis of the ellipse and the X axis + double a = (EditCurve[1]-EditCurve[0]).Length(); + double phi = atan2f(EditCurve[1].fY-EditCurve[0].fY,EditCurve[1].fX-EditCurve[0].fX); + + // This is the angle at cursor point + double angleatpoint = acos((onSketchPos.fX-EditCurve[0].fX+(onSketchPos.fY-EditCurve[0].fY)*tan(phi))/(a*(cos(phi)+tan(phi)*sin(phi)))); + double b=(onSketchPos.fY-EditCurve[0].fY-a*cos(angleatpoint)*sin(phi))/(sin(angleatpoint)*cos(phi)); + + for (int i=1; i < 16; i++) { + double angle = i*M_PI/16.0; + double rx = a * cos(angle) * cos(phi) - b * sin(angle) * sin(phi); + double ry = a * cos(angle) * sin(phi) + b * sin(angle) * cos(phi); + EditCurve[1+i] = Base::Vector2D(EditCurve[0].fX + rx, EditCurve[0].fY + ry); + EditCurve[17+i] = Base::Vector2D(EditCurve[0].fX - rx, EditCurve[0].fY - ry); + } + EditCurve[33] = EditCurve[1]; + EditCurve[17] = EditCurve[16]; + + // Display radius for user + SbString text; + text.sprintf(" (%.1fR,%.1fR)", a, b); + setPositionText(onSketchPos, text); + + sketchgui->drawEdit(EditCurve); + if (seekAutoConstraint(sugConstr3, onSketchPos, Base::Vector2D(0.f,0.f), + AutoConstraint::CURVE)) { + renderSuggestConstraintsCursor(sugConstr3); + return; + } + } + else if (Mode==STATUS_SEEK_Fourth) { // here we differ from ellipse creation + + double rx0 = axisPoint.fX - centerPoint.fX; // first semidiameter + double ry0 = axisPoint.fY - centerPoint.fY; // first semidiameter + + // angle between the major axis of the ellipse and the X axis + double a = (axisPoint-centerPoint).Length(); + double phi = atan2(axisPoint.fY-centerPoint.fY,axisPoint.fX-centerPoint.fX); + + // This is the angle at cursor point + double angleatpoint = acos((startingPoint.fX-centerPoint.fX+(startingPoint.fY-centerPoint.fY)*tan(phi))/(a*(cos(phi)+tan(phi)*sin(phi)))); + double b=abs((startingPoint.fY-centerPoint.fY-a*cos(angleatpoint)*sin(phi))/(sin(angleatpoint)*cos(phi))); + + double rxs = startingPoint.fX - centerPoint.fX; + double rys = startingPoint.fY - centerPoint.fY; + startAngle = atan2(a*(rys*cos(phi)-rxs*sin(phi)), b*(rxs*cos(phi)+rys*sin(phi))); // eccentric anomaly angle + + double angle1 = atan2(a*((onSketchPos.fY - centerPoint.fY)*cos(phi)-(onSketchPos.fX - centerPoint.fX)*sin(phi)), + b*((onSketchPos.fX - centerPoint.fX)*cos(phi)+(onSketchPos.fY - centerPoint.fY)*sin(phi)))- startAngle; + + double angle2 = angle1 + (angle1 < 0. ? 2 : -2) * M_PI ; + arcAngle = abs(angle1-arcAngle) < abs(angle2-arcAngle) ? angle1 : angle2; + + for (int i=0; i < 34; i++) { + double angle = startAngle+i*arcAngle/34.0; + double rx = a * cos(angle) * cos(phi) - b * sin(angle) * sin(phi); + double ry = a * cos(angle) * sin(phi) + b * sin(angle) * cos(phi); + EditCurve[i] = Base::Vector2D(centerPoint.fX + rx, centerPoint.fY + ry); + } +// EditCurve[33] = EditCurve[1]; +// EditCurve[17] = EditCurve[16]; + + // Display radii and angle for user + SbString text; + text.sprintf(" (%.1fR,%.1fR,%.1fdeg)", a, b, arcAngle * 180 / M_PI); + setPositionText(onSketchPos, text); + + sketchgui->drawEdit(EditCurve); + if (seekAutoConstraint(sugConstr4, onSketchPos, Base::Vector2D(0.f,0.f), + AutoConstraint::CURVE)) { + renderSuggestConstraintsCursor(sugConstr4); + return; + } + } + + + + applyCursor(); + } + + virtual bool pressButton(Base::Vector2D onSketchPos) + { + if (Mode==STATUS_SEEK_First){ + EditCurve[0] = onSketchPos; + centerPoint = onSketchPos; + Mode = STATUS_SEEK_Second; + } + else if(Mode==STATUS_SEEK_Second) { + EditCurve[1] = onSketchPos; + axisPoint = onSketchPos; + Mode = STATUS_SEEK_Third; + } + else if(Mode==STATUS_SEEK_Third) { + startingPoint = onSketchPos; + arcAngle = 0.; + arcAngle_t= 0.; + Mode = STATUS_SEEK_Fourth; + } + else { // Fourth + endPoint = onSketchPos; + + Mode = STATUS_Close; + } + return true; + } + + virtual bool releaseButton(Base::Vector2D onSketchPos) + { + if (Mode==STATUS_Close) { + unsetCursor(); + resetPositionText(); + + // angle between the major axis of the ellipse and the X axis + double a = (axisPoint-centerPoint).Length(); + double phi = atan2(axisPoint.fY-centerPoint.fY,axisPoint.fX-centerPoint.fX); + + // This is the angle at cursor point + double angleatpoint = acos((startingPoint.fX-centerPoint.fX+(startingPoint.fY-centerPoint.fY)*tan(phi))/(a*(cos(phi)+tan(phi)*sin(phi)))); + double b=abs((startingPoint.fY-centerPoint.fY-a*cos(angleatpoint)*sin(phi))/(sin(angleatpoint)*cos(phi))); + + double angle1 = atan2(a*((endPoint.fY - centerPoint.fY)*cos(phi)-(endPoint.fX - centerPoint.fX)*sin(phi)), + b*((endPoint.fX - centerPoint.fX)*cos(phi)+(endPoint.fY - centerPoint.fY)*sin(phi)))- startAngle; + + double angle2 = angle1 + (angle1 < 0. ? 2 : -2) * M_PI ; + arcAngle = abs(angle1-arcAngle) < abs(angle2-arcAngle) ? angle1 : angle2; + + if (arcAngle > 0) + endAngle = startAngle + arcAngle; + else { + endAngle = startAngle; + startAngle += arcAngle; + } + + Base::Vector2D majAxisDir,minAxisDir,minAxisPoint,majAxisPoint; + // We always create a CCW ellipse, because we want our XY reference system to be in the +X +Y direction + // Our normal will then always be in the +Z axis (local +Z axis of the sketcher) + + if(a>b) + { + // force second semidiameter to be perpendicular to first semidiamater + majAxisDir = axisPoint - centerPoint; + Base::Vector2D perp(-majAxisDir.fY,majAxisDir.fX); + perp.Normalize(); + perp.Scale(abs(b)); + minAxisPoint = centerPoint+perp; + majAxisPoint = centerPoint+majAxisDir; + } + else { + // force second semidiameter to be perpendicular to first semidiamater + minAxisDir = axisPoint - centerPoint; + Base::Vector2D perp(minAxisDir.fY,-minAxisDir.fX); + perp.Normalize(); + perp.Scale(abs(b)); + majAxisPoint = centerPoint+perp; + minAxisPoint = centerPoint+minAxisDir; + endAngle += M_PI/2; + startAngle += M_PI/2; + } + + //startAngle=-M_PI/4; + //endAngle=M_PI/4; + + Gui::Command::openCommand("Add sketch arc of ellipse"); + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.addGeometry(Part.ArcOfEllipse" + "(Part.Ellipse(App.Vector(%f,%f,0),App.Vector(%f,%f,0),App.Vector(%f,%f,0))," + "%f,%f))", + sketchgui->getObject()->getNameInDocument(), + majAxisPoint.fX, majAxisPoint.fY, + minAxisPoint.fX, minAxisPoint.fY, + centerPoint.fX, centerPoint.fY, + startAngle, endAngle); //arcAngle > 0 ? 0 : 1); + + Gui::Command::commitCommand(); + Gui::Command::updateActive(); + + // add auto constraints for the center point + if (sugConstr1.size() > 0) { + createAutoConstraints(sugConstr1, getHighestCurveIndex(), Sketcher::mid); + sugConstr1.clear(); + } + + // add suggested constraints for circumference + if (sugConstr2.size() > 0) { + //createAutoConstraints(sugConstr2, getHighestCurveIndex(), Sketcher::none); + sugConstr2.clear(); + } + + EditCurve.clear(); + sketchgui->drawEdit(EditCurve); + sketchgui->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider + } + return true; + } +protected: + SelectMode Mode; + std::vector EditCurve; + Base::Vector2D centerPoint, axisPoint, startingPoint, endPoint; + double rx, ry, startAngle, endAngle, arcAngle, arcAngle_t; + std::vector sugConstr1, sugConstr2, sugConstr3, sugConstr4; + +}; + +DEF_STD_CMD_A(CmdSketcherCreateArcOfEllipse); + +CmdSketcherCreateArcOfEllipse::CmdSketcherCreateArcOfEllipse() + : Command("Sketcher_CreateArcOfEllipse") +{ + sAppModule = "Sketcher"; + sGroup = QT_TR_NOOP("Sketcher"); + sMenuText = QT_TR_NOOP("Create an arc of ellipse"); + sToolTipText = QT_TR_NOOP("Create an arc of ellipse in the sketch"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Sketcher_Elliptical_Arc"; + eType = ForEdit; +} + +void CmdSketcherCreateArcOfEllipse::activated(int iMsg) +{ + ActivateHandler(getActiveGuiDocument(),new DrawSketchHandlerArcOfEllipse() ); +} + +bool CmdSketcherCreateArcOfEllipse::isActive(void) +{ + return isCreateGeoActive(getActiveGuiDocument()); +} // ====================================================================================== @@ -2548,6 +3121,7 @@ namespace SketcherGui { geom->getTypeId() == Part::GeomCircle::getClassTypeId()|| geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) return true; + // TODO: ellipse } return false; } @@ -2628,6 +3202,7 @@ public: if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId() || geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() || geom->getTypeId() == Part::GeomCircle::getClassTypeId() + // TODO: ellipse ) { try { Gui::Command::openCommand("Trim edge"); @@ -3548,6 +4123,8 @@ void CreateSketcherCommandsCreateGeo(void) rcCmdMgr.addCommand(new CmdSketcherCreateCircle()); rcCmdMgr.addCommand(new CmdSketcherCreate3PointCircle()); rcCmdMgr.addCommand(new CmdSketcherCompCreateCircle()); + rcCmdMgr.addCommand(new CmdSketcherCreateEllipse()); + rcCmdMgr.addCommand(new CmdSketcherCreateArcOfEllipse()); rcCmdMgr.addCommand(new CmdSketcherCreateLine()); rcCmdMgr.addCommand(new CmdSketcherCreatePolyline()); rcCmdMgr.addCommand(new CmdSketcherCreateRectangle()); diff --git a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp index e189b19857..c4d7a19446 100644 --- a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp +++ b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp @@ -679,6 +679,285 @@ bool CmdSketcherSelectElementsAssociatedWithConstraints::isActive(void) return isSketcherAcceleratorActive( getActiveGuiDocument(), true ); } +DEF_STD_CMD_A(CmdSketcherRestoreInternalAlignmentGeometry); + +CmdSketcherRestoreInternalAlignmentGeometry::CmdSketcherRestoreInternalAlignmentGeometry() + :Command("Sketcher_RestoreInternalAlignmentGeometry") +{ + sAppModule = "Sketcher"; + sGroup = QT_TR_NOOP("Sketcher"); + sMenuText = QT_TR_NOOP("Show/hide internal geometry"); + sToolTipText = QT_TR_NOOP("Show all internal geometry / hide unused internal geometry"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Sketcher_Element_Ellipse_All"; + sAccel = "CTRL+SHIFT+E"; + eType = ForEdit; +} + +void CmdSketcherRestoreInternalAlignmentGeometry::activated(int iMsg) +{ + // get the selection + std::vector selection = getSelection().getSelectionEx(); + Sketcher::SketchObject* Obj = dynamic_cast(selection[0].getObject()); + + // only one sketch with its subelements are allowed to be selected + if (selection.size() != 1) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select elements from a single sketch.")); + return; + } + + // get the needed lists and objects + const std::vector &SubNames = selection[0].getSubNames(); + const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues(); + + std::string doc_name = Obj->getDocument()->getName(); + std::string obj_name = Obj->getNameInDocument(); + std::stringstream ss; + + getSelection().clearSelection(); + + // go through the selected subelements + for (std::vector::const_iterator it=SubNames.begin(); it != SubNames.end(); ++it) { + // only handle edges + if (it->size() > 4 && it->substr(0,4) == "Edge") { + int GeoId = std::atoi(it->substr(4,4000).c_str()) - 1; + const Part::Geometry *geo = Obj->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; + bool extra_elements=false; + + int majorelementindex=-1; + int minorelementindex=-1; + int focus1elementindex=-1; + int focus2elementindex=-1; + + const std::vector< Sketcher::Constraint * > &vals = Obj->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; + } + } + } + + if(major && minor && focus1 && focus2) + { + // 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; + + 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++; + } + // those with less than 2 constraints must be removed + if(majorconstraints>=2 && minorconstraints>=2 && focus1constraints>=2 && focus2constraints>=2) + return; // nothing to delete + + App::Document* doc = App::GetApplication().getActiveDocument(); + + if (!doc) return; + + doc->openTransaction("Delete"); + + if(majorconstraints<2) { + ss.str(std::string()); + ss << "Edge" << majorelementindex + 1; + Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); + } + + if(minorconstraints<2) { + ss.str(std::string()); + ss << "Edge" << minorelementindex + 1; + Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); + } + + if(focus1constraints<2) { + ss.str(std::string()); + int vertex = Obj->getVertexIndexGeoPos(focus1elementindex,Sketcher::start); + if(vertex>-1){ + ss << "Vertex" << vertex + 1; + Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); + } + } + + if(focus2constraints<2) { + ss.str(std::string()); + int vertex = Obj->getVertexIndexGeoPos(focus2elementindex,Sketcher::start); + if(vertex>-1){ + ss << "Vertex" << vertex + 1; + Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); + } + } + + SketcherGui::ViewProviderSketch* vp = dynamic_cast(getActiveGuiDocument()->getInEdit()); + + if (vp) { + std::vector sel = Gui::Selection().getSelectionEx(doc->getName()); + vp->onDelete(sel[0].getSubNames()); + } + + + doc->commitTransaction(); + return; + } + + Gui::Command::openCommand("Expose ellipse internal geometry"); + + int currentgeoid= Obj->getHighestCurveIndex(); + int incrgeo= 0; + int majorindex=-1; + int minorindex=-1; + + 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(); + } + + majord*=0.99; + minord*=0.99; + + + 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); + + try{ + if(!major) + { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))", + Obj->getNameInDocument(), + majornegativeend.x,majornegativeend.y,majorpositiveend.x,majorpositiveend.y); // create line for major axis + + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseMajorDiameter',%d,%d)) ", + selection[0].getFeatName(),currentgeoid+incrgeo+1,GeoId); // constrain major axis + majorindex=currentgeoid+incrgeo+1; + incrgeo++; + } + if(!minor) + { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))", + Obj->getNameInDocument(), + minorpositiveend.x,minorpositiveend.y,minornegativeend.x,minornegativeend.y); // create line for minor axis + + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseMinorDiameter',%d,%d)) ", + selection[0].getFeatName(),currentgeoid+incrgeo+1,GeoId); // constrain minor axis + minorindex=currentgeoid+incrgeo+1; + incrgeo++; + } + if(!focus1) + { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))", + Obj->getNameInDocument(), + focus1P.x,focus1P.y); + + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseFocus1',%d,%d,%d)) ", + selection[0].getFeatName(),currentgeoid+incrgeo+1,Sketcher::start,GeoId); // constrain major axis + incrgeo++; + } + if(!focus2) + { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))", + Obj->getNameInDocument(), + focus2P.x,focus2P.y); + + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseFocus2',%d,%d,%d)) ", + Obj->getNameInDocument(),currentgeoid+incrgeo+1,Sketcher::start,GeoId); // constrain major axis + } + + // Make lines construction lines + if(majorindex!=-1){ + doCommand(Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",Obj->getNameInDocument(),majorindex); + } + + if(minorindex!=-1){ + doCommand(Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",Obj->getNameInDocument(),minorindex); + } + + Gui::Command::commitCommand(); + Gui::Command::updateActive(); + + } + catch (const Base::Exception& e) { + Base::Console().Error("%s\n", e.what()); + Gui::Command::abortCommand(); + Gui::Command::updateActive(); + } + + } // if(geo->getTypeId() == Part::GeomEllipse::getClassTypeId()) + else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Currently internal geometry is only supported for ellipse and arc of ellipse. The last selected element must be an ellipse or an arc of ellipse.")); + } + + } + } +} + +bool CmdSketcherRestoreInternalAlignmentGeometry::isActive(void) +{ + return isSketcherAcceleratorActive( getActiveGuiDocument(), true ); +} + + void CreateSketcherCommandsConstraintAccel(void) { Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); @@ -692,4 +971,5 @@ void CreateSketcherCommandsConstraintAccel(void) rcCmdMgr.addCommand(new CmdSketcherSelectRedundantConstraints()); rcCmdMgr.addCommand(new CmdSketcherSelectConflictingConstraints()); rcCmdMgr.addCommand(new CmdSketcherSelectElementsAssociatedWithConstraints()); + rcCmdMgr.addCommand(new CmdSketcherRestoreInternalAlignmentGeometry()); } diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp b/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp index 1559de143e..681eeb7b31 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp +++ b/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp @@ -241,6 +241,27 @@ int DrawSketchHandler::seekAutoConstraint(std::vector &suggested tangDeviation = projDist; } + } else if ((*it)->getTypeId() == Part::GeomEllipse::getClassTypeId()) { + // TODO: Ellipse + const Part::GeomEllipse *ellipse = dynamic_cast((*it)); + + Base::Vector3d center = ellipse->getCenter(); + Base::Vector3d tmpPos(Pos.fX, Pos.fY, 0.f); + + double radius = ellipse->getMajorRadius(); + + Base::Vector3d projPnt(0.f, 0.f, 0.f); + projPnt = projPnt.ProjToLine(center - tmpPos, Base::Vector3d(Dir.fX, Dir.fY)); + double projDist = projPnt.Length(); + + if ( (projDist < radius + tangDeviation ) && (projDist > radius - tangDeviation)) { + //Find if nearest + if (projDist < tangDeviation) { + tangId = i; + tangDeviation = projDist; + } + } + } else if ((*it)->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { const Part::GeomArcOfCircle *arc = dynamic_cast((*it)); diff --git a/src/Mod/Sketcher/Gui/EditDatumDialog.cpp b/src/Mod/Sketcher/Gui/EditDatumDialog.cpp index 359504f23f..10bc918bc1 100644 --- a/src/Mod/Sketcher/Gui/EditDatumDialog.cpp +++ b/src/Mod/Sketcher/Gui/EditDatumDialog.cpp @@ -72,8 +72,10 @@ void EditDatumDialog::exec(bool atCursor) { // Return if constraint doesn't have editable value if (Constr->Type == Sketcher::Distance || - Constr->Type == Sketcher::DistanceX || Constr->Type == Sketcher::DistanceY || - Constr->Type == Sketcher::Radius || Constr->Type == Sketcher::Angle) { + Constr->Type == Sketcher::DistanceX || + Constr->Type == Sketcher::DistanceY || + Constr->Type == Sketcher::Radius || + Constr->Type == Sketcher::Angle) { if (sketch->hasConflicts()) { QMessageBox::critical(qApp->activeWindow(), QObject::tr("Distance constraint"), diff --git a/src/Mod/Sketcher/Gui/PropertyConstraintListItem.cpp b/src/Mod/Sketcher/Gui/PropertyConstraintListItem.cpp index 4ff1629957..7ea6dad2db 100644 --- a/src/Mod/Sketcher/Gui/PropertyConstraintListItem.cpp +++ b/src/Mod/Sketcher/Gui/PropertyConstraintListItem.cpp @@ -73,7 +73,7 @@ void PropertyConstraintListItem::initialize() (*it)->Type == Sketcher::DistanceX || (*it)->Type == Sketcher::DistanceY || (*it)->Type == Sketcher::Radius || - (*it)->Type == Sketcher::Angle) { + (*it)->Type == Sketcher::Angle ) { PropertyUnitItem* item = static_cast(PropertyUnitItem::create()); @@ -146,10 +146,10 @@ QVariant PropertyConstraintListItem::value(const App::Property* prop) const (*it)->Type == Sketcher::DistanceX || (*it)->Type == Sketcher::DistanceY || (*it)->Type == Sketcher::Radius || - (*it)->Type == Sketcher::Angle) { + (*it)->Type == Sketcher::Angle ) { Base::Quantity quant; - if ((*it)->Type == Sketcher::Angle) { + if ((*it)->Type == Sketcher::Angle ) { double datum = Base::toDegrees((*it)->Value); quant.setUnit(Base::Unit::Angle); quant.setValue(datum); @@ -220,7 +220,7 @@ bool PropertyConstraintListItem::event (QEvent* ev) (*it)->Type == Sketcher::DistanceX || (*it)->Type == Sketcher::DistanceY || (*it)->Type == Sketcher::Radius || - (*it)->Type == Sketcher::Angle) { + (*it)->Type == Sketcher::Angle ) { // Get the internal name QString internalName = QString::fromLatin1("Constraint%1").arg(id+1); diff --git a/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp b/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp index cfc6b266c8..1a0eb7d219 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp @@ -319,14 +319,8 @@ void TaskSketcherConstrains::on_listWidgetConstraints_itemChanged(QListWidgetIte QString unitStr; switch(v->Type) { case Sketcher::Distance: - unitStr = Base::Quantity(v->Value,Base::Unit::Length).getUserString(); - break; case Sketcher::DistanceX: - unitStr = Base::Quantity(v->Value,Base::Unit::Length).getUserString(); - break; case Sketcher::DistanceY: - unitStr = Base::Quantity(v->Value,Base::Unit::Length).getUserString(); - break; case Sketcher::Radius: unitStr = Base::Quantity(v->Value,Base::Unit::Length).getUserString(); break; @@ -360,10 +354,18 @@ void TaskSketcherConstrains::slotConstraintsChanged(void) QIcon tang ( Gui::BitmapFactory().pixmap("Constraint_Tangent") ); QIcon dist ( Gui::BitmapFactory().pixmap("Constraint_Length") ); QIcon radi ( Gui::BitmapFactory().pixmap("Constraint_Radius") ); + QIcon majradi ( Gui::BitmapFactory().pixmap("Constraint_Ellipse_Major_Radius") ); + QIcon minradi ( Gui::BitmapFactory().pixmap("Constraint_Ellipse_Minor_Radius") ); QIcon angl ( Gui::BitmapFactory().pixmap("Constraint_InternalAngle") ); + QIcon ellipseXUAngl ( Gui::BitmapFactory().pixmap("Constraint_Ellipse_Axis_Angle") ); QIcon equal( Gui::BitmapFactory().pixmap("Constraint_EqualLength") ); QIcon pntoo( Gui::BitmapFactory().pixmap("Constraint_PointOnObject") ); QIcon symm ( Gui::BitmapFactory().pixmap("Constraint_Symmetric") ); + QIcon iaellipseminoraxis ( Gui::BitmapFactory().pixmap("Constraint_InternalAlignment_Ellipse_MinorAxis") ); + QIcon iaellipsemajoraxis ( Gui::BitmapFactory().pixmap("Constraint_InternalAlignment_Ellipse_MajorAxis") ); + QIcon iaellipsefocus1 ( Gui::BitmapFactory().pixmap("Constraint_InternalAlignment_Ellipse_Focus1") ); + QIcon iaellipsefocus2 ( Gui::BitmapFactory().pixmap("Constraint_InternalAlignment_Ellipse_Focus2") ); + QIcon iaellipseother ( Gui::BitmapFactory().pixmap("Constraint_InternalAlignment") ); assert(sketchView); // Build up ListView with the constraints @@ -464,6 +466,27 @@ void TaskSketcherConstrains::slotConstraintsChanged(void) ui->listWidgetConstraints->addItem(item); } break; + case Sketcher::InternalAlignment: + if (Filter<2 || (Filter==3 && !(*it)->Name.empty())) + switch((*it)->AlignmentType){ + case Sketcher::EllipseMajorDiameter: + ui->listWidgetConstraints->addItem(new ConstraintItem(iaellipsemajoraxis,name,i-1,(*it)->Type)); + break; + case Sketcher::EllipseMinorDiameter: + ui->listWidgetConstraints->addItem(new ConstraintItem(iaellipseminoraxis,name,i-1,(*it)->Type)); + break; + case Sketcher::EllipseFocus1: + ui->listWidgetConstraints->addItem(new ConstraintItem(iaellipsefocus1,name,i-1,(*it)->Type)); + break; + case Sketcher::EllipseFocus2: + ui->listWidgetConstraints->addItem(new ConstraintItem(iaellipsefocus2,name,i-1,(*it)->Type)); + break; + case Sketcher::Undef: + default: + ui->listWidgetConstraints->addItem(new ConstraintItem(iaellipseother,name,i-1,(*it)->Type)); + break; + } + break; default: ui->listWidgetConstraints->addItem(new ConstraintItem(name,i-1,(*it)->Type)); break; diff --git a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp index d4585eefeb..1859888607 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp @@ -148,7 +148,7 @@ void ElementView::contextMenuEvent (QContextMenuEvent* event) CONTEXT_ITEM("Constraint_Length","Length Constraint","Sketcher_ConstrainDistance",doLengthConstraint,true) CONTEXT_ITEM("Constraint_Radius","Radius Constraint","Sketcher_ConstrainRadius",doRadiusConstraint,true) CONTEXT_ITEM("Constraint_InternalAngle","Angle Constraint","Sketcher_ConstrainAngle",doAngleConstraint,true) - + menu.addSeparator(); CONTEXT_ITEM("Sketcher_AlterConstruction","Toggle construction line","Sketcher_ToggleConstruction",doToggleConstruction,true) @@ -638,7 +638,12 @@ void TaskSketcherElements::slotElementsChanged(void) QIcon Sketcher_Element_Line_EndPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Line_EndPoint") ); QIcon Sketcher_Element_Line_StartingPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Line_StartingPoint") ); QIcon Sketcher_Element_Point_StartingPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Point_StartingPoint") ); - + QIcon Sketcher_Element_Ellipse_Edge( Gui::BitmapFactory().pixmap("Sketcher_Element_Ellipse_Edge_2") ); + QIcon Sketcher_Element_Ellipse_MidPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Ellipse_CentrePoint") ); + QIcon Sketcher_Element_ArcOfEllipse_Edge( Gui::BitmapFactory().pixmap("Sketcher_Element_Elliptical_Arc_Edge") ); + QIcon Sketcher_Element_ArcOfEllipse_MidPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Elliptical_Arc_Centre_Point") ); + QIcon Sketcher_Element_ArcOfEllipse_StartingPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Elliptical_Arc_Start_Point") ); + QIcon Sketcher_Element_ArcOfEllipse_EndPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Elliptical_Arc_End_Point") ); QIcon none( Gui::BitmapFactory().pixmap("Sketcher_Element_SelectionTypeInvalid") ); assert(sketchView); @@ -654,29 +659,41 @@ void TaskSketcherElements::slotElementsChanged(void) Base::Type type = (*it)->getTypeId(); ui->listWidgetElements->addItem(new ElementItem( - (type == Part::GeomPoint::getClassTypeId() && element==1) ? Sketcher_Element_Point_StartingPoint : - (type == Part::GeomLineSegment::getClassTypeId() && element==0) ? Sketcher_Element_Line_Edge : - (type == Part::GeomLineSegment::getClassTypeId() && element==1) ? Sketcher_Element_Line_StartingPoint : - (type == Part::GeomLineSegment::getClassTypeId() && element==2) ? Sketcher_Element_Line_EndPoint : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==0) ? Sketcher_Element_Arc_Edge : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==1) ? Sketcher_Element_Arc_StartingPoint : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==2) ? Sketcher_Element_Arc_EndPoint : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==3) ? Sketcher_Element_Arc_MidPoint : - (type == Part::GeomCircle::getClassTypeId() && element==0) ? Sketcher_Element_Circle_Edge : - (type == Part::GeomCircle::getClassTypeId() && element==3) ? Sketcher_Element_Circle_MidPoint : + (type == Part::GeomPoint::getClassTypeId() && element==1) ? Sketcher_Element_Point_StartingPoint : + (type == Part::GeomLineSegment::getClassTypeId() && element==0) ? Sketcher_Element_Line_Edge : + (type == Part::GeomLineSegment::getClassTypeId() && element==1) ? Sketcher_Element_Line_StartingPoint : + (type == Part::GeomLineSegment::getClassTypeId() && element==2) ? Sketcher_Element_Line_EndPoint : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==0) ? Sketcher_Element_Arc_Edge : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==1) ? Sketcher_Element_Arc_StartingPoint : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==2) ? Sketcher_Element_Arc_EndPoint : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==3) ? Sketcher_Element_Arc_MidPoint : + (type == Part::GeomCircle::getClassTypeId() && element==0) ? Sketcher_Element_Circle_Edge : + (type == Part::GeomCircle::getClassTypeId() && element==3) ? Sketcher_Element_Circle_MidPoint : + (type == Part::GeomEllipse::getClassTypeId() && element==0) ? Sketcher_Element_Ellipse_Edge : + (type == Part::GeomEllipse::getClassTypeId() && element==3) ? Sketcher_Element_Ellipse_MidPoint : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfEllipse_Edge : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfEllipse_StartingPoint : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfEllipse_EndPoint : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfEllipse_MidPoint : none, - type == Part::GeomPoint::getClassTypeId() ? ( isNamingBoxChecked ? - (tr("Point") + QString::fromLatin1("(Edge%1)").arg(i)): - (QString::fromLatin1("%1-").arg(i)+tr("Point"))) : - type == Part::GeomLineSegment::getClassTypeId() ? ( isNamingBoxChecked ? - (tr("Line") + QString::fromLatin1("(Edge%1)").arg(i)): - (QString::fromLatin1("%1-").arg(i)+tr("Line"))) : - type == Part::GeomArcOfCircle::getClassTypeId() ? ( isNamingBoxChecked ? - (tr("Arc") + QString::fromLatin1("(Edge%1)").arg(i)): - (QString::fromLatin1("%1-").arg(i)+tr("Arc"))) : - type == Part::GeomCircle::getClassTypeId() ? ( isNamingBoxChecked ? - (tr("Circle") + QString::fromLatin1("(Edge%1)").arg(i)): - (QString::fromLatin1("%1-").arg(i)+tr("Circle"))) : + type == Part::GeomPoint::getClassTypeId() ? ( isNamingBoxChecked ? + (tr("Point") + QString::fromLatin1("(Edge%1)").arg(i)): + (QString::fromLatin1("%1-").arg(i)+tr("Point"))) : + type == Part::GeomLineSegment::getClassTypeId() ? ( isNamingBoxChecked ? + (tr("Line") + QString::fromLatin1("(Edge%1)").arg(i)): + (QString::fromLatin1("%1-").arg(i)+tr("Line"))) : + type == Part::GeomArcOfCircle::getClassTypeId() ? ( isNamingBoxChecked ? + (tr("Arc") + QString::fromLatin1("(Edge%1)").arg(i)): + (QString::fromLatin1("%1-").arg(i)+tr("Arc"))) : + type == Part::GeomCircle::getClassTypeId() ? ( isNamingBoxChecked ? + (tr("Circle") + QString::fromLatin1("(Edge%1)").arg(i)): + (QString::fromLatin1("%1-").arg(i)+tr("Circle"))) : + type == Part::GeomEllipse::getClassTypeId() ? ( isNamingBoxChecked ? + (tr("Ellipse") + QString::fromLatin1("(Edge%1)").arg(i)): + (QString::fromLatin1("%1-").arg(i)+tr("Ellipse"))) : + type == Part::GeomArcOfEllipse::getClassTypeId() ? ( isNamingBoxChecked ? + (tr("Elliptical Arc") + QString::fromLatin1("(Edge%1)").arg(i)): + (QString::fromLatin1("%1-").arg(i)+tr("Elliptical Arc"))) : ( isNamingBoxChecked ? (tr("Other") + QString::fromLatin1("(Edge%1)").arg(i)): (QString::fromLatin1("%1-").arg(i)+tr("Other"))), @@ -749,16 +766,17 @@ void TaskSketcherElements::on_listWidgetElements_filterShortcutPressed() switch(element) { + case 0: // Edge - element = ( type == Part::GeomCircle::getClassTypeId() ) ? 3 : 1; + element = ( type == Part::GeomCircle::getClassTypeId() || type == Part::GeomEllipse::getClassTypeId() ) ? 3 : 1; break; case 1: // StartingPoint - element = ( type == Part::GeomCircle::getClassTypeId() ) ? 3 : - ( type == Part::GeomPoint::getClassTypeId() ) ? 1 : 2; + element = ( type == Part::GeomCircle::getClassTypeId() || type == Part::GeomEllipse::getClassTypeId() ) ? 3 : + ( type == Part::GeomPoint::getClassTypeId() ) ? 1 : 2; break; case 2: // EndPoint element = ( type == Part::GeomLineSegment::getClassTypeId() ) ? 0 : - ( type == Part::GeomPoint::getClassTypeId() ) ? 1 : 3; + ( type == Part::GeomPoint::getClassTypeId() ) ? 1 : 3; break; case 3: // MidPoint element = ( type == Part::GeomPoint::getClassTypeId() ) ? 1 : 0; @@ -850,22 +868,34 @@ void TaskSketcherElements::updateIcons(int element) QIcon Sketcher_Element_Line_EndPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Line_EndPoint") ); QIcon Sketcher_Element_Line_StartingPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Line_StartingPoint") ); QIcon Sketcher_Element_Point_StartingPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Point_StartingPoint") ); + QIcon Sketcher_Element_Ellipse_Edge( Gui::BitmapFactory().pixmap("Sketcher_Element_Ellipse_Edge_2") ); + QIcon Sketcher_Element_Ellipse_MidPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Ellipse_CentrePoint") ); + QIcon Sketcher_Element_ArcOfEllipse_Edge( Gui::BitmapFactory().pixmap("Sketcher_Element_Elliptical_Arc_Edge") ); + QIcon Sketcher_Element_ArcOfEllipse_MidPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Elliptical_Arc_Centre_Point") ); + QIcon Sketcher_Element_ArcOfEllipse_StartingPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Elliptical_Arc_Start_Point") ); + QIcon Sketcher_Element_ArcOfEllipse_EndPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Elliptical_Arc_End_Point") ); QIcon none( Gui::BitmapFactory().pixmap("Sketcher_Element_SelectionTypeInvalid") ); for (int i=0;ilistWidgetElements->count(); i++) { Base::Type type = static_cast(ui->listWidgetElements->item(i))->GeometryType; ui->listWidgetElements->item(i)->setIcon( - (type == Part::GeomPoint::getClassTypeId() && element==1) ? Sketcher_Element_Point_StartingPoint : - (type == Part::GeomLineSegment::getClassTypeId() && element==0) ? Sketcher_Element_Line_Edge : - (type == Part::GeomLineSegment::getClassTypeId() && element==1) ? Sketcher_Element_Line_StartingPoint : - (type == Part::GeomLineSegment::getClassTypeId() && element==2) ? Sketcher_Element_Line_EndPoint : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==0) ? Sketcher_Element_Arc_Edge : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==1) ? Sketcher_Element_Arc_StartingPoint : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==2) ? Sketcher_Element_Arc_EndPoint : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==3) ? Sketcher_Element_Arc_MidPoint : - (type == Part::GeomCircle::getClassTypeId() && element==0) ? Sketcher_Element_Circle_Edge : - (type == Part::GeomCircle::getClassTypeId() && element==3) ? Sketcher_Element_Circle_MidPoint : + (type == Part::GeomPoint::getClassTypeId() && element==1) ? Sketcher_Element_Point_StartingPoint : + (type == Part::GeomLineSegment::getClassTypeId() && element==0) ? Sketcher_Element_Line_Edge : + (type == Part::GeomLineSegment::getClassTypeId() && element==1) ? Sketcher_Element_Line_StartingPoint : + (type == Part::GeomLineSegment::getClassTypeId() && element==2) ? Sketcher_Element_Line_EndPoint : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==0) ? Sketcher_Element_Arc_Edge : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==1) ? Sketcher_Element_Arc_StartingPoint : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==2) ? Sketcher_Element_Arc_EndPoint : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==3) ? Sketcher_Element_Arc_MidPoint : + (type == Part::GeomCircle::getClassTypeId() && element==0) ? Sketcher_Element_Circle_Edge : + (type == Part::GeomCircle::getClassTypeId() && element==3) ? Sketcher_Element_Circle_MidPoint : + (type == Part::GeomEllipse::getClassTypeId() && element==0) ? Sketcher_Element_Ellipse_Edge : + (type == Part::GeomEllipse::getClassTypeId() && element==3) ? Sketcher_Element_Ellipse_MidPoint : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfEllipse_Edge : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfEllipse_StartingPoint : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfEllipse_EndPoint : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfEllipse_MidPoint : none); } } diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 145aa11998..589897de39 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -28,6 +28,7 @@ # include # include # include +# include # include # include # include @@ -715,7 +716,9 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe const Part::Geometry *geo = getSketchObject()->getGeometry(edit->DragCurve); if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() || - geo->getTypeId() == Part::GeomCircle::getClassTypeId()) { + geo->getTypeId() == Part::GeomCircle::getClassTypeId() || + geo->getTypeId() == Part::GeomEllipse::getClassTypeId()|| + geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { // TODO: ellipse Gui::Command::openCommand("Drag Curve"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.movePoint(%i,%i,App.Vector(%f,%f,0),%i)" ,getObject()->getNameInDocument() @@ -912,8 +915,10 @@ void ViewProviderSketch::editDoubleClicked(void) // if its the right constraint if (Constr->Type == Sketcher::Distance || - Constr->Type == Sketcher::DistanceX || Constr->Type == Sketcher::DistanceY || - Constr->Type == Sketcher::Radius || Constr->Type == Sketcher::Angle) { + Constr->Type == Sketcher::DistanceX || + Constr->Type == Sketcher::DistanceY || + Constr->Type == Sketcher::Radius || + Constr->Type == Sketcher::Angle) { // Coin's SoIdleSensor causes problems on some platform while Qt seems to work properly (#0001517) EditDatumDialog *editDatumDialog = new EditDatumDialog(this, *it); @@ -1161,14 +1166,15 @@ void ViewProviderSketch::moveConstraint(int constNum, const Base::Vector2D &toPo p1 = arc->getCenter(); p2 = p1 + radius * Base::Vector3d(cos(angle),sin(angle),0.); } - else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) { + else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) { const Part::GeomCircle *circle = dynamic_cast(geo); double radius = circle->getRadius(); p1 = circle->getCenter(); Base::Vector3d tmpDir = Base::Vector3d(toPos.fX, toPos.fY, 0) - p1; double angle = atan2(tmpDir.y, tmpDir.x); p2 = p1 + radius * Base::Vector3d(cos(angle),sin(angle),0.); - } else + } + else return; } else return; @@ -1815,7 +1821,7 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & Gui::Selection().addSelection(doc->getName(), sketchObject->getNameInDocument(), ss.str().c_str()); } - } else if ((*it)->getTypeId() == Part::GeomCircle::getClassTypeId()) { + } else if ((*it)->getTypeId() == Part::GeomCircle::getClassTypeId()) { // ----- Check if circle lies inside box selection -----/ const Part::GeomCircle *circle = dynamic_cast(*it); pnt0 = circle->getCenter(); @@ -1850,6 +1856,50 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & } } + if (bpolyInside) { + ss.clear(); + ss.str(""); + ss << "Edge" << GeoId + 1; + Gui::Selection().addSelection(doc->getName(), sketchObject->getNameInDocument(),ss.str().c_str()); + } + } + } else if ((*it)->getTypeId() == Part::GeomEllipse::getClassTypeId()) { + // ----- Check if circle lies inside box selection -----/ + const Part::GeomEllipse *ellipse = dynamic_cast(*it); + pnt0 = ellipse->getCenter(); + VertexId += 1; + + Plm.multVec(pnt0, pnt0); + pnt0 = proj(pnt0); + + if (polygon.Contains(Base::Vector2D(pnt0.x, pnt0.y))) { + std::stringstream ss; + ss << "Vertex" << VertexId + 1; + Gui::Selection().addSelection(doc->getName(), sketchObject->getNameInDocument(), ss.str().c_str()); + + int countSegments = 12; + float segment = float(2 * M_PI) / countSegments; + + // circumscribed polygon radius + float a = float(ellipse->getMajorRadius()) / cos(segment/2); + float b = float(ellipse->getMinorRadius()) / cos(segment/2); + float phi = float(ellipse->getAngleXU()); + + bool bpolyInside = true; + pnt0 = ellipse->getCenter(); + float angle = 0.f; + for (int i = 0; i < countSegments; ++i, angle += segment) { + pnt = Base::Vector3d(pnt0.x + a * cos(angle) * cos(phi) - b * sin(angle) * sin(phi), + pnt0.y + a * cos(angle) * sin(phi) + b * sin(angle) * cos(phi), + 0.f); + Plm.multVec(pnt, pnt); + pnt = proj(pnt); + if (!polygon.Contains(Base::Vector2D(pnt.x, pnt.y))) { + bpolyInside = false; + break; + } + } + if (bpolyInside) { ss.clear(); ss.str(""); @@ -2082,7 +2132,7 @@ void ViewProviderSketch::updateColor(void) bool hasMaterial = false; SoMaterial *m; - if (!hasDatumLabel && type != Sketcher::Coincident) { + if (!hasDatumLabel && type != Sketcher::Coincident && type !=InternalAlignment) { hasMaterial = true; m = dynamic_cast(s->getChild(CONSTRAINT_SEPARATOR_INDEX_MATERIAL_OR_DATUMLABEL)); } @@ -2095,9 +2145,9 @@ void ViewProviderSketch::updateColor(void) m->diffuseColor = SelectColor; } else if (type == Sketcher::Coincident) { int index; - index = edit->ActSketch.getPointId(constraint->First, constraint->FirstPos) + 1; + index = edit->ActSketch.getVisiblePointId(constraint->First, constraint->FirstPos) + 1; if (index >= 0 && index < PtNum) pcolor[index] = SelectColor; - index = edit->ActSketch.getPointId(constraint->Second, constraint->SecondPos) + 1; + index = edit->ActSketch.getVisiblePointId(constraint->Second, constraint->SecondPos) + 1; if (index >= 0 && index < PtNum) pcolor[index] = SelectColor; } } else if (edit->PreselectConstraintSet.count(i)) { @@ -2735,6 +2785,25 @@ void ViewProviderSketch::draw(bool temp) edit->CurvIdToGeoId.push_back(GeoId); Points.push_back(center); } + else if ((*it)->getTypeId() == Part::GeomEllipse::getClassTypeId()) { // add an ellipse + const Part::GeomEllipse *ellipse = dynamic_cast(*it); + Handle_Geom_Ellipse curve = Handle_Geom_Ellipse::DownCast(ellipse->handle()); + + int countSegments = 50; + Base::Vector3d center = ellipse->getCenter(); + double segment = (2 * M_PI) / countSegments; + for (int i=0; i < countSegments; i++) { + gp_Pnt pnt = curve->Value(i*segment); + Coords.push_back(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z())); + } + + gp_Pnt pnt = curve->Value(0); + Coords.push_back(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z())); + + Index.push_back(countSegments+1); + edit->CurvIdToGeoId.push_back(GeoId); + Points.push_back(center); + } else if ((*it)->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { // add an arc const Part::GeomArcOfCircle *arc = dynamic_cast(*it); Handle_Geom_TrimmedCurve curve = Handle_Geom_TrimmedCurve::DownCast(arc->handle()); @@ -2768,6 +2837,39 @@ void ViewProviderSketch::draw(bool temp) Points.push_back(end); Points.push_back(center); } + else if ((*it)->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { // add an arc + const Part::GeomArcOfEllipse *arc = dynamic_cast(*it); + Handle_Geom_TrimmedCurve curve = Handle_Geom_TrimmedCurve::DownCast(arc->handle()); + + double startangle, endangle; + arc->getRange(startangle, endangle); + if (startangle > endangle) // if arc is reversed + std::swap(startangle, endangle); + + double range = endangle-startangle; + int countSegments = std::max(6, int(50.0 * range / (2 * M_PI))); + double segment = range / countSegments; + + Base::Vector3d center = arc->getCenter(); + Base::Vector3d start = arc->getStartPoint(); + Base::Vector3d end = arc->getEndPoint(); + + for (int i=0; i < countSegments; i++) { + gp_Pnt pnt = curve->Value(startangle); + Coords.push_back(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z())); + startangle += segment; + } + + // end point + gp_Pnt pnt = curve->Value(endangle); + Coords.push_back(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z())); + + Index.push_back(countSegments+1); + edit->CurvIdToGeoId.push_back(GeoId); + Points.push_back(start); + Points.push_back(end); + Points.push_back(center); + } else if ((*it)->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { // add a bspline const Part::GeomBSplineCurve *spline = dynamic_cast(*it); Handle_Geom_BSplineCurve curve = Handle_Geom_BSplineCurve::DownCast(spline->handle()); @@ -2875,7 +2977,8 @@ Restart: // root separator for this constraint SoSeparator *sep = dynamic_cast(edit->constrGroup->getChild(i)); const Constraint *Constr = *it; - + + bool major_radius = false; // this is checked in the radius to reuse code // distinquish different constraint types to build up switch (Constr->Type) { case Horizontal: // write the new position of the Horizontal constraint Same as vertical position. @@ -2929,7 +3032,7 @@ Restart: norm1 = Base::Vector3d(cos(midangle),sin(midangle),0); dir1 = Base::Vector3d(-norm1.y,norm1.x,0); midpos1 = arc->getCenter() + arc->getRadius() * norm1; - } else if (geo1->getTypeId() == Part::GeomCircle::getClassTypeId()) { + } else if (geo1->getTypeId() == Part::GeomCircle::getClassTypeId()) { // TODO: ellipse const Part::GeomCircle *circle = dynamic_cast(geo1); norm1 = Base::Vector3d(cos(M_PI/4),sin(M_PI/4),0); dir1 = Base::Vector3d(-norm1.y,norm1.x,0); @@ -2950,7 +3053,7 @@ Restart: norm2 = Base::Vector3d(cos(midangle),sin(midangle),0); dir2 = Base::Vector3d(-norm2.y,norm2.x,0); midpos2 = arc->getCenter() + arc->getRadius() * norm2; - } else if (geo2->getTypeId() == Part::GeomCircle::getClassTypeId()) { + } else if (geo2->getTypeId() == Part::GeomCircle::getClassTypeId()) { // TODO: ellipse const Part::GeomCircle *circle = dynamic_cast(geo2); norm2 = Base::Vector3d(cos(M_PI/4),sin(M_PI/4),0); dir2 = Base::Vector3d(-norm2.y,norm2.x,0); @@ -2996,7 +3099,7 @@ Restart: geo2->getTypeId() != Part::GeomLineSegment::getClassTypeId()) { if (Constr->Type == Equal) { double r1,r2,angle1,angle2; - if (geo1->getTypeId() == Part::GeomCircle::getClassTypeId()) { + if (geo1->getTypeId() == Part::GeomCircle::getClassTypeId()) { // TODO: ellipse const Part::GeomCircle *circle = dynamic_cast(geo1); r1 = circle->getRadius(); angle1 = M_PI/4; @@ -3008,10 +3111,16 @@ Restart: arc->getRange(startangle, endangle); angle1 = (startangle + endangle)/2; midpos1 = arc->getCenter(); + } else if (geo1->getTypeId() == Part::GeomEllipse::getClassTypeId()) { + // TODO: ellipse + const Part::GeomEllipse *ellipse = dynamic_cast(geo1); + r1 = ellipse->getMajorRadius(); + angle1 = -ellipse->getAngleXU(); + midpos1 = ellipse->getCenter(); } else break; - if (geo2->getTypeId() == Part::GeomCircle::getClassTypeId()) { + if (geo2->getTypeId() == Part::GeomCircle::getClassTypeId()) { // TODO: ellipse const Part::GeomCircle *circle = dynamic_cast(geo2); r2 = circle->getRadius(); angle2 = M_PI/4; @@ -3023,7 +3132,14 @@ Restart: arc->getRange(startangle, endangle); angle2 = (startangle + endangle)/2; midpos2 = arc->getCenter(); - } else + } else if (geo2->getTypeId() == Part::GeomEllipse::getClassTypeId()) { + // TODO: ellipse + const Part::GeomEllipse *ellipse = dynamic_cast(geo2); + r2 = ellipse->getMajorRadius(); + angle2 = -ellipse->getAngleXU(); + midpos2 = ellipse->getCenter(); + } + else break; norm1 = Base::Vector3d(cos(angle1),sin(angle1),0); @@ -3196,7 +3312,7 @@ Restart: const Part::GeomLineSegment *lineSeg = dynamic_cast(geo1); Base::Vector3d dir = (lineSeg->getEndPoint() - lineSeg->getStartPoint()).Normalize(); Base::Vector3d norm(-dir.y, dir.x, 0); - if (geo2->getTypeId()== Part::GeomCircle::getClassTypeId()) { + if (geo2->getTypeId()== Part::GeomCircle::getClassTypeId()) { // TODO: ellipse const Part::GeomCircle *circle = dynamic_cast(geo2); // tangency between a line and a circle float length = (circle->getCenter() - lineSeg->getStartPoint())*dir; @@ -3204,6 +3320,24 @@ Restart: pos = lineSeg->getStartPoint() + dir * length; relPos = norm * 1; //TODO Huh? } + else if (geo2->getTypeId()== Part::GeomEllipse::getClassTypeId() || + geo2->getTypeId()== Part::GeomArcOfEllipse::getClassTypeId()) { // TODO: ellipse + + Base::Vector3d center; + if(geo2->getTypeId()== Part::GeomEllipse::getClassTypeId()){ + const Part::GeomEllipse *ellipse = dynamic_cast(geo2); + center=ellipse->getCenter(); + } else { + const Part::GeomArcOfEllipse *aoc = dynamic_cast(geo2); + center=aoc->getCenter(); + } + + // tangency between a line and an ellipse + float length = (center - lineSeg->getStartPoint())*dir; + + pos = lineSeg->getStartPoint() + dir * length; + relPos = norm * 1; + } else if (geo2->getTypeId()== Part::GeomArcOfCircle::getClassTypeId()) { const Part::GeomArcOfCircle *arc = dynamic_cast(geo2); // tangency between a line and an arc @@ -3214,7 +3348,7 @@ Restart: } } - if (geo1->getTypeId()== Part::GeomCircle::getClassTypeId() && + if (geo1->getTypeId()== Part::GeomCircle::getClassTypeId() && // TODO: ellipse geo2->getTypeId()== Part::GeomCircle::getClassTypeId()) { const Part::GeomCircle *circle1 = dynamic_cast(geo1); const Part::GeomCircle *circle2 = dynamic_cast(geo2); @@ -3223,12 +3357,12 @@ Restart: pos = circle1->getCenter() + dir * circle1->getRadius(); relPos = dir * 1; } - else if (geo2->getTypeId()== Part::GeomCircle::getClassTypeId()) { + else if (geo2->getTypeId()== Part::GeomCircle::getClassTypeId()) { // TODO: ellipse std::swap(geo1,geo2); } if (geo1->getTypeId()== Part::GeomCircle::getClassTypeId() && - geo2->getTypeId()== Part::GeomArcOfCircle::getClassTypeId()) { + geo2->getTypeId()== Part::GeomArcOfCircle::getClassTypeId()) { // TODO: ellipse const Part::GeomCircle *circle = dynamic_cast(geo1); const Part::GeomArcOfCircle *arc = dynamic_cast(geo2); // tangency between a circle and an arc @@ -3368,7 +3502,7 @@ Restart: asciiText->pnts.finishEditing(); } - break; + break; case Radius: { assert(Constr->First >= -extGeoCount && Constr->First < intGeoCount); @@ -3386,13 +3520,14 @@ Restart: pnt1 = arc->getCenter(); pnt2 = pnt1 + radius * Base::Vector3d(cos(angle),sin(angle),0.); } - else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) { + else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) { const Part::GeomCircle *circle = dynamic_cast(geo); double radius = circle->getRadius(); double angle = (double) Constr->LabelPosition; pnt1 = circle->getCenter(); pnt2 = pnt1 + radius * Base::Vector3d(cos(angle),sin(angle),0.); - } else + } + else break; } else break; @@ -3584,6 +3719,12 @@ void ViewProviderSketch::rebuildConstraintsVisual(void) edit->vConstrType.push_back((*it)->Type); } break; + case InternalAlignment: + { + // TODO: Implement visual representation (if any) + edit->vConstrType.push_back((*it)->Type); + } + break; default: edit->vConstrType.push_back(None); } diff --git a/src/Mod/Sketcher/Gui/Workbench.cpp b/src/Mod/Sketcher/Gui/Workbench.cpp index c0cd8c3c0e..b49d10be64 100644 --- a/src/Mod/Sketcher/Gui/Workbench.cpp +++ b/src/Mod/Sketcher/Gui/Workbench.cpp @@ -136,12 +136,16 @@ inline void SketcherAddWorkspaceArcs(Gui::MenuItem& geom){ geom << "Sketcher_CreateArc" << "Sketcher_Create3PointArc" << "Sketcher_CreateCircle" - << "Sketcher_Create3PointCircle"; + << "Sketcher_Create3PointCircle" + << "Sketcher_CreateEllipse" + << "Sketcher_CreateArcOfEllipse"; } template <> inline void SketcherAddWorkspaceArcs(Gui::ToolBarItem& geom){ geom << "Sketcher_CompCreateArc" - << "Sketcher_CompCreateCircle"; + << "Sketcher_CompCreateCircle" + << "Sketcher_CreateEllipse" + << "Sketcher_CreateArcOfEllipse"; } template void SketcherAddWorkspaceRegularPolygon(T& geom); @@ -177,9 +181,32 @@ inline void SketcherAddWorkbenchGeometries(T& geom){ /*<< "Sketcher_CreateDraftLine"*/; } - template -inline void SketcherAddWorkbenchConstraints(T& cons){ +inline void SketcherAddWorkbenchConstraints(T& cons); + +template <> +inline void SketcherAddWorkbenchConstraints(Gui::MenuItem& cons){ + cons << "Sketcher_ConstrainCoincident" + << "Sketcher_ConstrainPointOnObject" + << "Sketcher_ConstrainVertical" + << "Sketcher_ConstrainHorizontal" + << "Sketcher_ConstrainParallel" + << "Sketcher_ConstrainPerpendicular" + << "Sketcher_ConstrainTangent" + << "Sketcher_ConstrainEqual" + << "Sketcher_ConstrainSymmetric" + << "Separator" + << "Sketcher_ConstrainLock" + << "Sketcher_ConstrainDistanceX" + << "Sketcher_ConstrainDistanceY" + << "Sketcher_ConstrainDistance" + << "Sketcher_ConstrainRadius" + << "Sketcher_ConstrainAngle" + << "Sketcher_ConstrainInternalAlignment"; +} + +template <> +inline void SketcherAddWorkbenchConstraints(Gui::ToolBarItem& cons){ cons << "Sketcher_ConstrainCoincident" << "Sketcher_ConstrainPointOnObject" << "Sketcher_ConstrainVertical" @@ -196,7 +223,6 @@ inline void SketcherAddWorkbenchConstraints(T& cons){ << "Sketcher_ConstrainDistance" << "Sketcher_ConstrainRadius" << "Sketcher_ConstrainAngle"; - } template @@ -212,13 +238,15 @@ inline void SketcherAddWorkbenchTools(Gui::MenuItem& consaccel){ << "Sketcher_SelectHorizontalAxis" << "Sketcher_SelectRedundantConstraints" << "Sketcher_SelectConflictingConstraints" - << "Sketcher_SelectElementsAssociatedWithConstraints"; + << "Sketcher_SelectElementsAssociatedWithConstraints" + << "Sketcher_RestoreInternalAlignmentGeometry"; } template <> inline void SketcherAddWorkbenchTools(Gui::ToolBarItem& consaccel){ consaccel << "Sketcher_CloseShape" << "Sketcher_ConnectLines" - << "Sketcher_SelectConstraints"; + << "Sketcher_SelectConstraints" + << "Sketcher_RestoreInternalAlignmentGeometry"; } template