From 7a2fa1dce89ccaff686d044d13460785c546b8e6 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 28 May 2024 12:26:23 +0200 Subject: [PATCH 1/9] Sketch: Refactor SketchAnalysis Move helper classes to anonymous namespace --- src/Mod/Sketcher/App/SketchAnalysis.cpp | 25 ++++++++++++++----------- src/Mod/Sketcher/App/SketchAnalysis.h | 7 ------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchAnalysis.cpp b/src/Mod/Sketcher/App/SketchAnalysis.cpp index 513dd89168..0a5c380fcc 100644 --- a/src/Mod/Sketcher/App/SketchAnalysis.cpp +++ b/src/Mod/Sketcher/App/SketchAnalysis.cpp @@ -49,17 +49,18 @@ SketchAnalysis::SketchAnalysis(Sketcher::SketchObject* Obj) : sketch(Obj) {} -SketchAnalysis::~SketchAnalysis() -{} +SketchAnalysis::~SketchAnalysis() = default; -struct SketchAnalysis::VertexIds +namespace +{ +struct VertexIds { Base::Vector3d v; - int GeoId; - Sketcher::PointPos PosId; + int GeoId {}; + Sketcher::PointPos PosId {}; }; -struct SketchAnalysis::Vertex_Less +struct Vertex_Less { explicit Vertex_Less(double tolerance) : tolerance(tolerance) @@ -82,7 +83,7 @@ private: double tolerance; }; -struct SketchAnalysis::VertexID_Less +struct VertexID_Less { bool operator()(const VertexIds& x, const VertexIds& y) const { @@ -90,7 +91,7 @@ struct SketchAnalysis::VertexID_Less } }; -struct SketchAnalysis::Vertex_EqualTo +struct Vertex_EqualTo { explicit Vertex_EqualTo(double tolerance) : tolerance(tolerance) @@ -111,13 +112,13 @@ private: double tolerance; }; -struct SketchAnalysis::EdgeIds +struct EdgeIds { double l; int GeoId; }; -struct SketchAnalysis::Edge_Less +struct Edge_Less { explicit Edge_Less(double tolerance) : tolerance(tolerance) @@ -134,7 +135,7 @@ private: double tolerance; }; -struct SketchAnalysis::Edge_EqualTo +struct Edge_EqualTo { explicit Edge_EqualTo(double tolerance) : tolerance(tolerance) @@ -151,6 +152,8 @@ private: double tolerance; }; +} // namespace + int SketchAnalysis::detectMissingPointOnPointConstraints(double precision, bool includeconstruction /*=true*/) { diff --git a/src/Mod/Sketcher/App/SketchAnalysis.h b/src/Mod/Sketcher/App/SketchAnalysis.h index 07914e2d8b..5456060fc6 100644 --- a/src/Mod/Sketcher/App/SketchAnalysis.h +++ b/src/Mod/Sketcher/App/SketchAnalysis.h @@ -172,13 +172,6 @@ public: private: Sketcher::SketchObject* sketch; - struct VertexIds; - struct Vertex_Less; - struct VertexID_Less; - struct Vertex_EqualTo; - struct EdgeIds; - struct Edge_Less; - struct Edge_EqualTo; std::vector vertexConstraints; std::vector verthorizConstraints; std::vector lineequalityConstraints; From 8abbed295e7108edd645a62d0faf05cab2269444 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 28 May 2024 13:24:05 +0200 Subject: [PATCH 2/9] Sketch: Refactor SketchAnalysis Refactor detectMissingPointOnPointConstraints --- src/Mod/Sketcher/App/SketchAnalysis.cpp | 214 ++++++++++++++---------- 1 file changed, 124 insertions(+), 90 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchAnalysis.cpp b/src/Mod/Sketcher/App/SketchAnalysis.cpp index 0a5c380fcc..3ac9920150 100644 --- a/src/Mod/Sketcher/App/SketchAnalysis.cpp +++ b/src/Mod/Sketcher/App/SketchAnalysis.cpp @@ -142,22 +142,130 @@ struct Edge_EqualTo {} bool operator()(const EdgeIds& x, const EdgeIds& y) const { - if (fabs(x.l - y.l) <= tolerance) { - return true; - } - return false; + return (fabs(x.l - y.l) <= tolerance); } private: double tolerance; }; +struct PointConstraints +{ + explicit PointConstraints(std::vector& vertexIds) + : vertexIds {vertexIds} + {} + + void addGeometry(const Part::Geometry* geo, int index) + { + if (const auto* segm = dynamic_cast(geo)) { + addLineSegment(segm, index); + } + else if (const auto* segm = dynamic_cast(geo)) { + addArcOfCircle(segm, index); + } + else if (const auto* segm = dynamic_cast(geo)) { + addArcOfEllipse(segm, index); + } + else if (const auto* segm = dynamic_cast(geo)) { + addArcOfHyperbola(segm, index); + } + else if (const auto* segm = dynamic_cast(geo)) { + addArcOfParabola(segm, index); + } + else if (const auto* segm = dynamic_cast(geo)) { + addBSplineCurve(segm, index); + } + } + + void addLineSegment(const Part::GeomLineSegment* segm, int index) + { + VertexIds id; + id.GeoId = index; + id.PosId = Sketcher::PointPos::start; + id.v = segm->getStartPoint(); + vertexIds.push_back(id); + id.GeoId = index; + id.PosId = Sketcher::PointPos::end; + id.v = segm->getEndPoint(); + vertexIds.push_back(id); + } + + void addArcOfCircle(const Part::GeomArcOfCircle* segm, int index) + { + VertexIds id; + id.GeoId = index; + id.PosId = Sketcher::PointPos::start; + id.v = segm->getStartPoint(/*emulateCCW=*/true); + vertexIds.push_back(id); + id.GeoId = index; + id.PosId = Sketcher::PointPos::end; + id.v = segm->getEndPoint(/*emulateCCW=*/true); + vertexIds.push_back(id); + } + + void addArcOfEllipse(const Part::GeomArcOfEllipse* segm, int index) + { + VertexIds id; + id.GeoId = index; + id.PosId = Sketcher::PointPos::start; + id.v = segm->getStartPoint(/*emulateCCW=*/true); + vertexIds.push_back(id); + id.GeoId = index; + id.PosId = Sketcher::PointPos::end; + id.v = segm->getEndPoint(/*emulateCCW=*/true); + vertexIds.push_back(id); + } + + void addArcOfHyperbola(const Part::GeomArcOfHyperbola* segm, int index) + { + VertexIds id; + id.GeoId = index; + id.PosId = Sketcher::PointPos::start; + id.v = segm->getStartPoint(); + vertexIds.push_back(id); + id.GeoId = index; + id.PosId = Sketcher::PointPos::end; + id.v = segm->getEndPoint(); + vertexIds.push_back(id); + } + + void addArcOfParabola(const Part::GeomArcOfParabola* segm, int index) + { + VertexIds id; + id.GeoId = index; + id.PosId = Sketcher::PointPos::start; + id.v = segm->getStartPoint(); + vertexIds.push_back(id); + id.GeoId = index; + id.PosId = Sketcher::PointPos::end; + id.v = segm->getEndPoint(); + vertexIds.push_back(id); + } + + void addBSplineCurve(const Part::GeomBSplineCurve* segm, int index) + { + VertexIds id; + id.GeoId = index; + id.PosId = Sketcher::PointPos::start; + id.v = segm->getStartPoint(); + vertexIds.push_back(id); + id.GeoId = index; + id.PosId = Sketcher::PointPos::end; + id.v = segm->getEndPoint(); + vertexIds.push_back(id); + } + +private: + std::vector& vertexIds; +}; + } // namespace int SketchAnalysis::detectMissingPointOnPointConstraints(double precision, bool includeconstruction /*=true*/) { std::vector vertexIds; // Holds a list of all vertices in the sketch + PointConstraints pointConstr(vertexIds); // Build the list of sketch vertices const std::vector& geom = sketch->getInternalGeometry(); @@ -168,84 +276,7 @@ int SketchAnalysis::detectMissingPointOnPointConstraints(double precision, continue; } - if (gf->getGeometry()->is()) { - const Part::GeomLineSegment* segm = - static_cast(gf->getGeometry()); - VertexIds id; - id.GeoId = (int)i; - id.PosId = Sketcher::PointPos::start; - id.v = segm->getStartPoint(); - vertexIds.push_back(id); - id.GeoId = (int)i; - id.PosId = Sketcher::PointPos::end; - id.v = segm->getEndPoint(); - vertexIds.push_back(id); - } - else if (gf->getGeometry()->is()) { - const Part::GeomArcOfCircle* segm = - static_cast(gf->getGeometry()); - VertexIds id; - id.GeoId = (int)i; - id.PosId = Sketcher::PointPos::start; - id.v = segm->getStartPoint(/*emulateCCW=*/true); - vertexIds.push_back(id); - id.GeoId = (int)i; - id.PosId = Sketcher::PointPos::end; - id.v = segm->getEndPoint(/*emulateCCW=*/true); - vertexIds.push_back(id); - } - else if (gf->getGeometry()->is()) { - const Part::GeomArcOfEllipse* segm = - static_cast(gf->getGeometry()); - VertexIds id; - id.GeoId = (int)i; - id.PosId = Sketcher::PointPos::start; - id.v = segm->getStartPoint(/*emulateCCW=*/true); - vertexIds.push_back(id); - id.GeoId = (int)i; - id.PosId = Sketcher::PointPos::end; - id.v = segm->getEndPoint(/*emulateCCW=*/true); - vertexIds.push_back(id); - } - else if (gf->getGeometry()->is()) { - const Part::GeomArcOfHyperbola* segm = - static_cast(gf->getGeometry()); - VertexIds id; - id.GeoId = (int)i; - id.PosId = Sketcher::PointPos::start; - id.v = segm->getStartPoint(); - vertexIds.push_back(id); - id.GeoId = (int)i; - id.PosId = Sketcher::PointPos::end; - id.v = segm->getEndPoint(); - vertexIds.push_back(id); - } - else if (gf->getGeometry()->is()) { - const Part::GeomArcOfParabola* segm = - static_cast(gf->getGeometry()); - VertexIds id; - id.GeoId = (int)i; - id.PosId = Sketcher::PointPos::start; - id.v = segm->getStartPoint(); - vertexIds.push_back(id); - id.GeoId = (int)i; - id.PosId = Sketcher::PointPos::end; - id.v = segm->getEndPoint(); - vertexIds.push_back(id); - } - else if (gf->getGeometry()->is()) { - const Part::GeomBSplineCurve* segm = - static_cast(gf->getGeometry()); - VertexIds id; - id.GeoId = (int)i; - id.PosId = Sketcher::PointPos::start; - id.v = segm->getStartPoint(); - vertexIds.push_back(id); - id.GeoId = (int)i; - id.PosId = Sketcher::PointPos::end; - id.v = segm->getEndPoint(); - vertexIds.push_back(id); - } + pointConstr.addGeometry(gf->getGeometry(), int(i)); // TODO take into account single vertices ? } @@ -257,10 +288,13 @@ int SketchAnalysis::detectMissingPointOnPointConstraints(double precision, std::vector coincidences = sketch->Constraints.getValues(); for (auto& constraint : sketch->Constraints.getValues()) { - if (constraint->Type == Sketcher::Coincident || constraint->Type == Sketcher::Tangent - || constraint->Type == Sketcher::Perpendicular) { + // clang-format off + if (constraint->Type == Sketcher::Coincident || + constraint->Type == Sketcher::Tangent || + constraint->Type == Sketcher::Perpendicular) { coincidences.push_back(constraint); } + // clang-format on // TODO optimizing by removing constraints not applying on vertices ? } @@ -295,7 +329,8 @@ int SketchAnalysis::detectMissingPointOnPointConstraints(double precision, // Decompose the group of adjacent vertices into groups of coincident vertices // Going through existent coincidences for (auto& coincidence : coincidences) { - VertexIds v1, v2; + VertexIds v1; + VertexIds v2; v1.GeoId = coincidence->First; v1.PosId = coincidence->FirstPos; v2.GeoId = coincidence->Second; @@ -407,10 +442,8 @@ void SketchAnalysis::analyseMissingPointOnPointCoincident(double angleprecision) if (geo1->is() && geo2->is()) { - const Part::GeomLineSegment* segm1 = - static_cast(geo1); - const Part::GeomLineSegment* segm2 = - static_cast(geo2); + const auto* segm1 = static_cast(geo1); + const auto* segm2 = static_cast(geo2); Base::Vector3d dir1 = segm1->getEndPoint() - segm1->getStartPoint(); Base::Vector3d dir2 = segm2->getEndPoint() - segm2->getStartPoint(); @@ -424,7 +457,8 @@ void SketchAnalysis::analyseMissingPointOnPointCoincident(double angleprecision) } try { - double u1, u2; + double u1; + double u2; curve1->closestParameter(vc.v, u1); curve2->closestParameter(vc.v, u2); From 7f00aad6aacb33b844cf0f3bba1487f95e943206 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 28 May 2024 13:40:38 +0200 Subject: [PATCH 3/9] Sketch: Refactor SketchAnalysis Refactor makeMissingPointOnPoint --- src/Mod/Sketcher/App/SketchAnalysis.cpp | 102 +++++++++++++++--------- src/Mod/Sketcher/App/SketchAnalysis.h | 10 ++- src/Mod/Sketcher/App/SketchObject.cpp | 6 +- 3 files changed, 75 insertions(+), 43 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchAnalysis.cpp b/src/Mod/Sketcher/App/SketchAnalysis.cpp index 3ac9920150..ad00af681f 100644 --- a/src/Mod/Sketcher/App/SketchAnalysis.cpp +++ b/src/Mod/Sketcher/App/SketchAnalysis.cpp @@ -482,55 +482,79 @@ void SketchAnalysis::analyseMissingPointOnPointCoincident(double angleprecision) } } -void SketchAnalysis::makeMissingPointOnPointCoincident(bool onebyone) +Sketcher::Constraint* SketchAnalysis::create(const ConstraintIds& id) +{ + auto c = new Sketcher::Constraint(); + c->Type = id.Type; + c->First = id.First; + c->Second = id.Second; + c->FirstPos = id.FirstPos; + c->SecondPos = id.SecondPos; + return c; +} + +void SketchAnalysis::solveSketch(const char* errorText) +{ + int status {}; + int dofs {}; + solvesketch(status, dofs, true); + + if (status == -2) { // redundant constraints + sketch->autoRemoveRedundants(false); + + solvesketch(status, dofs, false); + } + + if (status) { + THROWMT(Base::RuntimeError, errorText); + } +} + +void SketchAnalysis::makeConstraints(std::vector& ids) { - int status, dofs; std::vector constr; - - for (const auto& it : vertexConstraints) { - Sketcher::Constraint* c = new Sketcher::Constraint(); - c->Type = it.Type; - c->First = it.First; - c->Second = it.Second; - c->FirstPos = it.FirstPos; - c->SecondPos = it.SecondPos; - - if (onebyone) { - // addConstraint() creates a clone - sketch->addConstraint(c); - delete c; - - solvesketch(status, dofs, true); - - if (status == -2) { // redundant constraints - sketch->autoRemoveRedundants(false); - - solvesketch(status, dofs, false); - } - - if (status) { - THROWMT(Base::RuntimeError, - QT_TRANSLATE_NOOP("Exceptions", - "Autoconstrain error: Unsolvable sketch while applying " - "coincident constraints.")); - } - } - else { - constr.push_back(c); - } + constr.reserve(ids.size()); + for (const auto& it : ids) { + auto c = create(it); + constr.push_back(c); } - if (!onebyone) { - sketch->addConstraints(constr); - } - - vertexConstraints.clear(); + sketch->addConstraints(constr); + ids.clear(); for (auto it : constr) { delete it; } } +void SketchAnalysis::makeConstraintsOneByOne(std::vector& ids, const char* errorText) +{ + for (const auto& it : ids) { + auto c = create(it); + + // addConstraint() creates a clone + sketch->addConstraint(c); + delete c; + + solveSketch(errorText); + } + + ids.clear(); +} + +void SketchAnalysis::makeMissingPointOnPointCoincident() +{ + makeConstraints(vertexConstraints); +} + +void SketchAnalysis::makeMissingPointOnPointCoincidentOneByOne() +{ + makeConstraintsOneByOne(vertexConstraints, + QT_TRANSLATE_NOOP("Exceptions", + "Autoconstrain error: Unsolvable sketch while " + "applying coincident constraints.")); +} + int SketchAnalysis::detectMissingVerticalHorizontalConstraints(double angleprecision) { const std::vector& geom = sketch->getInternalGeometry(); diff --git a/src/Mod/Sketcher/App/SketchAnalysis.h b/src/Mod/Sketcher/App/SketchAnalysis.h index 5456060fc6..d06355fc5c 100644 --- a/src/Mod/Sketcher/App/SketchAnalysis.h +++ b/src/Mod/Sketcher/App/SketchAnalysis.h @@ -97,9 +97,11 @@ public: vertexConstraints = cl; } /// Point on Point constraint simple routine Make step (see constructor) - /// if onebyone, then the sketch is solved after each individual constraint addition and any + void makeMissingPointOnPointCoincident(); + /// Point on Point constraint simple routine Make step (see constructor) + /// The sketch is solved after each individual constraint addition and any /// redundancy removed. - void makeMissingPointOnPointCoincident(bool onebyone = false); + void makeMissingPointOnPointCoincidentOneByOne(); /// Vertical/Horizontal constraints simple routine Detect step (see constructor) int detectMissingVerticalHorizontalConstraints(double angleprecision = M_PI / 8); @@ -180,7 +182,11 @@ private: private: bool checkHorizontal(Base::Vector3d dir, double angleprecision); bool checkVertical(Base::Vector3d dir, double angleprecision); + void makeConstraints(std::vector&); + void makeConstraintsOneByOne(std::vector&, const char* errorText); std::set getDegeneratedGeometries(double tolerance) const; + void solveSketch(const char* errorText); + static Sketcher::Constraint* create(const ConstraintIds& id); }; } // namespace Sketcher diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 9ff799fe3d..e322b40b9c 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -9825,8 +9825,10 @@ void SketchObject::setMissingPointOnPointConstraints(std::vector& void SketchObject::makeMissingPointOnPointCoincident(bool onebyone) { - if (analyser) - analyser->makeMissingPointOnPointCoincident(onebyone); + if (analyser) { + onebyone ? analyser->makeMissingPointOnPointCoincidentOneByOne() + : analyser->makeMissingPointOnPointCoincident(); + } } void SketchObject::makeMissingVerticalHorizontal(bool onebyone) From b052470b9345b609d3d89092e2f50c56035b51a3 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 28 May 2024 14:08:44 +0200 Subject: [PATCH 4/9] Sketch: Refactor SketchAnalysis Refactor makeMissingVerticalHorizontal --- src/Mod/Sketcher/App/SketchAnalysis.cpp | 57 ++++--------------------- src/Mod/Sketcher/App/SketchAnalysis.h | 3 +- src/Mod/Sketcher/App/SketchObject.cpp | 6 ++- 3 files changed, 15 insertions(+), 51 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchAnalysis.cpp b/src/Mod/Sketcher/App/SketchAnalysis.cpp index ad00af681f..402dc8f563 100644 --- a/src/Mod/Sketcher/App/SketchAnalysis.cpp +++ b/src/Mod/Sketcher/App/SketchAnalysis.cpp @@ -591,56 +591,17 @@ int SketchAnalysis::detectMissingVerticalHorizontalConstraints(double anglepreci return verthorizConstraints.size(); } -void SketchAnalysis::makeMissingVerticalHorizontal(bool onebyone) +void SketchAnalysis::makeMissingVerticalHorizontal() { - int status, dofs; - std::vector constr; + makeConstraints(verthorizConstraints); +} - for (std::vector::iterator it = verthorizConstraints.begin(); - it != verthorizConstraints.end(); - ++it) { - Sketcher::Constraint* c = new Sketcher::Constraint(); - c->Type = it->Type; - c->First = it->First; - c->Second = it->Second; - c->FirstPos = it->FirstPos; - c->SecondPos = it->SecondPos; - - if (onebyone) { - // addConstraint() creates a clone - sketch->addConstraint(c); - delete c; - - solvesketch(status, dofs, true); - - if (status == -2) { // redundant constraints - sketch->autoRemoveRedundants(false); - - solvesketch(status, dofs, false); - } - - if (status) { - THROWMT(Base::RuntimeError, - QT_TRANSLATE_NOOP("Exceptions", - "Autoconstrain error: Unsolvable sketch while applying " - "vertical/horizontal constraints.")); - } - } - else { - constr.push_back(c); - } - } - - if (!onebyone) { - sketch->addConstraints(constr); - } - - verthorizConstraints.clear(); - - for (std::vector::iterator it = constr.begin(); it != constr.end(); - ++it) { - delete *it; - } +void SketchAnalysis::makeMissingVerticalHorizontalOneByOne() +{ + makeConstraintsOneByOne(verthorizConstraints, + QT_TRANSLATE_NOOP("Exceptions", + "Autoconstrain error: Unsolvable sketch while " + "applying vertical/horizontal constraints.")); } bool SketchAnalysis::checkVertical(Base::Vector3d dir, double angleprecision) diff --git a/src/Mod/Sketcher/App/SketchAnalysis.h b/src/Mod/Sketcher/App/SketchAnalysis.h index d06355fc5c..3664a3db98 100644 --- a/src/Mod/Sketcher/App/SketchAnalysis.h +++ b/src/Mod/Sketcher/App/SketchAnalysis.h @@ -116,7 +116,8 @@ public: verthorizConstraints = cl; } /// Vertical/Horizontal constraints simple routine Make step (see constructor) - void makeMissingVerticalHorizontal(bool onebyone = false); + void makeMissingVerticalHorizontal(); + void makeMissingVerticalHorizontalOneByOne(); /// Equality constraints simple routine Detect step (see constructor) int detectMissingEqualityConstraints(double precision); diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index e322b40b9c..f4a14ddce3 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -9833,8 +9833,10 @@ void SketchObject::makeMissingPointOnPointCoincident(bool onebyone) void SketchObject::makeMissingVerticalHorizontal(bool onebyone) { - if (analyser) - analyser->makeMissingVerticalHorizontal(onebyone); + if (analyser) { + onebyone ? analyser->makeMissingVerticalHorizontalOneByOne() + : analyser->makeMissingVerticalHorizontal(); + } } void SketchObject::makeMissingEquality(bool onebyone) From ad56548739e42a5cf3bcd14dbd294ef41e7d8177 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 28 May 2024 14:19:58 +0200 Subject: [PATCH 5/9] Sketch: Refactor SketchAnalysis Refactor makeMissingEquality() --- src/Mod/Sketcher/App/SketchAnalysis.cpp | 64 +++++++------------------ src/Mod/Sketcher/App/SketchAnalysis.h | 3 +- src/Mod/Sketcher/App/SketchObject.cpp | 6 ++- 3 files changed, 23 insertions(+), 50 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchAnalysis.cpp b/src/Mod/Sketcher/App/SketchAnalysis.cpp index 402dc8f563..91619772ee 100644 --- a/src/Mod/Sketcher/App/SketchAnalysis.cpp +++ b/src/Mod/Sketcher/App/SketchAnalysis.cpp @@ -756,64 +756,34 @@ int SketchAnalysis::detectMissingEqualityConstraints(double precision) return this->lineequalityConstraints.size() + this->radiusequalityConstraints.size(); } -void SketchAnalysis::makeMissingEquality(bool onebyone) +void SketchAnalysis::makeMissingEquality() { - int status, dofs; - std::vector constr; + std::vector equalities(lineequalityConstraints); + equalities.insert(equalities.end(), + radiusequalityConstraints.begin(), + radiusequalityConstraints.end()); + makeConstraints(equalities); + lineequalityConstraints.clear(); + radiusequalityConstraints.clear(); +} + +void SketchAnalysis::makeMissingEqualityOneByOne() +{ std::vector equalities(lineequalityConstraints); equalities.insert(equalities.end(), radiusequalityConstraints.begin(), radiusequalityConstraints.end()); - for (std::vector::iterator it = equalities.begin(); - it != equalities.end(); - ++it) { - Sketcher::Constraint* c = new Sketcher::Constraint(); - c->Type = it->Type; - c->First = it->First; - c->Second = it->Second; - c->FirstPos = it->FirstPos; - c->SecondPos = it->SecondPos; - - if (onebyone) { - // addConstraint() creates a clone - sketch->addConstraint(c); - delete c; - - solvesketch(status, dofs, true); - - if (status == -2) { // redundant constraints - sketch->autoRemoveRedundants(false); - - solvesketch(status, dofs, false); - } - - if (status) { - THROWMT(Base::RuntimeError, - QT_TRANSLATE_NOOP("Exceptions", - "Autoconstrain error: Unsolvable sketch while applying " - "equality constraints.")); - } - } - else { - constr.push_back(c); - } - } - - if (!onebyone) { - sketch->addConstraints(constr); - } - + makeConstraintsOneByOne(equalities, + QT_TRANSLATE_NOOP("Exceptions", + "Autoconstrain error: Unsolvable sketch while " + "applying equality constraints.")); lineequalityConstraints.clear(); radiusequalityConstraints.clear(); - - for (std::vector::iterator it = constr.begin(); it != constr.end(); - ++it) { - delete *it; - } } + void SketchAnalysis::solvesketch(int& status, int& dofs, bool updategeo) { status = sketch->solve(updategeo); diff --git a/src/Mod/Sketcher/App/SketchAnalysis.h b/src/Mod/Sketcher/App/SketchAnalysis.h index 3664a3db98..291c92aec4 100644 --- a/src/Mod/Sketcher/App/SketchAnalysis.h +++ b/src/Mod/Sketcher/App/SketchAnalysis.h @@ -142,7 +142,8 @@ public: radiusequalityConstraints = cl; } /// Equality constraints simple routine Make step (see constructor) - void makeMissingEquality(bool onebyone = true); + void makeMissingEquality(); + void makeMissingEqualityOneByOne(); /// Detect degenerated geometries int detectDegeneratedGeometries(double tolerance) const; diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index f4a14ddce3..8da9bd1aa3 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -9841,8 +9841,10 @@ void SketchObject::makeMissingVerticalHorizontal(bool onebyone) void SketchObject::makeMissingEquality(bool onebyone) { - if (analyser) - analyser->makeMissingEquality(onebyone); + if (analyser) { + onebyone ? analyser->makeMissingEqualityOneByOne() + : analyser->makeMissingEquality(); + } } int SketchObject::detectDegeneratedGeometries(double tolerance) From 645c7acf659b1531d9bb3c91c3354408ba3c7b26 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 28 May 2024 14:28:07 +0200 Subject: [PATCH 6/9] Sketch: Refactor SketchAnalysis Refactor autoconstraint() --- src/Mod/Sketcher/App/SketchAnalysis.cpp | 155 +++++++++++------------- src/Mod/Sketcher/App/SketchAnalysis.h | 4 + 2 files changed, 72 insertions(+), 87 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchAnalysis.cpp b/src/Mod/Sketcher/App/SketchAnalysis.cpp index 91619772ee..dedd328d64 100644 --- a/src/Mod/Sketcher/App/SketchAnalysis.cpp +++ b/src/Mod/Sketcher/App/SketchAnalysis.cpp @@ -783,7 +783,6 @@ void SketchAnalysis::makeMissingEqualityOneByOne() radiusequalityConstraints.clear(); } - void SketchAnalysis::solvesketch(int& status, int& dofs, bool updategeo) { status = sketch->solve(updategeo); @@ -807,9 +806,7 @@ void SketchAnalysis::solvesketch(int& status, int& dofs, bool updategeo) } } -int SketchAnalysis::autoconstraint(double precision, - double angleprecision, - bool includeconstruction) +void SketchAnalysis::autoDeleteAllConstraints() { App::Document* doc = sketch->getDocument(); doc->openTransaction("delete all constraints"); @@ -818,15 +815,67 @@ int SketchAnalysis::autoconstraint(double precision, doc->commitTransaction(); - int status, dofs; - - solvesketch(status, dofs, true); - - if (status) { // it should not be possible at this moment as we start from a clean situation - THROWMT(Base::RuntimeError, - QT_TRANSLATE_NOOP("Exceptions", + // a failure should not be possible at this moment as we start from a clean situation + solveSketch(QT_TRANSLATE_NOOP("Exceptions", "Autoconstrain error: Unsolvable sketch without constraints.")); +} + +void SketchAnalysis::autoHorizontalVerticalConstraints() +{ + App::Document* doc = sketch->getDocument(); + doc->openTransaction("add vertical/horizontal constraints"); + + makeMissingVerticalHorizontal(); + + // finish the transaction and update + doc->commitTransaction(); + + solveSketch(QT_TRANSLATE_NOOP("Exceptions", + "Autoconstrain error: Unsolvable sketch after applying " + "horizontal and vertical constraints.")); +} + +void SketchAnalysis::autoPointOnPointCoincident() +{ + App::Document* doc = sketch->getDocument(); + doc->openTransaction("add coincident constraint"); + + makeMissingPointOnPointCoincident(); + + // finish the transaction and update + doc->commitTransaction(); + + solveSketch(QT_TRANSLATE_NOOP("Exceptions", + "Autoconstrain error: Unsolvable sketch after applying " + "point-on-point constraints.")); +} + +void SketchAnalysis::autoMissingEquality() +{ + App::Document* doc = sketch->getDocument(); + doc->openTransaction("add equality constraints"); + + try { + makeMissingEquality(); } + catch (Base::RuntimeError&) { + doc->abortTransaction(); + throw; + } + + // finish the transaction and update + doc->commitTransaction(); + + solveSketch(QT_TRANSLATE_NOOP("Exceptions", + "Autoconstrain error: Unsolvable sketch after " + "applying equality constraints.")); +} + +int SketchAnalysis::autoconstraint(double precision, + double angleprecision, + bool includeconstruction) +{ + autoDeleteAllConstraints(); // STAGE 1: Vertical/Horizontal Line Segments int nhv = detectMissingVerticalHorizontalConstraints(angleprecision); @@ -845,95 +894,27 @@ int SketchAnalysis::autoconstraint(double precision, // STAGE 3: Equality constraint detection int ne = detectMissingEqualityConstraints(precision); - Base::Console().Log( - "Constraints: Vertical/Horizontal: %d found. Point-on-point: %d. Equality: %d\n", - nhv, - nc, - ne); + Base::Console().Log("Constraints: Vertical/Horizontal: %d found. " + "Point-on-point: %d. Equality: %d\n", + nhv, + nc, + ne); // Applying STAGE 1, if any if (nhv > 0) { - App::Document* doc = sketch->getDocument(); - doc->openTransaction("add vertical/horizontal constraints"); - - makeMissingVerticalHorizontal(); - - // finish the transaction and update - doc->commitTransaction(); - - solvesketch(status, dofs, true); - - if (status == -2) { // redundants - sketch->autoRemoveRedundants(false); - solvesketch(status, dofs, false); - } - - if (status) { - THROWMT(Base::RuntimeError, - QT_TRANSLATE_NOOP("Exceptions", - "Autoconstrain error: Unsolvable sketch after applying " - "horizontal and vertical constraints.")); - } + autoHorizontalVerticalConstraints(); } // Applying STAGE 2 if (nc > 0) { - App::Document* doc = sketch->getDocument(); - doc->openTransaction("add coincident constraint"); - - makeMissingPointOnPointCoincident(); - - // finish the transaction and update - doc->commitTransaction(); - - solvesketch(status, dofs, true); - - if (status == -2) { // redundants - sketch->autoRemoveRedundants(false); - solvesketch(status, dofs, false); - } - - if (status) { - THROWMT(Base::RuntimeError, - QT_TRANSLATE_NOOP("Exceptions", - "Autoconstrain error: Unsolvable sketch after applying " - "point-on-point constraints.")); - } + autoPointOnPointCoincident(); } // Applying STAGE 3 if (ne > 0) { - App::Document* doc = sketch->getDocument(); - doc->openTransaction("add equality constraints"); - - try { - makeMissingEquality(); - } - catch (Base::RuntimeError&) { - doc->abortTransaction(); - throw; - } - - // finish the transaction and update - doc->commitTransaction(); - - solvesketch(status, dofs, true); - - if (status == -2) { // redundants - sketch->autoRemoveRedundants(false); - solvesketch(status, dofs, false); - } - - if (status) { - THROWMT( - Base::RuntimeError, - QT_TRANSLATE_NOOP( - "Exceptions", - "Autoconstrain error: Unsolvable sketch after applying equality constraints.")); - } + autoMissingEquality(); } - return 0; } diff --git a/src/Mod/Sketcher/App/SketchAnalysis.h b/src/Mod/Sketcher/App/SketchAnalysis.h index 291c92aec4..e972fc411d 100644 --- a/src/Mod/Sketcher/App/SketchAnalysis.h +++ b/src/Mod/Sketcher/App/SketchAnalysis.h @@ -182,6 +182,10 @@ private: std::vector radiusequalityConstraints; private: + void autoDeleteAllConstraints(); + void autoHorizontalVerticalConstraints(); + void autoPointOnPointCoincident(); + void autoMissingEquality(); bool checkHorizontal(Base::Vector3d dir, double angleprecision); bool checkVertical(Base::Vector3d dir, double angleprecision); void makeConstraints(std::vector&); From 4b8ef4721a9e62f4bea7d8329d3adc386ace7eff Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 28 May 2024 14:43:46 +0200 Subject: [PATCH 7/9] Sketch: Refactor SketchAnalysis Fix linter warnings --- src/Mod/Sketcher/App/SketchAnalysis.cpp | 91 +++++++++++-------------- src/Mod/Sketcher/App/SketchAnalysis.h | 9 +++ 2 files changed, 50 insertions(+), 50 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchAnalysis.cpp b/src/Mod/Sketcher/App/SketchAnalysis.cpp index dedd328d64..3638bb910a 100644 --- a/src/Mod/Sketcher/App/SketchAnalysis.cpp +++ b/src/Mod/Sketcher/App/SketchAnalysis.cpp @@ -114,8 +114,8 @@ private: struct EdgeIds { - double l; - int GeoId; + double l {}; + int GeoId {}; }; struct Edge_Less @@ -195,11 +195,11 @@ struct PointConstraints VertexIds id; id.GeoId = index; id.PosId = Sketcher::PointPos::start; - id.v = segm->getStartPoint(/*emulateCCW=*/true); + id.v = segm->getStartPoint(/*emulateCCWXY=*/true); vertexIds.push_back(id); id.GeoId = index; id.PosId = Sketcher::PointPos::end; - id.v = segm->getEndPoint(/*emulateCCW=*/true); + id.v = segm->getEndPoint(/*emulateCCWXY=*/true); vertexIds.push_back(id); } @@ -208,11 +208,11 @@ struct PointConstraints VertexIds id; id.GeoId = index; id.PosId = Sketcher::PointPos::start; - id.v = segm->getStartPoint(/*emulateCCW=*/true); + id.v = segm->getStartPoint(/*emulateCCWXY=*/true); vertexIds.push_back(id); id.GeoId = index; id.PosId = Sketcher::PointPos::end; - id.v = segm->getEndPoint(/*emulateCCW=*/true); + id.v = segm->getEndPoint(/*emulateCCWXY=*/true); vertexIds.push_back(id); } @@ -300,7 +300,7 @@ int SketchAnalysis::detectMissingPointOnPointConstraints(double precision, std::list missingCoincidences; // Holds the list of missing coincidences - std::vector::iterator vt = vertexIds.begin(); + auto vt = vertexIds.begin(); Vertex_EqualTo pred(precision); // Comparing existing constraints and find missing ones @@ -424,7 +424,7 @@ int SketchAnalysis::detectMissingPointOnPointConstraints(double precision, } // Return number of missing constraints - return this->vertexConstraints.size(); + return int(this->vertexConstraints.size()); } void SketchAnalysis::analyseMissingPointOnPointCoincident(double angleprecision) @@ -435,15 +435,15 @@ void SketchAnalysis::analyseMissingPointOnPointCoincident(double angleprecision) auto geo2 = sketch->getGeometry(vc.Second); // tangency point-on-point - const Part::GeomCurve* curve1 = dynamic_cast(geo1); - const Part::GeomCurve* curve2 = dynamic_cast(geo2); + const auto* curve1 = dynamic_cast(geo1); + const auto* curve2 = dynamic_cast(geo2); if (curve1 && curve2) { - if (geo1->is() && geo2->is()) { + const auto* segm1 = dynamic_cast(geo1); + const auto* segm2 = dynamic_cast(geo2); - const auto* segm1 = static_cast(geo1); - const auto* segm2 = static_cast(geo2); + if (segm1 && segm2) { Base::Vector3d dir1 = segm1->getEndPoint() - segm1->getStartPoint(); Base::Vector3d dir2 = segm2->getEndPoint() - segm2->getStartPoint(); @@ -457,8 +457,8 @@ void SketchAnalysis::analyseMissingPointOnPointCoincident(double angleprecision) } try { - double u1; - double u2; + double u1 {}; + double u2 {}; curve1->closestParameter(vc.v, u1); curve2->closestParameter(vc.v, u2); @@ -499,7 +499,7 @@ void SketchAnalysis::solveSketch(const char* errorText) int dofs {}; solvesketch(status, dofs, true); - if (status == -2) { // redundant constraints + if (status == int(Solver::RedundantConstraints)) { sketch->autoRemoveRedundants(false); solvesketch(status, dofs, false); @@ -564,9 +564,7 @@ int SketchAnalysis::detectMissingVerticalHorizontalConstraints(double anglepreci for (std::size_t i = 0; i < geom.size(); i++) { Part::Geometry* g = geom[i]; - if (g->is()) { - const Part::GeomLineSegment* segm = static_cast(g); - + if (const auto* segm = dynamic_cast(g)) { Base::Vector3d dir = segm->getEndPoint() - segm->getStartPoint(); ConstraintIds id; @@ -588,7 +586,7 @@ int SketchAnalysis::detectMissingVerticalHorizontalConstraints(double anglepreci } } - return verthorizConstraints.size(); + return int(verthorizConstraints.size()); } void SketchAnalysis::makeMissingVerticalHorizontal() @@ -623,22 +621,19 @@ int SketchAnalysis::detectMissingEqualityConstraints(double precision) for (std::size_t i = 0; i < geom.size(); i++) { Part::Geometry* g = geom[i]; - if (g->is()) { - const Part::GeomLineSegment* segm = static_cast(g); + if (const auto* segm = dynamic_cast(g)) { EdgeIds id; id.GeoId = (int)i; id.l = (segm->getEndPoint() - segm->getStartPoint()).Length(); lineedgeIds.push_back(id); } - else if (g->is()) { - const Part::GeomArcOfCircle* segm = static_cast(g); + else if (const auto* segm = dynamic_cast(g)) { EdgeIds id; id.GeoId = (int)i; id.l = segm->getRadius(); radiusedgeIds.push_back(id); } - else if (g->is()) { - const Part::GeomCircle* segm = static_cast(g); + else if (const auto* segm = dynamic_cast(g)) { EdgeIds id; id.GeoId = (int)i; id.l = segm->getRadius(); @@ -647,7 +642,7 @@ int SketchAnalysis::detectMissingEqualityConstraints(double precision) } std::sort(lineedgeIds.begin(), lineedgeIds.end(), Edge_Less(precision)); - std::vector::iterator vt = lineedgeIds.begin(); + auto vt = lineedgeIds.begin(); Edge_EqualTo pred(precision); std::list equallines; @@ -712,19 +707,16 @@ int SketchAnalysis::detectMissingEqualityConstraints(double precision) // and check which of them is forcing two vertexes to be coincident. // If there is none but two vertexes can be considered equal a coincident constraint is missing. std::vector constraint = sketch->Constraints.getValues(); - for (std::vector::iterator it = constraint.begin(); - it != constraint.end(); - ++it) { - if ((*it)->Type == Sketcher::Equal) { + for (auto it : constraint) { + if (it->Type == Sketcher::Equal) { ConstraintIds id {Base::Vector3d {}, - (*it)->First, - (*it)->Second, - (*it)->FirstPos, - (*it)->SecondPos, - (*it)->Type}; + it->First, + it->Second, + it->FirstPos, + it->SecondPos, + it->Type}; - std::list::iterator pos = - std::find_if(equallines.begin(), equallines.end(), Constraint_Equal(id)); + auto pos = std::find_if(equallines.begin(), equallines.end(), Constraint_Equal(id)); if (pos != equallines.end()) { equallines.erase(pos); @@ -741,19 +733,18 @@ int SketchAnalysis::detectMissingEqualityConstraints(double precision) this->lineequalityConstraints.clear(); this->lineequalityConstraints.reserve(equallines.size()); - for (std::list::iterator it = equallines.begin(); it != equallines.end(); ++it) { - this->lineequalityConstraints.push_back(*it); + for (const auto& it : equallines) { + this->lineequalityConstraints.push_back(it); } this->radiusequalityConstraints.clear(); this->radiusequalityConstraints.reserve(equalradius.size()); - for (std::list::iterator it = equalradius.begin(); it != equalradius.end(); - ++it) { - this->radiusequalityConstraints.push_back(*it); + for (const auto& it : equalradius) { + this->radiusequalityConstraints.push_back(it); } - return this->lineequalityConstraints.size() + this->radiusequalityConstraints.size(); + return int(this->lineequalityConstraints.size() + this->radiusequalityConstraints.size()); } void SketchAnalysis::makeMissingEquality() @@ -794,15 +785,15 @@ void SketchAnalysis::solvesketch(int& status, int& dofs, bool updategeo) dofs = sketch->getLastDoF(); } - if (sketch->getLastHasRedundancies()) { // redundant constraints - status = -2; + if (sketch->getLastHasRedundancies()) { + status = int(Solver::RedundantConstraints); } - if (dofs < 0) { // over-constrained sketch - status = -4; + if (dofs < 0) { + status = int(Solver::OverConstrained); } - else if (sketch->getLastHasConflicts()) { // conflicting constraints - status = -3; + else if (sketch->getLastHasConflicts()) { + status = int(Solver::ConflictingConstraints); } } diff --git a/src/Mod/Sketcher/App/SketchAnalysis.h b/src/Mod/Sketcher/App/SketchAnalysis.h index e972fc411d..4695254d29 100644 --- a/src/Mod/Sketcher/App/SketchAnalysis.h +++ b/src/Mod/Sketcher/App/SketchAnalysis.h @@ -39,6 +39,15 @@ namespace Sketcher class SketchObject; + +enum class Solver +{ + RedundantConstraints = -2, + ConflictingConstraints = -3, + OverConstrained = -4, +}; + + class SketcherExport SketchAnalysis { public: From 60574c65074834f85b4ffc140b72f34e563ccb7c Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 28 May 2024 15:10:51 +0200 Subject: [PATCH 8/9] Sketch: Refactor SketchAnalysis Refactor detectMissingEqualityConstraints() --- src/Mod/Sketcher/App/SketchAnalysis.cpp | 202 ++++++++++++++---------- 1 file changed, 120 insertions(+), 82 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchAnalysis.cpp b/src/Mod/Sketcher/App/SketchAnalysis.cpp index 3638bb910a..b007e0b04e 100644 --- a/src/Mod/Sketcher/App/SketchAnalysis.cpp +++ b/src/Mod/Sketcher/App/SketchAnalysis.cpp @@ -259,6 +259,122 @@ private: std::vector& vertexIds; }; +struct EqualityConstraints +{ + void addGeometry(const Part::Geometry* geo, int index) + { + if (const auto* segm = dynamic_cast(geo)) { + addLineSegment(segm, index); + } + else if (const auto* segm = dynamic_cast(geo)) { + addArcOfCircle(segm, index); + } + else if (const auto* segm = dynamic_cast(geo)) { + addCircle(segm, index); + } + } + + void addLineSegment(const Part::GeomLineSegment* segm, int index) + { + EdgeIds id; + id.GeoId = index; + id.l = (segm->getEndPoint() - segm->getStartPoint()).Length(); + lineedgeIds.push_back(id); + } + + void addArcOfCircle(const Part::GeomArcOfCircle* segm, int index) + { + EdgeIds id; + id.GeoId = index; + id.l = segm->getRadius(); + radiusedgeIds.push_back(id); + } + + void addCircle(const Part::GeomCircle* segm, int index) + { + EdgeIds id; + id.GeoId = index; + id.l = segm->getRadius(); + radiusedgeIds.push_back(id); + } + + std::list getEqualLines(double precision) + { + std::sort(lineedgeIds.begin(), lineedgeIds.end(), Edge_Less(precision)); + auto vt = lineedgeIds.begin(); + Edge_EqualTo pred(precision); + + std::list equallines; + // Make a list of constraint we expect for coincident vertexes + while (vt < lineedgeIds.end()) { + // get first item whose adjacent element has the same vertex coordinates + vt = std::adjacent_find(vt, lineedgeIds.end(), pred); + if (vt < lineedgeIds.end()) { + std::vector::iterator vn; + for (vn = vt + 1; vn != lineedgeIds.end(); ++vn) { + if (pred(*vt, *vn)) { + ConstraintIds id; + id.Type = Equal; + id.v.x = vt->l; + id.First = vt->GeoId; + id.FirstPos = Sketcher::PointPos::none; + id.Second = vn->GeoId; + id.SecondPos = Sketcher::PointPos::none; + equallines.push_back(id); + } + else { + break; + } + } + + vt = vn; + } + } + + return equallines; + } + + std::list getEqualRadius(double precision) + { + std::sort(radiusedgeIds.begin(), radiusedgeIds.end(), Edge_Less(precision)); + auto vt = radiusedgeIds.begin(); + Edge_EqualTo pred(precision); + + std::list equalradius; + // Make a list of constraint we expect for coincident vertexes + while (vt < radiusedgeIds.end()) { + // get first item whose adjacent element has the same vertex coordinates + vt = std::adjacent_find(vt, radiusedgeIds.end(), pred); + if (vt < radiusedgeIds.end()) { + std::vector::iterator vn; + for (vn = vt + 1; vn != radiusedgeIds.end(); ++vn) { + if (pred(*vt, *vn)) { + ConstraintIds id; + id.Type = Equal; + id.v.x = vt->l; + id.First = vt->GeoId; + id.FirstPos = Sketcher::PointPos::none; + id.Second = vn->GeoId; + id.SecondPos = Sketcher::PointPos::none; + equalradius.push_back(id); + } + else { + break; + } + } + + vt = vn; + } + } + + return equalradius; + } + +private: + std::vector lineedgeIds; + std::vector radiusedgeIds; +}; + } // namespace int SketchAnalysis::detectMissingPointOnPointConstraints(double precision, @@ -614,94 +730,16 @@ bool SketchAnalysis::checkHorizontal(Base::Vector3d dir, double angleprecision) int SketchAnalysis::detectMissingEqualityConstraints(double precision) { - std::vector lineedgeIds; - std::vector radiusedgeIds; + EqualityConstraints equalConstr; const std::vector& geom = sketch->getInternalGeometry(); for (std::size_t i = 0; i < geom.size(); i++) { Part::Geometry* g = geom[i]; - - if (const auto* segm = dynamic_cast(g)) { - EdgeIds id; - id.GeoId = (int)i; - id.l = (segm->getEndPoint() - segm->getStartPoint()).Length(); - lineedgeIds.push_back(id); - } - else if (const auto* segm = dynamic_cast(g)) { - EdgeIds id; - id.GeoId = (int)i; - id.l = segm->getRadius(); - radiusedgeIds.push_back(id); - } - else if (const auto* segm = dynamic_cast(g)) { - EdgeIds id; - id.GeoId = (int)i; - id.l = segm->getRadius(); - radiusedgeIds.push_back(id); - } - } - - std::sort(lineedgeIds.begin(), lineedgeIds.end(), Edge_Less(precision)); - auto vt = lineedgeIds.begin(); - Edge_EqualTo pred(precision); - - std::list equallines; - // Make a list of constraint we expect for coincident vertexes - while (vt < lineedgeIds.end()) { - // get first item whose adjacent element has the same vertex coordinates - vt = std::adjacent_find(vt, lineedgeIds.end(), pred); - if (vt < lineedgeIds.end()) { - std::vector::iterator vn; - for (vn = vt + 1; vn != lineedgeIds.end(); ++vn) { - if (pred(*vt, *vn)) { - ConstraintIds id; - id.Type = Equal; - id.v.x = vt->l; - id.First = vt->GeoId; - id.FirstPos = Sketcher::PointPos::none; - id.Second = vn->GeoId; - id.SecondPos = Sketcher::PointPos::none; - equallines.push_back(id); - } - else { - break; - } - } - - vt = vn; - } - } - - std::sort(radiusedgeIds.begin(), radiusedgeIds.end(), Edge_Less(precision)); - vt = radiusedgeIds.begin(); - - std::list equalradius; - // Make a list of constraint we expect for coincident vertexes - while (vt < radiusedgeIds.end()) { - // get first item whose adjacent element has the same vertex coordinates - vt = std::adjacent_find(vt, radiusedgeIds.end(), pred); - if (vt < radiusedgeIds.end()) { - std::vector::iterator vn; - for (vn = vt + 1; vn != radiusedgeIds.end(); ++vn) { - if (pred(*vt, *vn)) { - ConstraintIds id; - id.Type = Equal; - id.v.x = vt->l; - id.First = vt->GeoId; - id.FirstPos = Sketcher::PointPos::none; - id.Second = vn->GeoId; - id.SecondPos = Sketcher::PointPos::none; - equalradius.push_back(id); - } - else { - break; - } - } - - vt = vn; - } + equalConstr.addGeometry(g, int(i)); } + std::list equallines = equalConstr.getEqualLines(precision); + std::list equalradius = equalConstr.getEqualRadius(precision); // Go through the available 'Coincident', 'Tangent' or 'Perpendicular' constraints // and check which of them is forcing two vertexes to be coincident. From 2b108b1bb33d2cccaf35f74b302772033a4939da Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 28 May 2024 15:28:53 +0200 Subject: [PATCH 9/9] Sketch: Refactor SketchAnalysis Refactor detectMissingPointOnPointConstraints() --- src/Mod/Sketcher/App/SketchAnalysis.cpp | 262 ++++++++++++------------ 1 file changed, 134 insertions(+), 128 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchAnalysis.cpp b/src/Mod/Sketcher/App/SketchAnalysis.cpp index b007e0b04e..527e83e529 100644 --- a/src/Mod/Sketcher/App/SketchAnalysis.cpp +++ b/src/Mod/Sketcher/App/SketchAnalysis.cpp @@ -151,10 +151,6 @@ private: struct PointConstraints { - explicit PointConstraints(std::vector& vertexIds) - : vertexIds {vertexIds} - {} - void addGeometry(const Part::Geometry* geo, int index) { if (const auto* segm = dynamic_cast(geo)) { @@ -255,8 +251,136 @@ struct PointConstraints vertexIds.push_back(id); } + std::list getMissingCoincidences(std::vector& allcoincid, + double precision) + { + std::list missingCoincidences; // Holds the list of missing coincidences + + // Sort points in geographic order + std::sort(vertexIds.begin(), vertexIds.end(), Vertex_Less(precision)); + + auto vt = vertexIds.begin(); + Vertex_EqualTo pred(precision); + + // Comparing existing constraints and find missing ones + + while (vt < vertexIds.end()) { + // Seeking for adjacent group of vertices + vt = std::adjacent_find(vt, vertexIds.end(), pred); + if (vt < vertexIds.end()) { // If one found + std::vector::iterator vn; + // Holds a single group of adjacent vertices + std::set vertexGrp; + // Extract the group of adjacent vertices + vertexGrp.insert(*vt); + for (vn = vt + 1; vn < vertexIds.end(); ++vn) { + if (pred(*vt, *vn)) { + vertexGrp.insert(*vn); + } + else { + break; + } + } + + // Holds groups of coincident vertices + std::vector> coincVertexGrps; + + // Decompose the group of adjacent vertices into groups of coincident vertices + // Going through existent coincidences + for (auto& coincidence : allcoincid) { + VertexIds v1; + VertexIds v2; + v1.GeoId = coincidence->First; + v1.PosId = coincidence->FirstPos; + v2.GeoId = coincidence->Second; + v2.PosId = coincidence->SecondPos; + + // Look if coincident vertices are in the group of adjacent ones we are + // processing + auto nv1 = vertexGrp.extract(v1); + auto nv2 = vertexGrp.extract(v2); + + // Maybe if both empty, they already have been extracted by other coincidences + // We have to check in existing coincident groups and eventually merge + if (nv1.empty() && nv2.empty()) { + std::set* tempGrp = nullptr; + for (auto it = coincVertexGrps.begin(); it < coincVertexGrps.end(); ++it) { + if ((it->find(v1) != it->end()) || (it->find(v2) != it->end())) { + if (!tempGrp) { + tempGrp = &*it; + } + else { + tempGrp->insert(it->begin(), it->end()); + coincVertexGrps.erase(it); + break; + } + } + } + continue; + } + + // Look if one of the constrained vertices is already in a group of coincident + // vertices + for (std::set& grp : coincVertexGrps) { + if ((grp.find(v1) != grp.end()) || (grp.find(v2) != grp.end())) { + // If yes add them to the existing group + if (!nv1.empty()) { + grp.insert(nv1.value()); + } + if (!nv2.empty()) { + grp.insert(nv2.value()); + } + continue; + } + } + + if (nv1.empty() || nv2.empty()) { + continue; + } + + // If no, create a new group of coincident vertices + std::set newGrp; + newGrp.insert(nv1.value()); + newGrp.insert(nv2.value()); + coincVertexGrps.push_back(newGrp); + } + + // If there are remaining vertices in the adjacent group (not in any existing + // constraint) add them as being each a separate coincident group + for (auto& lonept : vertexGrp) { + std::set newGrp; + newGrp.insert(lonept); + coincVertexGrps.push_back(newGrp); + } + + // If there is more than 1 coincident group into adjacent group, constraint(s) + // is(are) missing Virtually generate the missing constraint(s) + if (coincVertexGrps.size() > 1) { + std::vector>::iterator vn; + // Starting from the 2nd coincident group, generate a constraint between + // this group first vertex, and previous group first vertex + for (vn = coincVertexGrps.begin() + 1; vn < coincVertexGrps.end(); ++vn) { + ConstraintIds id; + id.Type = Coincident; // default point on point restriction + id.v = (vn - 1)->begin()->v; + id.First = (vn - 1)->begin()->GeoId; + id.FirstPos = (vn - 1)->begin()->PosId; + id.Second = vn->begin()->GeoId; + id.SecondPos = vn->begin()->PosId; + missingCoincidences.push_back(id); + } + } + + vt = vn; + } + } + + return missingCoincidences; + } + private: - std::vector& vertexIds; + // Holds a list of all vertices in the sketch + std::vector vertexIds; }; struct EqualityConstraints @@ -380,8 +504,7 @@ private: int SketchAnalysis::detectMissingPointOnPointConstraints(double precision, bool includeconstruction /*=true*/) { - std::vector vertexIds; // Holds a list of all vertices in the sketch - PointConstraints pointConstr(vertexIds); + PointConstraints pointConstr; // Build the list of sketch vertices const std::vector& geom = sketch->getInternalGeometry(); @@ -396,13 +519,9 @@ int SketchAnalysis::detectMissingPointOnPointConstraints(double precision, // TODO take into account single vertices ? } - // Sort points in geographic order - std::sort(vertexIds.begin(), vertexIds.end(), Vertex_Less(precision)); - - // Build a list of all coincidence in the sketch + // Build a list of all coincidences in the sketch std::vector coincidences = sketch->Constraints.getValues(); - for (auto& constraint : sketch->Constraints.getValues()) { // clang-format off if (constraint->Type == Sketcher::Coincident || @@ -414,122 +533,9 @@ int SketchAnalysis::detectMissingPointOnPointConstraints(double precision, // TODO optimizing by removing constraints not applying on vertices ? } - std::list missingCoincidences; // Holds the list of missing coincidences - - auto vt = vertexIds.begin(); - Vertex_EqualTo pred(precision); - - // Comparing existing constraints and find missing ones - - while (vt < vertexIds.end()) { - // Seeking for adjacent group of vertices - vt = std::adjacent_find(vt, vertexIds.end(), pred); - if (vt < vertexIds.end()) { // If one found - std::vector::iterator vn; - // Holds a single group of adjacent vertices - std::set vertexGrp; - // Extract the group of adjacent vertices - vertexGrp.insert(*vt); - for (vn = vt + 1; vn < vertexIds.end(); ++vn) { - if (pred(*vt, *vn)) { - vertexGrp.insert(*vn); - } - else { - break; - } - } - - // Holds groups of coincident vertices - std::vector> coincVertexGrps; - - // Decompose the group of adjacent vertices into groups of coincident vertices - // Going through existent coincidences - for (auto& coincidence : coincidences) { - VertexIds v1; - VertexIds v2; - v1.GeoId = coincidence->First; - v1.PosId = coincidence->FirstPos; - v2.GeoId = coincidence->Second; - v2.PosId = coincidence->SecondPos; - - // Look if coincident vertices are in the group of adjacent ones we are processing - auto nv1 = vertexGrp.extract(v1); - auto nv2 = vertexGrp.extract(v2); - - // Maybe if both empty, they already have been extracted by other coincidences - // We have to check in existing coincident groups and eventually merge - if (nv1.empty() && nv2.empty()) { - std::set* tempGrp = nullptr; - for (auto it = coincVertexGrps.begin(); it < coincVertexGrps.end(); ++it) { - if ((it->find(v1) != it->end()) || (it->find(v2) != it->end())) { - if (!tempGrp) { - tempGrp = &*it; - } - else { - tempGrp->insert(it->begin(), it->end()); - coincVertexGrps.erase(it); - break; - } - } - } - continue; - } - - // Look if one of the constrained vertices is already in a group of coincident - // vertices - for (std::set& grp : coincVertexGrps) { - if ((grp.find(v1) != grp.end()) || (grp.find(v2) != grp.end())) { - // If yes add them to the existing group - if (!nv1.empty()) { - grp.insert(nv1.value()); - } - if (!nv2.empty()) { - grp.insert(nv2.value()); - } - continue; - } - } - - if (nv1.empty() || nv2.empty()) { - continue; - } - - // If no, create a new group of coincident vertices - std::set newGrp; - newGrp.insert(nv1.value()); - newGrp.insert(nv2.value()); - coincVertexGrps.push_back(newGrp); - } - - // If there are remaining vertices in the adjacent group (not in any existing - // constraint) add them as being each a separate coincident group - for (auto& lonept : vertexGrp) { - std::set newGrp; - newGrp.insert(lonept); - coincVertexGrps.push_back(newGrp); - } - - // If there is more than 1 coincident group into adjacent group, constraint(s) is(are) - // missing Virtually generate the missing constraint(s) - if (coincVertexGrps.size() > 1) { - std::vector>::iterator vn; - // Starting from the 2nd coincident group, generate a constraint between - // this group first vertex, and previous group first vertex - for (vn = coincVertexGrps.begin() + 1; vn < coincVertexGrps.end(); ++vn) { - ConstraintIds id; - id.Type = Coincident; // default point on point restriction - id.v = (vn - 1)->begin()->v; - id.First = (vn - 1)->begin()->GeoId; - id.FirstPos = (vn - 1)->begin()->PosId; - id.Second = vn->begin()->GeoId; - id.SecondPos = vn->begin()->PosId; - missingCoincidences.push_back(id); - } - } - - vt = vn; - } - } + // Holds the list of missing coincidences + std::list missingCoincidences = + pointConstr.getMissingCoincidences(coincidences, precision); // Update list of missing constraints stored as member variable of sketch this->vertexConstraints.clear();