From 5a01d438f2d8fe73bd50a3ed2977003c2d29c084 Mon Sep 17 00:00:00 2001 From: Ajinkya Dahale Date: Sun, 22 Dec 2024 04:00:53 +0530 Subject: [PATCH] [Sketcher] Refactor internal geometry operations * Use range-for and rearrange for understandability. * Break down into individual functions by geomtype. * Also refactor `exposeInternalGeometryForType` * Use `Constraint::involves...()` in delete internal Suppress clang-tidy/clazy warnings by using `[[maybe_unused]]`. Co-authored-by: Chris Hennes --- src/Mod/Sketcher/App/SketchObject.cpp | 1387 +++++++++++++------------ src/Mod/Sketcher/App/SketchObject.h | 14 + 2 files changed, 755 insertions(+), 646 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 4cc9f3486739..9b2acf87d762 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -6090,540 +6090,664 @@ int SketchObject::removeAxesAlignment(const std::vector& geoIdList) return 0; } -int SketchObject::exposeInternalGeometry(int GeoId) +template <> +int SketchObject::exposeInternalGeometryForType(const int GeoId) { - if (GeoId < 0 || GeoId > getHighestCurveIndex()) - return -1; - const Part::Geometry* geo = getGeometry(GeoId); - // Only for supported types - if (geo->is() - || geo->is()) { - // First we search what has to be restored - bool major = false; - bool minor = false; - bool focus1 = false; - bool focus2 = false; - - const std::vector& vals = Constraints.getValues(); - - for (std::vector::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; - break; - case Sketcher::EllipseMinorDiameter: - minor = true; - break; - case Sketcher::EllipseFocus1: - focus1 = true; - break; - case Sketcher::EllipseFocus2: - focus2 = true; - break; - default: - return -1; - } - } + // First we search what has to be restored + bool major = false; + bool minor = false; + bool focus1 = false; + bool focus2 = false; + + const std::vector& vals = Constraints.getValues(); + + for (const auto& constr : vals) { + if (constr->Type != Sketcher::InternalAlignment || constr->Second != GeoId) { + continue; } - int currentgeoid = getHighestCurveIndex(); - int incrgeo = 0; + switch (constr->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; + default: + return -1; + } + } - Base::Vector3d center; - double majord; - double minord; - Base::Vector3d majdir; + int currentgeoid = getHighestCurveIndex(); + int incrgeo = 0; - std::vector igeo; - std::vector icon; + Base::Vector3d center; + double majord; + double minord; + Base::Vector3d majdir; - if (geo->is()) { - const Part::GeomEllipse* ellipse = static_cast(geo); + std::vector igeo; + std::vector icon; - center = ellipse->getCenter(); - majord = ellipse->getMajorRadius(); - minord = ellipse->getMinorRadius(); - majdir = ellipse->getMajorAxisDir(); - } - else { - const Part::GeomArcOfEllipse* aoe = static_cast(geo); + const Part::GeomEllipse* ellipse = static_cast(geo); - center = aoe->getCenter(); - majord = aoe->getMajorRadius(); - minord = aoe->getMinorRadius(); - majdir = aoe->getMajorAxisDir(); - } + center = ellipse->getCenter(); + majord = ellipse->getMajorRadius(); + minord = ellipse->getMinorRadius(); + majdir = ellipse->getMajorAxisDir(); - Base::Vector3d mindir = Vector3d(-majdir.y, majdir.x); + Base::Vector3d mindir = Vector3d(-majdir.y, majdir.x); - Base::Vector3d majorpositiveend = center + majord * majdir; - Base::Vector3d majornegativeend = center - majord * majdir; - Base::Vector3d minorpositiveend = center + minord * mindir; - Base::Vector3d minornegativeend = center - minord * mindir; + Base::Vector3d majorpositiveend = center + majord * majdir; + Base::Vector3d majornegativeend = center - majord * majdir; + Base::Vector3d minorpositiveend = center + minord * mindir; + Base::Vector3d minornegativeend = center - minord * mindir; - double df = sqrt(majord * majord - minord * minord); + double df = sqrt(majord * majord - minord * minord); - Base::Vector3d focus1P = center + df * majdir; - Base::Vector3d focus2P = center - df * majdir; + Base::Vector3d focus1P = center + df * majdir; + Base::Vector3d focus2P = center - df * majdir; - if (!major) { - Part::GeomLineSegment* lmajor = new Part::GeomLineSegment(); - lmajor->setPoints(majorpositiveend, majornegativeend); + if (!major) { + Part::GeomLineSegment* lmajor = new Part::GeomLineSegment(); + lmajor->setPoints(majorpositiveend, majornegativeend); - igeo.push_back(lmajor); + igeo.push_back(lmajor); - Sketcher::Constraint* newConstr = new Sketcher::Constraint(); - newConstr->Type = Sketcher::InternalAlignment; - newConstr->AlignmentType = EllipseMajorDiameter; - newConstr->First = currentgeoid + incrgeo + 1; - newConstr->Second = GeoId; + Sketcher::Constraint* newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = EllipseMajorDiameter; + newConstr->First = currentgeoid + incrgeo + 1; + newConstr->Second = GeoId; - icon.push_back(newConstr); - incrgeo++; - } - if (!minor) { - Part::GeomLineSegment* lminor = new Part::GeomLineSegment(); - lminor->setPoints(minorpositiveend, minornegativeend); + icon.push_back(newConstr); + incrgeo++; + } + if (!minor) { + Part::GeomLineSegment* lminor = new Part::GeomLineSegment(); + lminor->setPoints(minorpositiveend, minornegativeend); - igeo.push_back(lminor); + igeo.push_back(lminor); - Sketcher::Constraint* newConstr = new Sketcher::Constraint(); - newConstr->Type = Sketcher::InternalAlignment; - newConstr->AlignmentType = EllipseMinorDiameter; - newConstr->First = currentgeoid + incrgeo + 1; - newConstr->Second = GeoId; + Sketcher::Constraint* newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = EllipseMinorDiameter; + newConstr->First = currentgeoid + incrgeo + 1; + newConstr->Second = GeoId; - icon.push_back(newConstr); - incrgeo++; - } - if (!focus1) { - Part::GeomPoint* pf1 = new Part::GeomPoint(); - pf1->setPoint(focus1P); + icon.push_back(newConstr); + incrgeo++; + } + if (!focus1) { + Part::GeomPoint* pf1 = new Part::GeomPoint(); + pf1->setPoint(focus1P); - igeo.push_back(pf1); + igeo.push_back(pf1); - Sketcher::Constraint* newConstr = new Sketcher::Constraint(); - newConstr->Type = Sketcher::InternalAlignment; - newConstr->AlignmentType = EllipseFocus1; - newConstr->First = currentgeoid + incrgeo + 1; - newConstr->FirstPos = Sketcher::PointPos::start; - newConstr->Second = GeoId; + Sketcher::Constraint* newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = EllipseFocus1; + newConstr->First = currentgeoid + incrgeo + 1; + newConstr->FirstPos = Sketcher::PointPos::start; + newConstr->Second = GeoId; - icon.push_back(newConstr); - incrgeo++; - } - if (!focus2) { - Part::GeomPoint* pf2 = new Part::GeomPoint(); - pf2->setPoint(focus2P); - igeo.push_back(pf2); + icon.push_back(newConstr); + incrgeo++; + } + if (!focus2) { + Part::GeomPoint* pf2 = new Part::GeomPoint(); + pf2->setPoint(focus2P); + igeo.push_back(pf2); - Sketcher::Constraint* newConstr = new Sketcher::Constraint(); - newConstr->Type = Sketcher::InternalAlignment; - newConstr->AlignmentType = EllipseFocus2; - newConstr->First = currentgeoid + incrgeo + 1; - newConstr->FirstPos = Sketcher::PointPos::start; - newConstr->Second = GeoId; + Sketcher::Constraint* newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = EllipseFocus2; + newConstr->First = currentgeoid + incrgeo + 1; + newConstr->FirstPos = Sketcher::PointPos::start; + newConstr->Second = GeoId; - icon.push_back(newConstr); - } + icon.push_back(newConstr); + } + + this->addGeometry(igeo, true); + this->addConstraints(icon); - this->addGeometry(igeo, true); - this->addConstraints(icon); + for (auto& geo : igeo) { + delete geo; + } + + for (auto& con : icon) { + delete con; + } + + return incrgeo;// number of added elements +} - for (std::vector::iterator it = igeo.begin(); it != igeo.end(); ++it) { - if (*it) - delete *it; +// TODO: This is a repeat of ellipse. Can we do some code reuse? +template <> +int SketchObject::exposeInternalGeometryForType(const int GeoId) +{ + const Part::Geometry* geo = getGeometry(GeoId); + // First we search what has to be restored + bool major = false; + bool minor = false; + bool focus1 = false; + bool focus2 = false; + + const std::vector& vals = Constraints.getValues(); + + for (const auto& constr : vals) { + if (constr->Type != Sketcher::InternalAlignment || constr->Second != GeoId) { + continue; } - for (std::vector::iterator it = icon.begin(); it != icon.end(); ++it) { - if (*it) - delete *it; + switch (constr->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; + default: + return -1; } + } - icon.clear(); - igeo.clear(); + int currentgeoid = getHighestCurveIndex(); + int incrgeo = 0; - return incrgeo;// number of added elements + Base::Vector3d center; + double majord; + double minord; + Base::Vector3d majdir; + + std::vector igeo; + std::vector icon; + + const Part::GeomArcOfEllipse* aoe = static_cast(geo); + + center = aoe->getCenter(); + majord = aoe->getMajorRadius(); + minord = aoe->getMinorRadius(); + majdir = aoe->getMajorAxisDir(); + + Base::Vector3d mindir = Vector3d(-majdir.y, majdir.x); + + Base::Vector3d majorpositiveend = center + majord * majdir; + Base::Vector3d majornegativeend = center - majord * majdir; + Base::Vector3d minorpositiveend = center + minord * mindir; + Base::Vector3d minornegativeend = center - minord * mindir; + + double df = sqrt(majord * majord - minord * minord); + + Base::Vector3d focus1P = center + df * majdir; + Base::Vector3d focus2P = center - df * majdir; + + if (!major) { + Part::GeomLineSegment* lmajor = new Part::GeomLineSegment(); + lmajor->setPoints(majorpositiveend, majornegativeend); + + igeo.push_back(lmajor); + + Sketcher::Constraint* newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = EllipseMajorDiameter; + newConstr->First = currentgeoid + incrgeo + 1; + newConstr->Second = GeoId; + + icon.push_back(newConstr); + incrgeo++; } - else if (geo->is()) { - // First we search what has to be restored - bool major = false; - bool minor = false; - bool focus = false; - - const std::vector& vals = Constraints.getValues(); - - for (std::vector::const_iterator it = vals.begin(); it != vals.end(); - ++it) { - if ((*it)->Type == Sketcher::InternalAlignment && (*it)->Second == GeoId) { - switch ((*it)->AlignmentType) { - case Sketcher::HyperbolaMajor: - major = true; - break; - case Sketcher::HyperbolaMinor: - minor = true; - break; - case Sketcher::HyperbolaFocus: - focus = true; - break; - default: - return -1; - } - } - } + if (!minor) { + Part::GeomLineSegment* lminor = new Part::GeomLineSegment(); + lminor->setPoints(minorpositiveend, minornegativeend); - int currentgeoid = getHighestCurveIndex(); - int incrgeo = 0; + igeo.push_back(lminor); - const Part::GeomArcOfHyperbola* aoh = static_cast(geo); + Sketcher::Constraint* newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = EllipseMinorDiameter; + newConstr->First = currentgeoid + incrgeo + 1; + newConstr->Second = GeoId; - Base::Vector3d center = aoh->getCenter(); - double majord = aoh->getMajorRadius(); - double minord = aoh->getMinorRadius(); - Base::Vector3d majdir = aoh->getMajorAxisDir(); + icon.push_back(newConstr); + incrgeo++; + } + if (!focus1) { + Part::GeomPoint* pf1 = new Part::GeomPoint(); + pf1->setPoint(focus1P); - std::vector igeo; - std::vector icon; + igeo.push_back(pf1); - Base::Vector3d mindir = Vector3d(-majdir.y, majdir.x); + Sketcher::Constraint* newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = EllipseFocus1; + newConstr->First = currentgeoid + incrgeo + 1; + newConstr->FirstPos = Sketcher::PointPos::start; + newConstr->Second = GeoId; - Base::Vector3d majorpositiveend = center + majord * majdir; - Base::Vector3d majornegativeend = center - majord * majdir; - Base::Vector3d minorpositiveend = majorpositiveend + minord * mindir; - Base::Vector3d minornegativeend = majorpositiveend - minord * mindir; + icon.push_back(newConstr); + incrgeo++; + } + if (!focus2) { + Part::GeomPoint* pf2 = new Part::GeomPoint(); + pf2->setPoint(focus2P); + igeo.push_back(pf2); - double df = sqrt(majord * majord + minord * minord); + Sketcher::Constraint* newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = EllipseFocus2; + newConstr->First = currentgeoid + incrgeo + 1; + newConstr->FirstPos = Sketcher::PointPos::start; + newConstr->Second = GeoId; - Base::Vector3d focus1P = center + df * majdir; + icon.push_back(newConstr); + } - if (!major) { - Part::GeomLineSegment* lmajor = new Part::GeomLineSegment(); - lmajor->setPoints(majorpositiveend, majornegativeend); + this->addGeometry(igeo, true); + this->addConstraints(icon); - igeo.push_back(lmajor); + for (auto& geo : igeo) { + delete geo; + } - Sketcher::Constraint* newConstr = new Sketcher::Constraint(); - newConstr->Type = Sketcher::InternalAlignment; - newConstr->AlignmentType = Sketcher::HyperbolaMajor; - newConstr->First = currentgeoid + incrgeo + 1; - newConstr->Second = GeoId; + for (auto& con : icon) { + delete con; + } - icon.push_back(newConstr); - incrgeo++; - } - if (!minor) { - Part::GeomLineSegment* lminor = new Part::GeomLineSegment(); - lminor->setPoints(minorpositiveend, minornegativeend); + return incrgeo;// number of added elements - igeo.push_back(lminor); +} - Sketcher::Constraint* newConstr = new Sketcher::Constraint(); - newConstr->Type = Sketcher::InternalAlignment; - newConstr->AlignmentType = Sketcher::HyperbolaMinor; - newConstr->First = currentgeoid + incrgeo + 1; - newConstr->Second = GeoId; +template <> +int SketchObject::exposeInternalGeometryForType(const int GeoId) +{ + const Part::Geometry* geo = getGeometry(GeoId); + // First we search what has to be restored + bool major = false; + bool minor = false; + bool focus = false; - icon.push_back(newConstr); + const std::vector& vals = Constraints.getValues(); - incrgeo++; + for (auto const& constr : vals) { + if (constr->Type != Sketcher::InternalAlignment || constr->Second != GeoId) { + continue; } - if (!focus) { - Part::GeomPoint* pf1 = new Part::GeomPoint(); - pf1->setPoint(focus1P); - igeo.push_back(pf1); + switch (constr->AlignmentType) { + case Sketcher::HyperbolaMajor: + major = true; + break; + case Sketcher::HyperbolaMinor: + minor = true; + break; + case Sketcher::HyperbolaFocus: + focus = true; + break; + default: + return -1; + } + } - Sketcher::Constraint* newConstr = new Sketcher::Constraint(); - newConstr->Type = Sketcher::InternalAlignment; - newConstr->AlignmentType = Sketcher::HyperbolaFocus; - newConstr->First = currentgeoid + incrgeo + 1; - newConstr->FirstPos = Sketcher::PointPos::start; - newConstr->Second = GeoId; + int currentgeoid = getHighestCurveIndex(); + int incrgeo = 0; - icon.push_back(newConstr); - incrgeo++; - } + const Part::GeomArcOfHyperbola* aoh = static_cast(geo); - this->addGeometry(igeo, true); - this->addConstraints(icon); + Base::Vector3d center = aoh->getCenter(); + double majord = aoh->getMajorRadius(); + double minord = aoh->getMinorRadius(); + Base::Vector3d majdir = aoh->getMajorAxisDir(); - for (std::vector::iterator it = igeo.begin(); it != igeo.end(); ++it) - if (*it) - delete *it; + std::vector igeo; + std::vector icon; - for (std::vector::iterator it = icon.begin(); it != icon.end(); ++it) - if (*it) - delete *it; + Base::Vector3d mindir = Vector3d(-majdir.y, majdir.x); - icon.clear(); - igeo.clear(); + Base::Vector3d majorpositiveend = center + majord * majdir; + Base::Vector3d majornegativeend = center - majord * majdir; + Base::Vector3d minorpositiveend = majorpositiveend + minord * mindir; + Base::Vector3d minornegativeend = majorpositiveend - minord * mindir; - return incrgeo;// number of added elements - } - else if (geo->is()) { - // First we search what has to be restored - bool focus = false; - bool focus_to_vertex = false; - - const std::vector& vals = Constraints.getValues(); - - for (std::vector::const_iterator it = vals.begin(); it != vals.end(); - ++it) { - if ((*it)->Type == Sketcher::InternalAlignment && (*it)->Second == GeoId) { - switch ((*it)->AlignmentType) { - case Sketcher::ParabolaFocus: - focus = true; - break; - case Sketcher::ParabolaFocalAxis: - focus_to_vertex = true; - break; - default: - return -1; - } - } - } + double df = sqrt(majord * majord + minord * minord); - int currentgeoid = getHighestCurveIndex(); - int incrgeo = 0; + Base::Vector3d focus1P = center + df * majdir; - const Part::GeomArcOfParabola* aop = static_cast(geo); + if (!major) { + Part::GeomLineSegment* lmajor = new Part::GeomLineSegment(); + lmajor->setPoints(majorpositiveend, majornegativeend); - Base::Vector3d center = aop->getCenter(); - Base::Vector3d focusp = aop->getFocus(); + igeo.push_back(lmajor); - std::vector igeo; - std::vector icon; + Sketcher::Constraint* newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = Sketcher::HyperbolaMajor; + newConstr->First = currentgeoid + incrgeo + 1; + newConstr->Second = GeoId; - if (!focus) { - Part::GeomPoint* pf1 = new Part::GeomPoint(); - pf1->setPoint(focusp); + icon.push_back(newConstr); + incrgeo++; + } + if (!minor) { + Part::GeomLineSegment* lminor = new Part::GeomLineSegment(); + lminor->setPoints(minorpositiveend, minornegativeend); - igeo.push_back(pf1); + igeo.push_back(lminor); - Sketcher::Constraint* newConstr = new Sketcher::Constraint(); - newConstr->Type = Sketcher::InternalAlignment; - newConstr->AlignmentType = Sketcher::ParabolaFocus; - newConstr->First = currentgeoid + incrgeo + 1; - newConstr->FirstPos = Sketcher::PointPos::start; - newConstr->Second = GeoId; + Sketcher::Constraint* newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = Sketcher::HyperbolaMinor; + newConstr->First = currentgeoid + incrgeo + 1; + newConstr->Second = GeoId; - icon.push_back(newConstr); - incrgeo++; - } + icon.push_back(newConstr); - if (!focus_to_vertex) { - Part::GeomLineSegment* paxis = new Part::GeomLineSegment(); - paxis->setPoints(center, focusp); + incrgeo++; + } + if (!focus) { + Part::GeomPoint* pf1 = new Part::GeomPoint(); + pf1->setPoint(focus1P); - igeo.push_back(paxis); + igeo.push_back(pf1); - Sketcher::Constraint* newConstr = new Sketcher::Constraint(); - newConstr->Type = Sketcher::InternalAlignment; - newConstr->AlignmentType = Sketcher::ParabolaFocalAxis; - newConstr->First = currentgeoid + incrgeo + 1; - newConstr->FirstPos = Sketcher::PointPos::none; - newConstr->Second = GeoId; + Sketcher::Constraint* newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = Sketcher::HyperbolaFocus; + newConstr->First = currentgeoid + incrgeo + 1; + newConstr->FirstPos = Sketcher::PointPos::start; + newConstr->Second = GeoId; - icon.push_back(newConstr); + icon.push_back(newConstr); + incrgeo++; + } - incrgeo++; - } + this->addGeometry(igeo, true); + this->addConstraints(icon); + + for (auto& geo : igeo) { + delete geo; + } + + for (auto& con : icon) { + delete con; + } - this->addGeometry(igeo, true); - this->addConstraints(icon); + return incrgeo;// number of added elements +} + +template <> +int SketchObject::exposeInternalGeometryForType(const int GeoId) +{ + const Part::Geometry* geo = getGeometry(GeoId); + // First we search what has to be restored + bool focus = false; + bool focus_to_vertex = false; - for (std::vector::iterator it = igeo.begin(); it != igeo.end(); ++it) { - if (*it) - delete *it; + const std::vector& vals = Constraints.getValues(); + + for (auto const& constr : vals) { + if (constr->Type != Sketcher::InternalAlignment || constr->Second != GeoId) { + continue; } - for (std::vector::iterator it = icon.begin(); it != icon.end(); ++it) { - if (*it) - delete *it; + switch (constr->AlignmentType) { + case Sketcher::ParabolaFocus: + focus = true; + break; + case Sketcher::ParabolaFocalAxis: + focus_to_vertex = true; + break; + default: + return -1; } + } + + int currentgeoid = getHighestCurveIndex(); + int incrgeo = 0; + + const Part::GeomArcOfParabola* aop = static_cast(geo); + + Base::Vector3d center = aop->getCenter(); + Base::Vector3d focusp = aop->getFocus(); - icon.clear(); - igeo.clear(); + std::vector igeo; + std::vector icon; - return incrgeo;// number of added elements + if (!focus) { + Part::GeomPoint* pf1 = new Part::GeomPoint(); + pf1->setPoint(focusp); + + igeo.push_back(pf1); + + Sketcher::Constraint* newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = Sketcher::ParabolaFocus; + newConstr->First = currentgeoid + incrgeo + 1; + newConstr->FirstPos = Sketcher::PointPos::start; + newConstr->Second = GeoId; + + icon.push_back(newConstr); + incrgeo++; } - else if (geo->is()) { - const Part::GeomBSplineCurve* bsp = static_cast(geo); - // First we search what has to be restored - std::vector controlpoints(bsp->countPoles()); - std::vector controlpointgeoids(bsp->countPoles()); + if (!focus_to_vertex) { + Part::GeomLineSegment* paxis = new Part::GeomLineSegment(); + paxis->setPoints(center, focusp); - std::vector knotpoints(bsp->countKnots()); - std::vector knotgeoids(bsp->countKnots()); + igeo.push_back(paxis); - bool isfirstweightconstrained = false; + Sketcher::Constraint* newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = Sketcher::ParabolaFocalAxis; + newConstr->First = currentgeoid + incrgeo + 1; + newConstr->FirstPos = Sketcher::PointPos::none; + newConstr->Second = GeoId; - std::vector::iterator itb; - std::vector::iterator it; + icon.push_back(newConstr); - for (it = controlpointgeoids.begin(), itb = controlpoints.begin(); - it != controlpointgeoids.end() && itb != controlpoints.end(); - ++it, ++itb) { - (*it) = -1; - (*itb) = false; - } + incrgeo++; + } - for (it = knotgeoids.begin(), itb = knotpoints.begin(); - it != knotgeoids.end() && itb != knotpoints.end(); - ++it, ++itb) { - (*it) = -1; - (*itb) = false; - } + this->addGeometry(igeo, true); + this->addConstraints(icon); - const std::vector& vals = Constraints.getValues(); + for (auto& geo : igeo) { + delete geo; + } - // search for existing poles - for (std::vector::const_iterator it = vals.begin(); it != vals.end(); - ++it) { - if ((*it)->Type == Sketcher::InternalAlignment && (*it)->Second == GeoId) { - switch ((*it)->AlignmentType) { - case Sketcher::BSplineControlPoint: - controlpoints[(*it)->InternalAlignmentIndex] = true; - controlpointgeoids[(*it)->InternalAlignmentIndex] = (*it)->First; - break; - case Sketcher::BSplineKnotPoint: - knotpoints[(*it)->InternalAlignmentIndex] = true; - knotgeoids[(*it)->InternalAlignmentIndex] = (*it)->First; - break; - default: - return -1; - } - } + for (auto& con : icon) { + delete con; + } + + return incrgeo;// number of added elements +} + +template <> +int SketchObject::exposeInternalGeometryForType(const int GeoId) +{ + const Part::Geometry* geo = getGeometry(GeoId); + + const Part::GeomBSplineCurve* bsp = static_cast(geo); + // First we search what has to be restored + std::vector controlpointgeoids(bsp->countPoles(), GeoEnum::GeoUndef); + + std::vector knotgeoids(bsp->countKnots(), GeoEnum::GeoUndef); + + bool isfirstweightconstrained = false; + + std::vector::iterator it; + + const std::vector& vals = Constraints.getValues(); + + // search for existing poles + for (auto const& constr : vals) { + if (constr->Type != Sketcher::InternalAlignment || constr->Second != GeoId) { + continue; } - if (controlpoints[0]) { - // search for first pole weight constraint - for (std::vector::const_iterator it = vals.begin(); - it != vals.end(); - ++it) { - if ((*it)->Type == Sketcher::Weight && (*it)->First == controlpointgeoids[0]) { - isfirstweightconstrained = true; - } - } + switch (constr->AlignmentType) { + case Sketcher::BSplineControlPoint: + controlpointgeoids[constr->InternalAlignmentIndex] = constr->First; + break; + case Sketcher::BSplineKnotPoint: + knotgeoids[constr->InternalAlignmentIndex] = constr->First; + break; + default: + return -1; } + } - int currentgeoid = getHighestCurveIndex(); - int incrgeo = 0; + if (controlpointgeoids[0] != GeoEnum::GeoUndef) { + // search for first pole weight constraint + auto it = std::find_if(vals.begin(), + vals.end(), + [&controlpointgeoids](const auto& constr) {return (constr->Type == Sketcher::Weight && constr->First == controlpointgeoids[0]);}); + isfirstweightconstrained = (it != vals.end()); + } - std::vector igeo; - std::vector icon; + int currentgeoid = getHighestCurveIndex(); + int incrgeo = 0; - std::vector poles = bsp->getPoles(); - std::vector weights = bsp->getWeights(); - std::vector knots = bsp->getKnots(); + std::vector igeo; + std::vector icon; - double distance_p0_p1 = (poles[1] - poles[0]).Length();// for visual purposes only + std::vector poles = bsp->getPoles(); + std::vector weights = bsp->getWeights(); + std::vector knots = bsp->getKnots(); - int index = 0; + double distance_p0_p1 = (poles[1] - poles[0]).Length();// for visual purposes only - for (it = controlpointgeoids.begin(), itb = controlpoints.begin(); - it != controlpointgeoids.end() && itb != controlpoints.end(); - ++it, ++itb, index++) { + for (size_t index = 0; index < controlpointgeoids.size(); ++index) { + auto& cpGeoId = controlpointgeoids.at(index); + if (cpGeoId != GeoEnum::GeoUndef) { + continue; + } - if (!(*itb))// if controlpoint not existing - { - Part::GeomCircle* pc = new Part::GeomCircle(); - pc->setCenter(poles[index]); - pc->setRadius(distance_p0_p1 / 6); - - igeo.push_back(pc); - - Sketcher::Constraint* newConstr = new Sketcher::Constraint(); - newConstr->Type = Sketcher::InternalAlignment; - newConstr->AlignmentType = Sketcher::BSplineControlPoint; - newConstr->First = currentgeoid + incrgeo + 1; - newConstr->FirstPos = Sketcher::PointPos::mid; - newConstr->Second = GeoId; - newConstr->InternalAlignmentIndex = index; - - icon.push_back(newConstr); - - if (it != controlpointgeoids.begin()) { - if (isfirstweightconstrained && weights[0] == weights[index]) { - // if pole-weight newly created AND first weight is radius-constrained, - // AND these weights are equal, constrain them to be equal - Sketcher::Constraint* newConstr2 = new Sketcher::Constraint(); - newConstr2->Type = Sketcher::Equal; - newConstr2->First = currentgeoid + incrgeo + 1; - newConstr2->FirstPos = Sketcher::PointPos::none; - newConstr2->Second = controlpointgeoids[0]; - newConstr2->SecondPos = Sketcher::PointPos::none; - - icon.push_back(newConstr2); - } - } - else { - controlpointgeoids[0] = currentgeoid + incrgeo + 1; - if (weights[0] == 1.0) { - // if the first weight is 1.0 it's probably going to be non-rational - Sketcher::Constraint* newConstr3 = new Sketcher::Constraint(); - newConstr3->Type = Sketcher::Weight; - newConstr3->First = controlpointgeoids[0]; - newConstr3->setValue(weights[0]); + // if controlpoint not existing + Part::GeomCircle* pc = new Part::GeomCircle(); + pc->setCenter(poles[index]); + pc->setRadius(distance_p0_p1 / 6); - icon.push_back(newConstr3); + igeo.push_back(pc); + incrgeo++; - isfirstweightconstrained = true; - } - } - incrgeo++; + Sketcher::Constraint* newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = Sketcher::BSplineControlPoint; + newConstr->First = currentgeoid + incrgeo; + newConstr->FirstPos = Sketcher::PointPos::mid; + newConstr->Second = GeoId; + newConstr->InternalAlignmentIndex = index; + + icon.push_back(newConstr); + + if (index == 0) { + controlpointgeoids[0] = currentgeoid + incrgeo; + if (weights[0] == 1.0) { + // if the first weight is 1.0 it's probably going to be non-rational + Sketcher::Constraint* newConstr3 = new Sketcher::Constraint(); + newConstr3->Type = Sketcher::Weight; + newConstr3->First = controlpointgeoids[0]; + newConstr3->setValue(weights[0]); + + icon.push_back(newConstr3); + + isfirstweightconstrained = true; } + + continue; } - index = 0; + if (isfirstweightconstrained && weights[0] == weights[index]) { + // if pole-weight newly created AND first weight is radius-constrained, + // AND these weights are equal, constrain them to be equal + Sketcher::Constraint* newConstr2 = new Sketcher::Constraint(); + newConstr2->Type = Sketcher::Equal; + newConstr2->First = currentgeoid + incrgeo; + newConstr2->FirstPos = Sketcher::PointPos::none; + newConstr2->Second = controlpointgeoids[0]; + newConstr2->SecondPos = Sketcher::PointPos::none; - for (it = knotgeoids.begin(), itb = knotpoints.begin(); - it != knotgeoids.end() && itb != knotpoints.end(); - ++it, ++itb, index++) { + icon.push_back(newConstr2); + } + } - if (!(*itb))// if knot point not existing - { - Part::GeomPoint* kp = new Part::GeomPoint(); + for (size_t index = 0; index < knotgeoids.size(); ++index) { + auto& kGeoId = knotgeoids.at(index); + if (kGeoId != GeoEnum::GeoUndef) { + continue; + } - kp->setPoint(bsp->pointAtParameter(knots[index])); + // if knot point not existing + Part::GeomPoint* kp = new Part::GeomPoint(); - igeo.push_back(kp); + kp->setPoint(bsp->pointAtParameter(knots[index])); - Sketcher::Constraint* newConstr = new Sketcher::Constraint(); - newConstr->Type = Sketcher::InternalAlignment; - newConstr->AlignmentType = Sketcher::BSplineKnotPoint; - newConstr->First = currentgeoid + incrgeo + 1; - newConstr->FirstPos = Sketcher::PointPos::start; - newConstr->Second = GeoId; - newConstr->InternalAlignmentIndex = index; + igeo.push_back(kp); + incrgeo++; - icon.push_back(newConstr); + Sketcher::Constraint* newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = Sketcher::BSplineKnotPoint; + newConstr->First = currentgeoid + incrgeo; + newConstr->FirstPos = Sketcher::PointPos::start; + newConstr->Second = GeoId; + newConstr->InternalAlignmentIndex = index; - incrgeo++; - } - } + icon.push_back(newConstr); + } + + Q_UNUSED(isfirstweightconstrained); - Q_UNUSED(isfirstweightconstrained); + this->addGeometry(igeo, true); + this->addConstraints(icon); - this->addGeometry(igeo, true); - this->addConstraints(icon); + for (auto& geo : igeo) { + delete geo; + } - for (std::vector::iterator it = igeo.begin(); it != igeo.end(); ++it) - if (*it) - delete *it; + for (auto& con : icon) { + delete con; + } - for (std::vector::iterator it = icon.begin(); it != icon.end(); ++it) - if (*it) - delete *it; + return incrgeo;// number of added elements +} - icon.clear(); - igeo.clear(); +int SketchObject::exposeInternalGeometry(int GeoId) +{ + if (GeoId < 0 || GeoId > getHighestCurveIndex()) + return -1; - return incrgeo;// number of added elements + const Part::Geometry* geo = getGeometry(GeoId); + // Only for supported types + if (geo->is()) { + return exposeInternalGeometryForType(GeoId); + } + else if (geo->is()) { + return exposeInternalGeometryForType(GeoId); + } + else if (geo->is()) { + return exposeInternalGeometryForType(GeoId); + } + else if (geo->is()) { + return exposeInternalGeometryForType(GeoId); + } + else if (geo->is()) { + return exposeInternalGeometryForType(GeoId); } else return -1;// not supported type @@ -6639,289 +6763,260 @@ int SketchObject::deleteUnusedInternalGeometry(int GeoId, bool delgeoid) if (geo->is() || geo->is() || geo->is()) { + return deleteUnusedInternalGeometryWhenTwoFoci(GeoId, delgeoid); + } - int majorelementindex = -1; - int minorelementindex = -1; - int focus1elementindex = -1; - int focus2elementindex = -1; + if (geo->is()) { + return deleteUnusedInternalGeometryWhenOneFocus(GeoId, delgeoid); + } - const std::vector& vals = Constraints.getValues(); + if (geo->is()) { + return deleteUnusedInternalGeometryWhenBSpline(GeoId, delgeoid); + } - for (std::vector::const_iterator it = vals.begin(); it != vals.end(); - ++it) { - if ((*it)->Type == Sketcher::InternalAlignment && (*it)->Second == GeoId) { - switch ((*it)->AlignmentType) { - case Sketcher::EllipseMajorDiameter: - case Sketcher::HyperbolaMajor: - majorelementindex = (*it)->First; - break; - case Sketcher::EllipseMinorDiameter: - case Sketcher::HyperbolaMinor: - minorelementindex = (*it)->First; - break; - case Sketcher::EllipseFocus1: - case Sketcher::HyperbolaFocus: - focus1elementindex = (*it)->First; - break; - case Sketcher::EllipseFocus2: - focus2elementindex = (*it)->First; - break; - default: - return -1; - } - } - } + // Default case: type not supported + return -1; +} - // Hide unused geometry here - int majorconstraints = 0;// number of constraints associated to the geoid of the major axis - int minorconstraints = 0; - int focus1constraints = 0; - int focus2constraints = 0; +int SketchObject::deleteUnusedInternalGeometryWhenTwoFoci(int GeoId, bool delgeoid) +{ + int majorelementindex = -1; + int minorelementindex = -1; + int focus1elementindex = -1; + int focus2elementindex = -1; - for (std::vector::const_iterator it = vals.begin(); it != vals.end(); - ++it) { + const std::vector& vals = Constraints.getValues(); - 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++; + for (auto const& constr : vals) { + if (constr->Type != Sketcher::InternalAlignment || constr->Second != GeoId) { + continue; } - std::vector delgeometries; + switch (constr->AlignmentType) { + case Sketcher::EllipseMajorDiameter: + case Sketcher::HyperbolaMajor: + majorelementindex = constr->First; + break; + case Sketcher::EllipseMinorDiameter: + case Sketcher::HyperbolaMinor: + minorelementindex = constr->First; + break; + case Sketcher::EllipseFocus1: + case Sketcher::HyperbolaFocus: + focus1elementindex = constr->First; + break; + case Sketcher::EllipseFocus2: + focus2elementindex = constr->First; + break; + default: + return -1; + } + } - // those with less than 2 constraints must be removed - if (focus2constraints < 2) - delgeometries.push_back(focus2elementindex); + // 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; - if (focus1constraints < 2) - delgeometries.push_back(focus1elementindex); + for (const auto& constr : vals) { + if (constr->involvesGeoId(majorelementindex)) + majorconstraints++; + else if (constr->involvesGeoId(minorelementindex)) + minorconstraints++; + else if (constr->involvesGeoId(focus1elementindex)) + focus1constraints++; + else if (constr->involvesGeoId(focus2elementindex)) + focus2constraints++; + } - if (minorconstraints < 2) - delgeometries.push_back(minorelementindex); + std::vector delgeometries; - if (majorconstraints < 2) - delgeometries.push_back(majorelementindex); + // those with less than 2 constraints must be removed + if (focus2constraints < 2) + delgeometries.push_back(focus2elementindex); - if (delgeoid) - delgeometries.push_back(GeoId); + if (focus1constraints < 2) + delgeometries.push_back(focus1elementindex); - // indices over an erased element get automatically updated!! - std::sort(delgeometries.begin(), delgeometries.end()); + if (minorconstraints < 2) + delgeometries.push_back(minorelementindex); - if (!delgeometries.empty()) { - for (std::vector::reverse_iterator it = delgeometries.rbegin(); - it != delgeometries.rend(); - ++it) { - delGeometry(*it, false); - } - } + if (majorconstraints < 2) + delgeometries.push_back(majorelementindex); - int ndeleted = delgeometries.size(); + if (delgeoid) + delgeometries.push_back(GeoId); - delgeometries.clear(); + // indices over an erased element get automatically updated!! + std::sort(delgeometries.begin(), delgeometries.end(), std::greater<>()); - return ndeleted;// number of deleted elements + for (auto& dGeoId : delgeometries) { + delGeometry(dGeoId, false); } - else if (geo->is()) { - // if the focus-to-vertex line is constrained, then never delete the focus - // if the line is unconstrained, then the line may be deleted, - // in this case the focus may be deleted if unconstrained. - int majorelementindex = -1; - int focus1elementindex = -1; - - const std::vector& vals = Constraints.getValues(); - - for (std::vector::const_iterator it = vals.begin(); it != vals.end(); - ++it) { - if ((*it)->Type == Sketcher::InternalAlignment && (*it)->Second == GeoId) { - switch ((*it)->AlignmentType) { - case Sketcher::ParabolaFocus: - focus1elementindex = (*it)->First; - break; - case Sketcher::ParabolaFocalAxis: - majorelementindex = (*it)->First; - break; - default: - return -1; - } - } - } - // Hide unused geometry here - // number of constraints associated to the geoid of the major axis other than the coincident - // ones - int majorconstraints = 0; - int focus1constraints = 0; + int ndeleted = delgeometries.size(); - for (std::vector::const_iterator it = vals.begin(); it != vals.end(); - ++it) { - if ((*it)->Second == majorelementindex || (*it)->First == majorelementindex - || (*it)->Third == majorelementindex) - majorconstraints++; - else if ((*it)->Second == focus1elementindex || (*it)->First == focus1elementindex - || (*it)->Third == focus1elementindex) - focus1constraints++; - } + return ndeleted;// number of deleted elements +} - std::vector delgeometries; +int SketchObject::deleteUnusedInternalGeometryWhenOneFocus(int GeoId, bool delgeoid) +{ + // if the focus-to-vertex line is constrained, then never delete the focus + // if the line is unconstrained, then the line may be deleted, + // in this case the focus may be deleted if unconstrained. + int majorelementindex = -1; + int focus1elementindex = -1; - // major has minimum one constraint, the specific internal alignment constraint - if (majorelementindex != -1 && majorconstraints < 2) - delgeometries.push_back(majorelementindex); + const std::vector& vals = Constraints.getValues(); - // focus has minimum one constraint now, the specific internal alignment constraint - if (focus1elementindex != -1 && focus1constraints < 2) - delgeometries.push_back(focus1elementindex); + for (auto const& constr : vals) { + if (constr->Type != Sketcher::InternalAlignment || constr->Second != GeoId) { + continue; + } - if (delgeoid) - delgeometries.push_back(GeoId); + switch (constr->AlignmentType) { + case Sketcher::ParabolaFocus: + focus1elementindex = constr->First; + break; + case Sketcher::ParabolaFocalAxis: + majorelementindex = constr->First; + break; + default: + return -1; + } + } - // indices over an erased element get automatically updated!! - std::sort(delgeometries.begin(), delgeometries.end()); + // Hide unused geometry here + // number of constraints associated to the geoid of the major axis other than the coincident + // ones + int majorconstraints = 0; + int focus1constraints = 0; - if (!delgeometries.empty()) { - for (std::vector::reverse_iterator it = delgeometries.rbegin(); - it != delgeometries.rend(); - ++it) { - delGeometry(*it, false); - } + for (const auto& constr : vals) { + if (constr->involvesGeoId(majorelementindex)) { + majorconstraints++; + } + else if (constr->involvesGeoId(focus1elementindex)) { + focus1constraints++; } + } - int ndeleted = delgeometries.size(); + std::vector delgeometries; - delgeometries.clear(); + // major has minimum one constraint, the specific internal alignment constraint + if (majorelementindex != -1 && majorconstraints < 2) + delgeometries.push_back(majorelementindex); - return ndeleted;// number of deleted elements - } - else if (geo->is()) { + // focus has minimum one constraint now, the specific internal alignment constraint + if (focus1elementindex != -1 && focus1constraints < 2) + delgeometries.push_back(focus1elementindex); - const Part::GeomBSplineCurve* bsp = static_cast(geo); + if (delgeoid) + delgeometries.push_back(GeoId); - // First we search existing IA - std::vector controlpointgeoids(bsp->countPoles()); - std::vector cpassociatedconstraints(bsp->countPoles()); + // indices over an erased element get automatically updated!! + std::sort(delgeometries.begin(), delgeometries.end(), std::greater<>()); - std::vector knotgeoids(bsp->countKnots()); - std::vector kassociatedconstraints(bsp->countKnots()); + for (auto& dGeoId : delgeometries) { + delGeometry(dGeoId, false); + } - std::vector::iterator it; - std::vector::iterator ita; + int ndeleted = delgeometries.size(); - for (it = controlpointgeoids.begin(), ita = cpassociatedconstraints.begin(); - it != controlpointgeoids.end() && ita != cpassociatedconstraints.end(); - ++it, ++ita) { - (*it) = -1; - (*ita) = 0; - } + delgeometries.clear(); - for (it = knotgeoids.begin(), ita = kassociatedconstraints.begin(); - it != knotgeoids.end() && ita != kassociatedconstraints.end(); - ++it, ++ita) { - (*it) = -1; - (*ita) = 0; - } + return ndeleted;// number of deleted elements +} - const std::vector& vals = Constraints.getValues(); +int SketchObject::deleteUnusedInternalGeometryWhenBSpline(int GeoId, bool delgeoid) +{ + const Part::GeomBSplineCurve* bsp = static_cast(getGeometry(GeoId)); - // search for existing poles - for (std::vector::const_iterator jt = vals.begin(); jt != vals.end(); - ++jt) { - if ((*jt)->Type == Sketcher::InternalAlignment && (*jt)->Second == GeoId) { - switch ((*jt)->AlignmentType) { - case Sketcher::BSplineControlPoint: - controlpointgeoids[(*jt)->InternalAlignmentIndex] = (*jt)->First; - break; - case Sketcher::BSplineKnotPoint: - knotgeoids[(*jt)->InternalAlignmentIndex] = (*jt)->First; - break; - default: - return -1; - } - } - } + // First we search existing IA + std::vector > poleGeoIdsAndConstraints(bsp->countPoles(), {GeoEnum::GeoUndef, 0}); - std::vector delgeometries; + std::vector > knotGeoIdsAndConstraints(bsp->countKnots(), {GeoEnum::GeoUndef, 0}); - for (it = controlpointgeoids.begin(), ita = cpassociatedconstraints.begin(); - it != controlpointgeoids.end() && ita != cpassociatedconstraints.end(); - ++it, ++ita) { - if ((*it) != -1) { - // look for a circle at geoid index - for (std::vector::const_iterator itc = vals.begin(); - itc != vals.end(); - ++itc) { + const std::vector& vals = Constraints.getValues(); - if ((*itc)->Type == Sketcher::Equal) { - bool f = false, s = false; - for (std::vector::iterator its = controlpointgeoids.begin(); - its != controlpointgeoids.end(); - ++its) { - if ((*itc)->First == *its) { - f = true; - } - else if ((*itc)->Second == *its) { - s = true; - } + // search for existing poles + for (auto const& constr : vals) { + if (constr->Type != Sketcher::InternalAlignment || constr->Second != GeoId) { + continue; + } - if (f && s) {// the equality constraint is not interpole - break; - } - } + switch (constr->AlignmentType) { + case Sketcher::BSplineControlPoint: + poleGeoIdsAndConstraints[constr->InternalAlignmentIndex].first = constr->First; + break; + case Sketcher::BSplineKnotPoint: + knotGeoIdsAndConstraints[constr->InternalAlignmentIndex].first = constr->First; + break; + default: + return -1; + } + } - // the equality constraint constraints a pole but it is not interpole - if (f != s) { - (*ita)++; - } - } - // We do not ignore weight constraints as we did with radius constraints, - // because the radius magnitude no longer makes sense without the B-Spline. - } + std::vector delgeometries; - if ((*ita) < 2) {// IA - delgeometries.push_back((*it)); - } - } + for (auto& [cpGeoId, numConstr] : poleGeoIdsAndConstraints) { + if (cpGeoId == GeoEnum::GeoUndef) { + continue; } - for (it = knotgeoids.begin(), ita = kassociatedconstraints.begin(); - it != knotgeoids.end() && ita != kassociatedconstraints.end(); - ++it, ++ita) { - if ((*it) != -1) { - // look for a point at geoid index - for (std::vector::const_iterator itc = vals.begin(); - itc != vals.end(); - ++itc) { - if ((*itc)->Second == (*it) || (*itc)->First == (*it) - || (*itc)->Third == (*it)) { - (*ita)++; - } - } + // look for a circle at geoid index + for (auto const& constr : vals) { + if (constr->Type != Sketcher::Equal) { + continue; + } - if ((*ita) < 2) {// IA - delgeometries.push_back((*it)); - } + bool firstIsInCPGeoIds = std::find_if(poleGeoIdsAndConstraints.begin(), + poleGeoIdsAndConstraints.end(), + [&constr](const auto& _pair) { + return _pair.first == constr->First; + }) != poleGeoIdsAndConstraints.end(); + bool secondIsInCPGeoIds = std::find_if(poleGeoIdsAndConstraints.begin(), + poleGeoIdsAndConstraints.end(), + [&constr](const auto& _pair){ + return _pair.first == constr->Second; + }) != poleGeoIdsAndConstraints.end(); + + // the equality constraint constrains a pole but it is not interpole + if (firstIsInCPGeoIds != secondIsInCPGeoIds) { + numConstr++; } + // We do not ignore weight constraints as we did with radius constraints, + // because the radius magnitude no longer makes sense without the B-Spline. } + if (numConstr < 2) { // IA + delgeometries.push_back(cpGeoId); + } + } - if (delgeoid) - delgeometries.push_back(GeoId); + for (auto& [kGeoId, numConstr] : knotGeoIdsAndConstraints) { + if (kGeoId == GeoEnum::GeoUndef) { + continue; + } - int ndeleted = delGeometriesExclusiveList(delgeometries); + // look for a point at geoid index + numConstr = std::count_if(vals.begin(), vals.end(), [&kGeoId](const auto& constr) { + return constr->involvesGeoId(kGeoId); + }); - return ndeleted;// number of deleted elements + if (numConstr < 2) { // IA + delgeometries.push_back(kGeoId); + } } - else { - return -1;// not supported type + + if (delgeoid) { + delgeometries.push_back(GeoId); } + + int ndeleted = delGeometriesExclusiveList(delgeometries); + + return ndeleted;// number of deleted elements } int SketchObject::deleteUnusedInternalGeometryAndUpdateGeoId(int& GeoId, bool delgeoid) diff --git a/src/Mod/Sketcher/App/SketchObject.h b/src/Mod/Sketcher/App/SketchObject.h index 62a13821ddf8..09aca4d269f6 100644 --- a/src/Mod/Sketcher/App/SketchObject.h +++ b/src/Mod/Sketcher/App/SketchObject.h @@ -482,6 +482,11 @@ class SketcherExport SketchObject: public Part::Part2DObject * \return -1 on error */ int exposeInternalGeometry(int GeoId); + template + int exposeInternalGeometryForType([[maybe_unused]] const int GeoId) + { + return -1; // By default internal geometry is not supported + } /*! \brief Deletes all unused (not further constrained) internal geometry \param GeoId - the geometry having the internal geometry to delete @@ -899,6 +904,15 @@ class SketcherExport SketchObject: public Part::Part2DObject void buildShape(); /// get called by the container when a property has changed void onChanged(const App::Property* /*prop*/) override; + + /// Helper functions for `deleteUnusedInternalGeometry` by cases + /// two foci for ellipses and arcs of ellipses and hyperbolas + int deleteUnusedInternalGeometryWhenTwoFoci(int GeoId, bool delgeoid = false); + /// one focus for parabolas + int deleteUnusedInternalGeometryWhenOneFocus(int GeoId, bool delgeoid = false); + /// b-splines need their own treatment + int deleteUnusedInternalGeometryWhenBSpline(int GeoId, bool delgeoid = false); + void onDocumentRestored() override; void restoreFinished() override;