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 | 1691 +++++++++++++------------ src/Mod/Sketcher/App/SketchObject.h | 14 + 2 files changed, 907 insertions(+), 798 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 4cc9f34867..9b2acf87d7 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -6090,6 +6090,643 @@ int SketchObject::removeAxesAlignment(const std::vector& geoIdList) return 0; } +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; + } + + 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; + } + } + + int currentgeoid = getHighestCurveIndex(); + int incrgeo = 0; + + Base::Vector3d center; + double majord; + double minord; + Base::Vector3d majdir; + + std::vector igeo; + std::vector icon; + + const Part::GeomEllipse* ellipse = static_cast(geo); + + center = ellipse->getCenter(); + majord = ellipse->getMajorRadius(); + minord = ellipse->getMinorRadius(); + majdir = ellipse->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++; + } + if (!minor) { + Part::GeomLineSegment* lminor = new Part::GeomLineSegment(); + lminor->setPoints(minorpositiveend, minornegativeend); + + 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; + + icon.push_back(newConstr); + incrgeo++; + } + if (!focus1) { + Part::GeomPoint* pf1 = new Part::GeomPoint(); + pf1->setPoint(focus1P); + + 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; + + 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; + + icon.push_back(newConstr); + } + + 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 +} + +// 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; + } + + 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; + } + } + + int currentgeoid = getHighestCurveIndex(); + int incrgeo = 0; + + 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++; + } + if (!minor) { + Part::GeomLineSegment* lminor = new Part::GeomLineSegment(); + lminor->setPoints(minorpositiveend, minornegativeend); + + 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; + + icon.push_back(newConstr); + incrgeo++; + } + if (!focus1) { + Part::GeomPoint* pf1 = new Part::GeomPoint(); + pf1->setPoint(focus1P); + + 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; + + 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; + + icon.push_back(newConstr); + } + + 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 + +} + +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; + + const std::vector& vals = Constraints.getValues(); + + for (auto const& constr : vals) { + if (constr->Type != Sketcher::InternalAlignment || constr->Second != GeoId) { + continue; + } + + switch (constr->AlignmentType) { + case Sketcher::HyperbolaMajor: + major = true; + break; + case Sketcher::HyperbolaMinor: + minor = true; + break; + case Sketcher::HyperbolaFocus: + focus = true; + break; + default: + return -1; + } + } + + int currentgeoid = getHighestCurveIndex(); + int incrgeo = 0; + + const Part::GeomArcOfHyperbola* aoh = static_cast(geo); + + Base::Vector3d center = aoh->getCenter(); + double majord = aoh->getMajorRadius(); + double minord = aoh->getMinorRadius(); + Base::Vector3d majdir = aoh->getMajorAxisDir(); + + std::vector igeo; + std::vector icon; + + Base::Vector3d mindir = Vector3d(-majdir.y, majdir.x); + + Base::Vector3d majorpositiveend = center + majord * majdir; + Base::Vector3d majornegativeend = center - majord * majdir; + Base::Vector3d minorpositiveend = majorpositiveend + minord * mindir; + Base::Vector3d minornegativeend = majorpositiveend - minord * mindir; + + double df = sqrt(majord * majord + minord * minord); + + Base::Vector3d focus1P = 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 = Sketcher::HyperbolaMajor; + 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); + + 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; + + icon.push_back(newConstr); + + incrgeo++; + } + if (!focus) { + Part::GeomPoint* pf1 = new Part::GeomPoint(); + pf1->setPoint(focus1P); + + igeo.push_back(pf1); + + 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); + incrgeo++; + } + + 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 +} + +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; + + const std::vector& vals = Constraints.getValues(); + + for (auto const& constr : vals) { + if (constr->Type != Sketcher::InternalAlignment || constr->Second != GeoId) { + continue; + } + + 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(); + + std::vector igeo; + std::vector icon; + + 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++; + } + + if (!focus_to_vertex) { + Part::GeomLineSegment* paxis = new Part::GeomLineSegment(); + paxis->setPoints(center, focusp); + + igeo.push_back(paxis); + + 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; + + icon.push_back(newConstr); + + incrgeo++; + } + + 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 +} + +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; + } + + switch (constr->AlignmentType) { + case Sketcher::BSplineControlPoint: + controlpointgeoids[constr->InternalAlignmentIndex] = constr->First; + break; + case Sketcher::BSplineKnotPoint: + knotgeoids[constr->InternalAlignmentIndex] = constr->First; + break; + default: + return -1; + } + } + + 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()); + } + + int currentgeoid = getHighestCurveIndex(); + int incrgeo = 0; + + std::vector igeo; + std::vector icon; + + std::vector poles = bsp->getPoles(); + std::vector weights = bsp->getWeights(); + std::vector knots = bsp->getKnots(); + + double distance_p0_p1 = (poles[1] - poles[0]).Length();// for visual purposes only + + for (size_t index = 0; index < controlpointgeoids.size(); ++index) { + auto& cpGeoId = controlpointgeoids.at(index); + if (cpGeoId != GeoEnum::GeoUndef) { + continue; + } + + // if controlpoint not existing + Part::GeomCircle* pc = new Part::GeomCircle(); + pc->setCenter(poles[index]); + pc->setRadius(distance_p0_p1 / 6); + + igeo.push_back(pc); + 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; + } + + 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; + + icon.push_back(newConstr2); + } + } + + for (size_t index = 0; index < knotgeoids.size(); ++index) { + auto& kGeoId = knotgeoids.at(index); + if (kGeoId != GeoEnum::GeoUndef) { + continue; + } + + // if knot point not existing + Part::GeomPoint* kp = new Part::GeomPoint(); + + kp->setPoint(bsp->pointAtParameter(knots[index])); + + igeo.push_back(kp); + incrgeo++; + + 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; + + icon.push_back(newConstr); + } + + Q_UNUSED(isfirstweightconstrained); + + 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 +} + int SketchObject::exposeInternalGeometry(int GeoId) { if (GeoId < 0 || GeoId > getHighestCurveIndex()) @@ -6097,533 +6734,20 @@ int SketchObject::exposeInternalGeometry(int GeoId) 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; - } - } - } - - int currentgeoid = getHighestCurveIndex(); - int incrgeo = 0; - - Base::Vector3d center; - double majord; - double minord; - Base::Vector3d majdir; - - std::vector igeo; - std::vector icon; - - if (geo->is()) { - const Part::GeomEllipse* ellipse = static_cast(geo); - - center = ellipse->getCenter(); - majord = ellipse->getMajorRadius(); - minord = ellipse->getMinorRadius(); - majdir = ellipse->getMajorAxisDir(); - } - else { - 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++; - } - if (!minor) { - Part::GeomLineSegment* lminor = new Part::GeomLineSegment(); - lminor->setPoints(minorpositiveend, minornegativeend); - - 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; - - icon.push_back(newConstr); - incrgeo++; - } - if (!focus1) { - Part::GeomPoint* pf1 = new Part::GeomPoint(); - pf1->setPoint(focus1P); - - 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; - - 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; - - icon.push_back(newConstr); - } - - this->addGeometry(igeo, true); - this->addConstraints(icon); - - for (std::vector::iterator it = igeo.begin(); it != igeo.end(); ++it) { - if (*it) - delete *it; - } - - for (std::vector::iterator it = icon.begin(); it != icon.end(); ++it) { - if (*it) - delete *it; - } - - icon.clear(); - igeo.clear(); - - return incrgeo;// number of added elements + if (geo->is()) { + return exposeInternalGeometryForType(GeoId); + } + else if (geo->is()) { + return exposeInternalGeometryForType(GeoId); } 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; - } - } - } - - int currentgeoid = getHighestCurveIndex(); - int incrgeo = 0; - - const Part::GeomArcOfHyperbola* aoh = static_cast(geo); - - Base::Vector3d center = aoh->getCenter(); - double majord = aoh->getMajorRadius(); - double minord = aoh->getMinorRadius(); - Base::Vector3d majdir = aoh->getMajorAxisDir(); - - std::vector igeo; - std::vector icon; - - Base::Vector3d mindir = Vector3d(-majdir.y, majdir.x); - - Base::Vector3d majorpositiveend = center + majord * majdir; - Base::Vector3d majornegativeend = center - majord * majdir; - Base::Vector3d minorpositiveend = majorpositiveend + minord * mindir; - Base::Vector3d minornegativeend = majorpositiveend - minord * mindir; - - double df = sqrt(majord * majord + minord * minord); - - Base::Vector3d focus1P = 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 = Sketcher::HyperbolaMajor; - 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); - - 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; - - icon.push_back(newConstr); - - incrgeo++; - } - if (!focus) { - Part::GeomPoint* pf1 = new Part::GeomPoint(); - pf1->setPoint(focus1P); - - igeo.push_back(pf1); - - 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); - incrgeo++; - } - - this->addGeometry(igeo, true); - this->addConstraints(icon); - - for (std::vector::iterator it = igeo.begin(); it != igeo.end(); ++it) - if (*it) - delete *it; - - for (std::vector::iterator it = icon.begin(); it != icon.end(); ++it) - if (*it) - delete *it; - - icon.clear(); - igeo.clear(); - - return incrgeo;// number of added elements + return exposeInternalGeometryForType(GeoId); } 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; - } - } - } - - int currentgeoid = getHighestCurveIndex(); - int incrgeo = 0; - - const Part::GeomArcOfParabola* aop = static_cast(geo); - - Base::Vector3d center = aop->getCenter(); - Base::Vector3d focusp = aop->getFocus(); - - std::vector igeo; - std::vector icon; - - 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++; - } - - if (!focus_to_vertex) { - Part::GeomLineSegment* paxis = new Part::GeomLineSegment(); - paxis->setPoints(center, focusp); - - igeo.push_back(paxis); - - 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; - - icon.push_back(newConstr); - - incrgeo++; - } - - this->addGeometry(igeo, true); - this->addConstraints(icon); - - for (std::vector::iterator it = igeo.begin(); it != igeo.end(); ++it) { - if (*it) - delete *it; - } - - for (std::vector::iterator it = icon.begin(); it != icon.end(); ++it) { - if (*it) - delete *it; - } - - icon.clear(); - igeo.clear(); - - return incrgeo;// number of added elements + return exposeInternalGeometryForType(GeoId); } 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()); - - std::vector knotpoints(bsp->countKnots()); - std::vector knotgeoids(bsp->countKnots()); - - bool isfirstweightconstrained = false; - - std::vector::iterator itb; - std::vector::iterator it; - - for (it = controlpointgeoids.begin(), itb = controlpoints.begin(); - it != controlpointgeoids.end() && itb != controlpoints.end(); - ++it, ++itb) { - (*it) = -1; - (*itb) = false; - } - - for (it = knotgeoids.begin(), itb = knotpoints.begin(); - it != knotgeoids.end() && itb != knotpoints.end(); - ++it, ++itb) { - (*it) = -1; - (*itb) = false; - } - - const std::vector& vals = Constraints.getValues(); - - // 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; - } - } - } - - 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; - } - } - } - - int currentgeoid = getHighestCurveIndex(); - int incrgeo = 0; - - std::vector igeo; - std::vector icon; - - std::vector poles = bsp->getPoles(); - std::vector weights = bsp->getWeights(); - std::vector knots = bsp->getKnots(); - - double distance_p0_p1 = (poles[1] - poles[0]).Length();// for visual purposes only - - int index = 0; - - for (it = controlpointgeoids.begin(), itb = controlpoints.begin(); - it != controlpointgeoids.end() && itb != controlpoints.end(); - ++it, ++itb, index++) { - - 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]); - - icon.push_back(newConstr3); - - isfirstweightconstrained = true; - } - } - incrgeo++; - } - } - - index = 0; - - for (it = knotgeoids.begin(), itb = knotpoints.begin(); - it != knotgeoids.end() && itb != knotpoints.end(); - ++it, ++itb, index++) { - - if (!(*itb))// if knot point not existing - { - Part::GeomPoint* kp = new Part::GeomPoint(); - - kp->setPoint(bsp->pointAtParameter(knots[index])); - - igeo.push_back(kp); - - 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; - - icon.push_back(newConstr); - - incrgeo++; - } - } - - Q_UNUSED(isfirstweightconstrained); - - this->addGeometry(igeo, true); - this->addConstraints(icon); - - for (std::vector::iterator it = igeo.begin(); it != igeo.end(); ++it) - if (*it) - delete *it; - - for (std::vector::iterator it = icon.begin(); it != icon.end(); ++it) - if (*it) - delete *it; - - icon.clear(); - igeo.clear(); - - return incrgeo;// number of added elements + 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()) { - - int majorelementindex = -1; - int minorelementindex = -1; - int focus1elementindex = -1; - int focus2elementindex = -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::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; - } - } - } - - // Hide unused geometry here - int majorconstraints = 0;// number of constraints associated to the geoid of the major axis - int minorconstraints = 0; - int focus1constraints = 0; - int focus2constraints = 0; - - for (std::vector::const_iterator it = vals.begin(); it != vals.end(); - ++it) { - - if ((*it)->Second == majorelementindex || (*it)->First == majorelementindex - || (*it)->Third == majorelementindex) - majorconstraints++; - else if ((*it)->Second == minorelementindex || (*it)->First == minorelementindex - || (*it)->Third == minorelementindex) - minorconstraints++; - else if ((*it)->Second == focus1elementindex || (*it)->First == focus1elementindex - || (*it)->Third == focus1elementindex) - focus1constraints++; - else if ((*it)->Second == focus2elementindex || (*it)->First == focus2elementindex - || (*it)->Third == focus2elementindex) - focus2constraints++; - } - - std::vector delgeometries; - - // those with less than 2 constraints must be removed - if (focus2constraints < 2) - delgeometries.push_back(focus2elementindex); - - if (focus1constraints < 2) - delgeometries.push_back(focus1elementindex); - - if (minorconstraints < 2) - delgeometries.push_back(minorelementindex); - - if (majorconstraints < 2) - delgeometries.push_back(majorelementindex); - - if (delgeoid) - delgeometries.push_back(GeoId); - - // indices over an erased element get automatically updated!! - std::sort(delgeometries.begin(), delgeometries.end()); - - if (!delgeometries.empty()) { - for (std::vector::reverse_iterator it = delgeometries.rbegin(); - it != delgeometries.rend(); - ++it) { - delGeometry(*it, false); - } - } - - int ndeleted = delgeometries.size(); - - delgeometries.clear(); - - return ndeleted;// number of deleted elements + return deleteUnusedInternalGeometryWhenTwoFoci(GeoId, delgeoid); } - 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; - - 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++; - } - - std::vector delgeometries; - - // major has minimum one constraint, the specific internal alignment constraint - if (majorelementindex != -1 && majorconstraints < 2) - delgeometries.push_back(majorelementindex); - - // focus has minimum one constraint now, the specific internal alignment constraint - if (focus1elementindex != -1 && focus1constraints < 2) - delgeometries.push_back(focus1elementindex); - - if (delgeoid) - delgeometries.push_back(GeoId); - - // indices over an erased element get automatically updated!! - std::sort(delgeometries.begin(), delgeometries.end()); - - if (!delgeometries.empty()) { - for (std::vector::reverse_iterator it = delgeometries.rbegin(); - it != delgeometries.rend(); - ++it) { - delGeometry(*it, false); - } - } - - int ndeleted = delgeometries.size(); - - delgeometries.clear(); - - return ndeleted;// number of deleted elements + if (geo->is()) { + return deleteUnusedInternalGeometryWhenOneFocus(GeoId, delgeoid); } - else if (geo->is()) { - const Part::GeomBSplineCurve* bsp = static_cast(geo); - - // First we search existing IA - std::vector controlpointgeoids(bsp->countPoles()); - std::vector cpassociatedconstraints(bsp->countPoles()); - - std::vector knotgeoids(bsp->countKnots()); - std::vector kassociatedconstraints(bsp->countKnots()); - - std::vector::iterator it; - std::vector::iterator ita; - - for (it = controlpointgeoids.begin(), ita = cpassociatedconstraints.begin(); - it != controlpointgeoids.end() && ita != cpassociatedconstraints.end(); - ++it, ++ita) { - (*it) = -1; - (*ita) = 0; - } - - for (it = knotgeoids.begin(), ita = kassociatedconstraints.begin(); - it != knotgeoids.end() && ita != kassociatedconstraints.end(); - ++it, ++ita) { - (*it) = -1; - (*ita) = 0; - } - - const std::vector& vals = Constraints.getValues(); - - // 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; - } - } - } - - std::vector delgeometries; - - 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) { - - 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; - } - - if (f && s) {// the equality constraint is not interpole - break; - } - } - - // 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. - } - - if ((*ita) < 2) {// IA - delgeometries.push_back((*it)); - } - } - } - - 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)++; - } - } - - if ((*ita) < 2) {// IA - delgeometries.push_back((*it)); - } - } - } - - - if (delgeoid) - delgeometries.push_back(GeoId); - - int ndeleted = delGeometriesExclusiveList(delgeometries); - - return ndeleted;// number of deleted elements + if (geo->is()) { + return deleteUnusedInternalGeometryWhenBSpline(GeoId, delgeoid); } - else { - return -1;// not supported type + + // Default case: type not supported + return -1; +} + +int SketchObject::deleteUnusedInternalGeometryWhenTwoFoci(int GeoId, bool delgeoid) +{ + int majorelementindex = -1; + int minorelementindex = -1; + int focus1elementindex = -1; + int focus2elementindex = -1; + + const std::vector& vals = Constraints.getValues(); + + for (auto const& constr : vals) { + if (constr->Type != Sketcher::InternalAlignment || constr->Second != GeoId) { + continue; + } + + 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; + } } + + // Hide unused geometry here + int majorconstraints = 0;// number of constraints associated to the geoid of the major axis + int minorconstraints = 0; + int focus1constraints = 0; + int focus2constraints = 0; + + for (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++; + } + + std::vector delgeometries; + + // those with less than 2 constraints must be removed + if (focus2constraints < 2) + delgeometries.push_back(focus2elementindex); + + if (focus1constraints < 2) + delgeometries.push_back(focus1elementindex); + + if (minorconstraints < 2) + delgeometries.push_back(minorelementindex); + + if (majorconstraints < 2) + delgeometries.push_back(majorelementindex); + + if (delgeoid) + delgeometries.push_back(GeoId); + + // indices over an erased element get automatically updated!! + std::sort(delgeometries.begin(), delgeometries.end(), std::greater<>()); + + for (auto& dGeoId : delgeometries) { + delGeometry(dGeoId, false); + } + + int ndeleted = delgeometries.size(); + + return ndeleted;// number of deleted elements +} + +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; + + const std::vector& vals = Constraints.getValues(); + + for (auto const& constr : vals) { + if (constr->Type != Sketcher::InternalAlignment || constr->Second != GeoId) { + continue; + } + + switch (constr->AlignmentType) { + case Sketcher::ParabolaFocus: + focus1elementindex = constr->First; + break; + case Sketcher::ParabolaFocalAxis: + majorelementindex = constr->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; + + for (const auto& constr : vals) { + if (constr->involvesGeoId(majorelementindex)) { + majorconstraints++; + } + else if (constr->involvesGeoId(focus1elementindex)) { + focus1constraints++; + } + } + + std::vector delgeometries; + + // major has minimum one constraint, the specific internal alignment constraint + if (majorelementindex != -1 && majorconstraints < 2) + delgeometries.push_back(majorelementindex); + + // focus has minimum one constraint now, the specific internal alignment constraint + if (focus1elementindex != -1 && focus1constraints < 2) + delgeometries.push_back(focus1elementindex); + + if (delgeoid) + delgeometries.push_back(GeoId); + + // indices over an erased element get automatically updated!! + std::sort(delgeometries.begin(), delgeometries.end(), std::greater<>()); + + for (auto& dGeoId : delgeometries) { + delGeometry(dGeoId, false); + } + + int ndeleted = delgeometries.size(); + + delgeometries.clear(); + + return ndeleted;// number of deleted elements +} + +int SketchObject::deleteUnusedInternalGeometryWhenBSpline(int GeoId, bool delgeoid) +{ + const Part::GeomBSplineCurve* bsp = static_cast(getGeometry(GeoId)); + + // First we search existing IA + std::vector > poleGeoIdsAndConstraints(bsp->countPoles(), {GeoEnum::GeoUndef, 0}); + + std::vector > knotGeoIdsAndConstraints(bsp->countKnots(), {GeoEnum::GeoUndef, 0}); + + const std::vector& vals = Constraints.getValues(); + + // search for existing poles + for (auto const& constr : vals) { + if (constr->Type != Sketcher::InternalAlignment || constr->Second != GeoId) { + continue; + } + + 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; + } + } + + std::vector delgeometries; + + for (auto& [cpGeoId, numConstr] : poleGeoIdsAndConstraints) { + if (cpGeoId == GeoEnum::GeoUndef) { + continue; + } + + // look for a circle at geoid index + for (auto const& constr : vals) { + if (constr->Type != Sketcher::Equal) { + continue; + } + + 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); + } + } + + for (auto& [kGeoId, numConstr] : knotGeoIdsAndConstraints) { + if (kGeoId == GeoEnum::GeoUndef) { + continue; + } + + // look for a point at geoid index + numConstr = std::count_if(vals.begin(), vals.end(), [&kGeoId](const auto& constr) { + return constr->involvesGeoId(kGeoId); + }); + + if (numConstr < 2) { // IA + delgeometries.push_back(kGeoId); + } + } + + 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 62a13821dd..09aca4d269 100644 --- a/src/Mod/Sketcher/App/SketchObject.h +++ b/src/Mod/Sketcher/App/SketchObject.h @@ -482,6 +482,11 @@ public: * \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 @@ protected: 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;