From afcaa8b9801e8f91488c39c9da5e97d881bd0839 Mon Sep 17 00:00:00 2001 From: logari81 Date: Thu, 29 Nov 2012 22:46:11 +0100 Subject: [PATCH] Sketcher: Implement symmetry with respect to a point constraint, aka midpoint constraint --- src/Mod/Sketcher/App/ConstraintPyImp.cpp | 17 ++++- src/Mod/Sketcher/App/Sketch.cpp | 33 +++++++- src/Mod/Sketcher/App/Sketch.h | 2 + src/Mod/Sketcher/App/freegcs/Constraints.cpp | 80 ++++++++++++++++++++ src/Mod/Sketcher/App/freegcs/Constraints.h | 31 ++++++-- src/Mod/Sketcher/App/freegcs/GCS.cpp | 27 +++++++ src/Mod/Sketcher/App/freegcs/GCS.h | 4 + src/Mod/Sketcher/Gui/CommandConstraints.cpp | 46 +++++++---- 8 files changed, 217 insertions(+), 23 deletions(-) diff --git a/src/Mod/Sketcher/App/ConstraintPyImp.cpp b/src/Mod/Sketcher/App/ConstraintPyImp.cpp index 3a9ee1782..d3148209e 100644 --- a/src/Mod/Sketcher/App/ConstraintPyImp.cpp +++ b/src/Mod/Sketcher/App/ConstraintPyImp.cpp @@ -51,7 +51,7 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/) int SecondIndex= Constraint::GeoUndef; int SecondPos = none; int ThirdIndex = Constraint::GeoUndef; - //int ThirdPos = none; + int ThirdPos = none; double Value = 0; // Note: In Python 2.x PyArg_ParseTuple prints a warning if a float is given but an integer is expected. // This means we must use a PyObject and check afterwards if it's a float or integer. @@ -292,6 +292,21 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/) } } } + PyErr_Clear(); + + if (PyArg_ParseTuple(args, "siiiiii", &ConstraintType, &FirstIndex, &FirstPos, &SecondIndex, &SecondPos, &ThirdIndex, &ThirdPos)) { + // ConstraintType, GeoIndex1, PosIndex1, GeoIndex2, PosIndex2, GeoIndex3, PosIndex3 + if (strcmp("Symmetric",ConstraintType) == 0 ) { + this->getConstraintPtr()->Type = Symmetric; + this->getConstraintPtr()->First = FirstIndex; + this->getConstraintPtr()->FirstPos = (Sketcher::PointPos) FirstPos; + this->getConstraintPtr()->Second = SecondIndex; + this->getConstraintPtr()->SecondPos = (Sketcher::PointPos) SecondPos; + this->getConstraintPtr()->Third = ThirdIndex; + this->getConstraintPtr()->ThirdPos = (Sketcher::PointPos) ThirdPos; + return 0; + } + } PyErr_SetString(PyExc_TypeError, "Constraint constructor accepts:\n" "-- empty parameter list\n" diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 1e85fc9e1..7ed811a76 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -537,8 +537,13 @@ int Sketch::addConstraint(const Constraint *constraint) rtn = addEqualConstraint(constraint->First,constraint->Second); break; case Symmetric: - rtn = addSymmetricConstraint(constraint->First,constraint->FirstPos, - constraint->Second,constraint->SecondPos,constraint->Third); + if (constraint->ThirdPos != none) + rtn = addSymmetricConstraint(constraint->First,constraint->FirstPos, + constraint->Second,constraint->SecondPos, + constraint->Third,constraint->ThirdPos); + else + rtn = addSymmetricConstraint(constraint->First,constraint->FirstPos, + constraint->Second,constraint->SecondPos,constraint->Third); break; case None: break; @@ -1522,6 +1527,30 @@ int Sketch::addSymmetricConstraint(int geoId1, PointPos pos1, int geoId2, PointP return -1; } +int Sketch::addSymmetricConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, + int geoId3, PointPos pos3) +{ + geoId1 = checkGeoId(geoId1); + geoId2 = checkGeoId(geoId2); + geoId3 = checkGeoId(geoId3); + + int pointId1 = getPointId(geoId1, pos1); + int pointId2 = getPointId(geoId2, pos2); + int pointId3 = getPointId(geoId3, pos3); + + if (pointId1 >= 0 && pointId1 < int(Points.size()) && + pointId2 >= 0 && pointId2 < int(Points.size()) && + pointId3 >= 0 && pointId3 < int(Points.size())) { + GCS::Point &p1 = Points[pointId1]; + GCS::Point &p2 = Points[pointId2]; + GCS::Point &p = Points[pointId3]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintP2PSymmetric(p1, p2, p, tag); + return ConstraintsCounter; + } + return -1; +} + bool Sketch::updateGeometry() { int i=0; diff --git a/src/Mod/Sketcher/App/Sketch.h b/src/Mod/Sketcher/App/Sketch.h index ea403d9f1..a5c3e6f19 100644 --- a/src/Mod/Sketcher/App/Sketch.h +++ b/src/Mod/Sketcher/App/Sketch.h @@ -172,6 +172,8 @@ public: int addPointOnObjectConstraint(int geoId1, PointPos pos1, int geoId2); /// add a symmetric constraint between two points with respect to a line int addSymmetricConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, int geoId3); + /// 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); //@} enum GeoType { diff --git a/src/Mod/Sketcher/App/freegcs/Constraints.cpp b/src/Mod/Sketcher/App/freegcs/Constraints.cpp index 76b42f8d7..97e992ca7 100644 --- a/src/Mod/Sketcher/App/freegcs/Constraints.cpp +++ b/src/Mod/Sketcher/App/freegcs/Constraints.cpp @@ -413,6 +413,18 @@ ConstraintPointOnLine::ConstraintPointOnLine(Point &p, Line &l) rescale(); } +ConstraintPointOnLine::ConstraintPointOnLine(Point &p, Point &lp1, Point &lp2) +{ + pvec.push_back(p.x); + pvec.push_back(p.y); + pvec.push_back(lp1.x); + pvec.push_back(lp1.y); + pvec.push_back(lp2.x); + pvec.push_back(lp2.y); + origpvec = pvec; + rescale(); +} + ConstraintType ConstraintPointOnLine::getTypeId() { return PointOnLine; @@ -460,6 +472,74 @@ double ConstraintPointOnLine::grad(double *param) return scale * deriv; } +// PointOnPerpBisector +ConstraintPointOnPerpBisector::ConstraintPointOnPerpBisector(Point &p, Line &l) +{ + pvec.push_back(p.x); + pvec.push_back(p.y); + pvec.push_back(l.p1.x); + pvec.push_back(l.p1.y); + pvec.push_back(l.p2.x); + pvec.push_back(l.p2.y); + origpvec = pvec; + rescale(); +} + +ConstraintPointOnPerpBisector::ConstraintPointOnPerpBisector(Point &p, Point &lp1, Point &lp2) +{ + pvec.push_back(p.x); + pvec.push_back(p.y); + pvec.push_back(lp1.x); + pvec.push_back(lp1.y); + pvec.push_back(lp2.x); + pvec.push_back(lp2.y); + origpvec = pvec; + rescale(); +} + +ConstraintType ConstraintPointOnPerpBisector::getTypeId() +{ + return PointOnPerpBisector; +} + +void ConstraintPointOnPerpBisector::rescale(double coef) +{ + scale = coef; +} + +double ConstraintPointOnPerpBisector::error() +{ + double dx1 = *p1x() - *p0x(); + double dy1 = *p1y() - *p0y(); + double dx2 = *p2x() - *p0x(); + double dy2 = *p2y() - *p0y(); + return scale * (sqrt(dx1*dx1+dy1*dy1) - sqrt(dx2*dx2+dy2*dy2)); +} + +double ConstraintPointOnPerpBisector::grad(double *param) +{ + double deriv=0.; + if (param == p0x() || param == p0y() || + param == p1x() || param == p1y()) { + double dx1 = *p1x() - *p0x(); + double dy1 = *p1y() - *p0y(); + if (param == p0x()) deriv -= dx1/sqrt(dx1*dx1+dy1*dy1); + if (param == p0y()) deriv -= dy1/sqrt(dx1*dx1+dy1*dy1); + if (param == p1x()) deriv += dx1/sqrt(dx1*dx1+dy1*dy1); + if (param == p1y()) deriv += dy1/sqrt(dx1*dx1+dy1*dy1); + } + if (param == p0x() || param == p0y() || + param == p2x() || param == p2y()) { + double dx2 = *p2x() - *p0x(); + double dy2 = *p2y() - *p0y(); + if (param == p0x()) deriv += dx2/sqrt(dx2*dx2+dy2*dy2); + if (param == p0y()) deriv += dy2/sqrt(dx2*dx2+dy2*dy2); + if (param == p2x()) deriv -= dx2/sqrt(dx2*dx2+dy2*dy2); + if (param == p2y()) deriv -= dy2/sqrt(dx2*dx2+dy2*dy2); + } + return scale * deriv; +} + // Parallel ConstraintParallel::ConstraintParallel(Line &l1, Line &l2) { diff --git a/src/Mod/Sketcher/App/freegcs/Constraints.h b/src/Mod/Sketcher/App/freegcs/Constraints.h index 17abd3106..034411bad 100644 --- a/src/Mod/Sketcher/App/freegcs/Constraints.h +++ b/src/Mod/Sketcher/App/freegcs/Constraints.h @@ -41,11 +41,12 @@ namespace GCS P2PAngle = 4, P2LDistance = 5, PointOnLine = 6, - Parallel = 7, - Perpendicular = 8, - L2LAngle = 9, - MidpointOnLine = 10, - TangentCircumf = 11 + PointOnPerpBisector = 7, + Parallel = 8, + Perpendicular = 9, + L2LAngle = 10, + MidpointOnLine = 11, + TangentCircumf = 12 }; class Constraint @@ -171,6 +172,26 @@ namespace GCS inline double* p2y() { return pvec[5]; } public: ConstraintPointOnLine(Point &p, Line &l); + ConstraintPointOnLine(Point &p, Point &lp1, Point &lp2); + virtual ConstraintType getTypeId(); + virtual void rescale(double coef=1.); + virtual double error(); + virtual double grad(double *); + }; + + // PointOnPerpBisector + class ConstraintPointOnPerpBisector : public Constraint + { + private: + inline double* p0x() { return pvec[0]; } + inline double* p0y() { return pvec[1]; } + inline double* p1x() { return pvec[2]; } + inline double* p1y() { return pvec[3]; } + inline double* p2x() { return pvec[4]; } + inline double* p2y() { return pvec[5]; } + public: + ConstraintPointOnPerpBisector(Point &p, Line &l); + ConstraintPointOnPerpBisector(Point &p, Point &lp1, Point &lp2); virtual ConstraintType getTypeId(); virtual void rescale(double coef=1.); virtual double error(); diff --git a/src/Mod/Sketcher/App/freegcs/GCS.cpp b/src/Mod/Sketcher/App/freegcs/GCS.cpp index ffab4c579..5babc2786 100644 --- a/src/Mod/Sketcher/App/freegcs/GCS.cpp +++ b/src/Mod/Sketcher/App/freegcs/GCS.cpp @@ -250,6 +250,27 @@ int System::addConstraintPointOnLine(Point &p, Line &l, int tagId) return addConstraint(constr); } +int System::addConstraintPointOnLine(Point &p, Point &lp1, Point &lp2, int tagId) +{ + Constraint *constr = new ConstraintPointOnLine(p, lp1, lp2); + constr->setTag(tagId); + return addConstraint(constr); +} + +int System::addConstraintPointOnPerpBisector(Point &p, Line &l, int tagId) +{ + Constraint *constr = new ConstraintPointOnPerpBisector(p, l); + constr->setTag(tagId); + return addConstraint(constr); +} + +int System::addConstraintPointOnPerpBisector(Point &p, Point &lp1, Point &lp2, int tagId) +{ + Constraint *constr = new ConstraintPointOnPerpBisector(p, lp1, lp2); + constr->setTag(tagId); + return addConstraint(constr); +} + int System::addConstraintParallel(Line &l1, Line &l2, int tagId) { Constraint *constr = new ConstraintParallel(l1, l2); @@ -552,6 +573,12 @@ int System::addConstraintP2PSymmetric(Point &p1, Point &p2, Line &l, int tagId) return addConstraintMidpointOnLine(p1, p2, l.p1, l.p2, tagId); } +int System::addConstraintP2PSymmetric(Point &p1, Point &p2, Point &p, int tagId) +{ + addConstraintPointOnPerpBisector(p, p1, p2, tagId); + return addConstraintPointOnLine(p, p1, p2, tagId); +} + void System::rescaleConstraint(int id, double coeff) { if (id >= clist.size() || id < 0) diff --git a/src/Mod/Sketcher/App/freegcs/GCS.h b/src/Mod/Sketcher/App/freegcs/GCS.h index f0d87906f..f592b92ea 100644 --- a/src/Mod/Sketcher/App/freegcs/GCS.h +++ b/src/Mod/Sketcher/App/freegcs/GCS.h @@ -99,6 +99,9 @@ namespace GCS int addConstraintP2PAngle(Point &p1, Point &p2, double *angle, int tagId=0); int addConstraintP2LDistance(Point &p, Line &l, double *distance, int tagId=0); int addConstraintPointOnLine(Point &p, Line &l, int tagId=0); + int addConstraintPointOnLine(Point &p, Point &lp1, Point &lp2, int tagId=0); + int addConstraintPointOnPerpBisector(Point &p, Line &l, int tagId=0); + int addConstraintPointOnPerpBisector(Point &p, Point &lp1, Point &lp2, int tagId=0); int addConstraintParallel(Line &l1, Line &l2, int tagId=0); int addConstraintPerpendicular(Line &l1, Line &l2, int tagId=0); int addConstraintPerpendicular(Point &l1p1, Point &l1p2, @@ -151,6 +154,7 @@ namespace GCS 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); void rescaleConstraint(int id, double coeff); void declareUnknowns(VEC_pD ¶ms); diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index f469b0801..2fe005604 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -1835,29 +1835,45 @@ void CmdSketcherConstrainSymmetric::activated(int iMsg) std::swap(PosId2,PosId3); } + if ((GeoId1 < 0 && GeoId2 < 0 && GeoId3 < 0)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Cannot add a constraint between external geometries!")); + return; + } + if (isVertex(GeoId1,PosId1) && - isVertex(GeoId2,PosId2) && - isEdge(GeoId3,PosId3)) { + isVertex(GeoId2,PosId2)) { - if ((GeoId1 < 0 && GeoId2 < 0) || (GeoId1 < 0 && GeoId3 < 0) || (GeoId2 < 0 && GeoId3 < 0)) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Cannot add a constraint between external geometries!")); - return; - } + if (isEdge(GeoId3,PosId3)) { + const Part::Geometry *geom = Obj->getGeometry(GeoId3); + if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { + if (GeoId1 == GeoId2 && GeoId2 == GeoId3) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Cannot add a symmetry constraint between a line and its end points!")); + return; + } - const Part::Geometry *geom = Obj->getGeometry(GeoId3); - if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { - if (GeoId1 == GeoId2 && GeoId2 == GeoId3) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Cannot add a symmetry constraint between a line and its end points!")); + // undo command open + openCommand("add symmetric constraint"); + Gui::Command::doCommand( + Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Symmetric',%d,%d,%d,%d,%d)) ", + selection[0].getFeatName(),GeoId1,PosId1,GeoId2,PosId2,GeoId3); + + // finish the transaction and update + commitCommand(); + updateActive(); + + // clear the selection (convenience) + getSelection().clearSelection(); return; } - + } + else if (isVertex(GeoId3,PosId3)) { // undo command open openCommand("add symmetric constraint"); Gui::Command::doCommand( - Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Symmetric',%d,%d,%d,%d,%d)) ", - selection[0].getFeatName(),GeoId1,PosId1,GeoId2,PosId2,GeoId3); + Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Symmetric',%d,%d,%d,%d,%d,%d)) ", + selection[0].getFeatName(),GeoId1,PosId1,GeoId2,PosId2,GeoId3,PosId3); // finish the transaction and update commitCommand();