diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index bf68f40fae..fd29941145 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -2162,7 +2162,7 @@ int Sketch::addConstraint(const Constraint* constraint) c.driving); } } - else { // line length + else { // line length, arc length c.value = new double(constraint->getValue()); if (c.driving) { FixParameters.push_back(c.value); @@ -3288,19 +3288,23 @@ int Sketch::addAngleAtPointConstraint(int geoId1, return ConstraintsCounter; } -// line length constraint +// line length and arc length constraint int Sketch::addDistanceConstraint(int geoId, double* value, bool driving) { geoId = checkGeoId(geoId); - if (Geoms[geoId].type != Line) { + int tag = ++ConstraintsCounter; + if (Geoms[geoId].type == Line) { + GCS::Line& l = Lines[Geoms[geoId].index]; + GCSsys.addConstraintP2PDistance(l.p1, l.p2, value, tag, driving); + } + else if (Geoms[geoId].type == Arc) { + GCS::Arc& a = Arcs[Geoms[geoId].index]; + GCSsys.addConstraintArcLength(a, value, tag, driving); + } + else { return -1; } - - GCS::Line& l = Lines[Geoms[geoId].index]; - - int tag = ++ConstraintsCounter; - GCSsys.addConstraintP2PDistance(l.p1, l.p2, value, tag, driving); return ConstraintsCounter; } diff --git a/src/Mod/Sketcher/App/planegcs/Constraints.cpp b/src/Mod/Sketcher/App/planegcs/Constraints.cpp index 5a66be5bee..4fe4e64a58 100644 --- a/src/Mod/Sketcher/App/planegcs/Constraints.cpp +++ b/src/Mod/Sketcher/App/planegcs/Constraints.cpp @@ -24,6 +24,8 @@ #pragma warning(disable : 4251) #endif +#include + #include #define DEBUG_DERIVS 0 #if DEBUG_DERIVS @@ -3491,4 +3493,90 @@ double ConstraintP2CDistance::grad(double* param) return deriv * scale; } +// -------------------------------------------------------- +// ConstraintArcLength +ConstraintArcLength::ConstraintArcLength(Arc& a, double* d) +{ + this->d = d; + pvec.push_back(d); + + this->arc = a; + this->arc.PushOwnParams(pvec); + + origpvec = pvec; + pvecChangedFlag = true; + rescale(); +} + +void ConstraintArcLength::ReconstructGeomPointers() +{ + int i = 0; + i++; // skip the first parameter as there is the inline function distance for it + arc.ReconstructOnNewPvec(pvec, i); + pvecChangedFlag = false; +} + +ConstraintType ConstraintArcLength::getTypeId() +{ + return ArcLength; +} + +void ConstraintArcLength::rescale(double coef) +{ + scale = coef; +} + +void ConstraintArcLength::errorgrad(double* err, double* grad, double* param) +{ + if (pvecChangedFlag) { + ReconstructGeomPointers(); + } + + double rad = *arc.rad; + double endA = *arc.endAngle; + double startA = *arc.startAngle; + // Assume positive angles and CCW arc + while (startA < 0.) { + startA += 2. * M_PI; + } + while (endA < startA) { + endA += 2. * M_PI; + } + if (err) { + *err = rad * (endA - startA) - *distance(); + } + else if (grad) { + if (param == distance()) { + // if constraint is not driving it varies on distance(). + *grad = -1.; + } + else { + double dRad = param == arc.rad ? 1. : 0.; + double dStartA = param == arc.startAngle ? 1. : 0.; + double dEndA = param == arc.endAngle ? 1. : 0.; + *grad = rad * (dEndA - dStartA) + dRad * (endA - startA); + } + } +} + +double ConstraintArcLength::error() +{ + double err; + errorgrad(&err, nullptr, nullptr); + return scale * err; +} + +double ConstraintArcLength::grad(double* param) +{ + if (findParamInPvec(param) == -1) { + return 0.0; + } + + double deriv; + errorgrad(nullptr, &deriv, param); + + return deriv * scale; +} + + } // namespace GCS diff --git a/src/Mod/Sketcher/App/planegcs/Constraints.h b/src/Mod/Sketcher/App/planegcs/Constraints.h index 017165ca6f..04c2003d5e 100644 --- a/src/Mod/Sketcher/App/planegcs/Constraints.h +++ b/src/Mod/Sketcher/App/planegcs/Constraints.h @@ -81,7 +81,8 @@ enum ConstraintType P2CDistance = 32, AngleViaPointAndParam = 33, AngleViaPointAndTwoParams = 34, - AngleViaTwoPoints = 35 + AngleViaTwoPoints = 35, + ArcLength = 36, }; enum InternalAlignmentType @@ -1385,6 +1386,28 @@ public: double grad(double*) override; }; +// ArcLength +class ConstraintArcLength: public Constraint +{ +private: + Arc arc; + double* d; + inline double* distance() + { + return pvec[0]; + } + void ReconstructGeomPointers(); // writes pointers in pvec to the parameters of a + void + errorgrad(double* err, + double* grad, + double* param); // error and gradient combined. Values are returned through pointers. +public: + ConstraintArcLength(Arc& a, double* d); + ConstraintType getTypeId() override; + void rescale(double coef = 1.) override; + double error() override; + double grad(double*) override; +}; } // namespace GCS diff --git a/src/Mod/Sketcher/App/planegcs/GCS.cpp b/src/Mod/Sketcher/App/planegcs/GCS.cpp index cb87fc5892..036894b8be 100644 --- a/src/Mod/Sketcher/App/planegcs/GCS.cpp +++ b/src/Mod/Sketcher/App/planegcs/GCS.cpp @@ -889,6 +889,15 @@ int System::addConstraintP2CDistance(Point& p, Circle& c, double* distance, int return addConstraint(constr); } +int System::addConstraintArcLength(Arc& a, double* distance, int tagId, bool driving) +{ + Constraint* constr = new ConstraintArcLength(a, distance); + constr->setTag(tagId); + constr->setDriving(driving); + return addConstraint(constr); +} + + // derived constraints int System::addConstraintP2PCoincident(Point& p1, Point& p2, int tagId, bool driving) diff --git a/src/Mod/Sketcher/App/planegcs/GCS.h b/src/Mod/Sketcher/App/planegcs/GCS.h index 5d941a9f91..6b0b12da05 100644 --- a/src/Mod/Sketcher/App/planegcs/GCS.h +++ b/src/Mod/Sketcher/App/planegcs/GCS.h @@ -462,6 +462,7 @@ public: double* distance, int tagId = 0, bool driving = true); + int addConstraintArcLength(Arc& a, double* dist, int tagId, bool driving = true); // internal alignment constraints int addConstraintInternalAlignmentPoint2Ellipse(Ellipse& e, diff --git a/src/Mod/Sketcher/App/planegcs/Geo.h b/src/Mod/Sketcher/App/planegcs/Geo.h index b021ef2e84..4604c55b26 100644 --- a/src/Mod/Sketcher/App/planegcs/Geo.h +++ b/src/Mod/Sketcher/App/planegcs/Geo.h @@ -243,6 +243,7 @@ public: double* startAngle; double* endAngle; // double *rad; //inherited + // start and end points are computed by an ArcRules constraint Point start; Point end; // Point center; //inherited diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 8371a57744..eb42689663 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -4615,6 +4615,33 @@ void CmdSketcherConstrainDistance::activated(int iMsg) finishDatumConstraint(this, Obj, true); } + return; + } + else if (isArcOfCircle(*geom)) { + auto arc = static_cast(geom); + double ActLength = arc->getAngle(false) * arc->getRadius(); + + openCommand(QT_TRANSLATE_NOOP("Command", "Add length constraint")); + Gui::cmdAppObjectArgs(selection[0].getObject(), + "addConstraint(Sketcher.Constraint('Distance',%d,%f))", + GeoId1, + ActLength); + + // it is a constraint on a external line, make it non-driving + if (arebothpointsorsegmentsfixed || GeoId1 <= Sketcher::GeoEnum::RefExt + || constraintCreationMode == Reference) { + const std::vector& ConStr = Obj->Constraints.getValues(); + + Gui::cmdAppObjectArgs(selection[0].getObject(), + "setDriving(%d,%s)", + ConStr.size() - 1, + "False"); + finishDatumConstraint(this, Obj, false); + } + else { + finishDatumConstraint(this, Obj, true); + } + return; } }