From 6cf63b078eb08918d0a232c1fde88f9b3c191f81 Mon Sep 17 00:00:00 2001 From: Ajinkya Dahale Date: Thu, 10 Apr 2025 16:15:42 +0530 Subject: [PATCH] Sketcher: Refactor further `DrawSketchDefaultHandler.h` These are somewhat riskier refactors. If confirmed safe, these can be merged with the previous commit. --- .../Sketcher/Gui/DrawSketchDefaultHandler.h | 422 +++++++++--------- 1 file changed, 213 insertions(+), 209 deletions(-) diff --git a/src/Mod/Sketcher/Gui/DrawSketchDefaultHandler.h b/src/Mod/Sketcher/Gui/DrawSketchDefaultHandler.h index 177bc6ed5a..55a60b280a 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchDefaultHandler.h +++ b/src/Mod/Sketcher/Gui/DrawSketchDefaultHandler.h @@ -36,6 +36,7 @@ #include #include +#include "AutoConstraint.h" #include "DrawSketchHandler.h" #include "ViewProviderSketch.h" @@ -651,6 +652,214 @@ protected: See documentation of the functions above*/ //@{ + // TODO: Figure out and explain what it actually returns + bool generateOneAutoConstraintFromSuggestion(const AutoConstraint& ac, + int geoId1, + Sketcher::PointPos posId1) + { + int geoId2 = ac.GeoId; + Sketcher::PointPos posId2 = ac.PosId; + + static const auto isStartOrEnd = [](const Sketcher::PointPos posId) { + return posId == Sketcher::PointPos::start || posId == Sketcher::PointPos::end; + }; + + + switch (ac.Type) { + case Sketcher::Coincident: { + if (posId1 == Sketcher::PointPos::none) { + return true; + } + + // find if there is already a matching tangency + auto itOfTangentConstraint = AutoConstraints.end(); + if (isStartOrEnd(posId1) && isStartOrEnd(posId2)) { + itOfTangentConstraint = + std::ranges::find_if(AutoConstraints, [&](const auto& ace) { + return ace->Type == Sketcher::Tangent && ace->First == geoId1 + && ace->Second == geoId2; + }); + } + + if (itOfTangentConstraint != AutoConstraints.end()) { + // modify tangency to endpoint-to-endpoint + (*itOfTangentConstraint)->FirstPos = posId1; + (*itOfTangentConstraint)->SecondPos = posId2; + } + else { + auto c = std::make_unique(); + c->Type = Sketcher::Coincident; + c->First = geoId1; + c->FirstPos = posId1; + c->Second = geoId2; + c->SecondPos = posId2; + AutoConstraints.push_back(std::move(c)); + } + } break; + case Sketcher::PointOnObject: { + if (posId1 == Sketcher::PointPos::none) { + // Auto constraining an edge so swap parameters + std::swap(geoId1, geoId2); + std::swap(posId1, posId2); + } + + auto itOfTangentConstraint = AutoConstraints.end(); + if (isStartOrEnd(posId1)) { + itOfTangentConstraint = + std::ranges::find_if(AutoConstraints, [&](const auto& ace) { + return ace->Type == Sketcher::Tangent && ace->involvesGeoId(geoId1) + && ace->involvesGeoId(geoId2); + }); + } + + // if tangency, convert to point-to-edge tangency + if (itOfTangentConstraint != AutoConstraints.end()) { + if ((*itOfTangentConstraint)->First != geoId1) { + std::swap((*itOfTangentConstraint)->Second, + (*itOfTangentConstraint)->First); + } + + (*itOfTangentConstraint)->FirstPos = posId1; + } + else { + auto c = std::make_unique(); + c->Type = Sketcher::PointOnObject; + c->First = geoId1; + c->FirstPos = posId1; + c->Second = geoId2; + AutoConstraints.push_back(std::move(c)); + } + } break; + case Sketcher::Symmetric: { + auto c = std::make_unique(); + c->Type = Sketcher::Symmetric; + c->First = geoId2; + c->FirstPos = Sketcher::PointPos::start; + c->Second = geoId2; + c->SecondPos = Sketcher::PointPos::end; + c->Third = geoId1; + c->ThirdPos = posId1; + AutoConstraints.push_back(std::move(c)); + } break; + // In special case of Horizontal/Vertical constraint, geoId2 is normally + // unused and should be 'Constraint::GeoUndef' However it can be used as a + // way to require the function to apply these constraints on another + // geometry In this case the caller as to set geoId2, then it will be used + // as target instead of geoId2 + case Sketcher::Horizontal: + case Sketcher::Vertical: { + auto c = std::make_unique(); + c->Type = ac.Type; + c->First = (geoId2 != Sketcher::GeoEnum::GeoUndef ? geoId2 : geoId1); + AutoConstraints.push_back(std::move(c)); + } break; + case Sketcher::Tangent: { + Sketcher::SketchObject* Obj = sketchgui->getObject(); + + const Part::Geometry* geom1 = Obj->getGeometry(geoId1); + const Part::Geometry* geom2 = Obj->getGeometry(geoId2); + + // ellipse tangency support using construction elements (lines) + if (geom1 && geom2 + && (geom1->is() || geom2->is())) { + if (!geom1->is()) { + std::swap(geoId1, geoId2); + } + + // geoId1 is the ellipse + geom1 = Obj->getGeometry(geoId1); + geom2 = Obj->getGeometry(geoId2); + + if (geom2->is() || geom2->is() + || geom2->is() || geom2->is()) { + // in all these cases an intermediate element is needed + // makeTangentToEllipseviaNewPoint( + // Obj, + // static_cast(geom1), + // geom2, + // geoId1, + // geoId2); + // NOTE: Temporarily deactivated + return false; + } + } + + // arc of ellipse tangency support using external elements + if (geom1 && geom2 + && (geom1->is() + || geom2->is())) { + if (!geom1->is()) { + std::swap(geoId1, geoId2); + } + + // geoId1 is the arc of ellipse + geom1 = Obj->getGeometry(geoId1); + geom2 = Obj->getGeometry(geoId2); + + if (geom2->is() || geom2->is() + || geom2->is()) { + // in all these cases an intermediate element is needed + // makeTangentToArcOfEllipseviaNewPoint( + // Obj, + // static_cast(geom1), + // geom2, + // geoId1, + // geoId2); + // NOTE: Temporarily deactivated + return false; + } + } + + auto resultCoincident = std::ranges::find_if(AutoConstraints, [&](const auto& ace) { + return ace->Type == Sketcher::Coincident && ace->First == geoId1 + && ace->Second == geoId2; + }); + + auto resultPointOnObject = + std::ranges::find_if(AutoConstraints, [&](const auto& ace) { + return ace->Type == Sketcher::PointOnObject && ace->involvesGeoId(geoId1) + && ace->involvesGeoId(geoId2); + }); + + if (resultCoincident != AutoConstraints.end() + && isStartOrEnd((*resultCoincident)->FirstPos) + && isStartOrEnd((*resultCoincident)->SecondPos)) { + // endpoint-to-endpoint tangency + (*resultCoincident)->Type = Sketcher::Tangent; + } + else if (resultPointOnObject != AutoConstraints.end() + && isStartOrEnd((*resultPointOnObject)->FirstPos)) { + // endpoint-to-edge tangency + (*resultPointOnObject)->Type = Sketcher::Tangent; + } + else if (resultCoincident != AutoConstraints.end() + && (*resultCoincident)->FirstPos == Sketcher::PointPos::mid + && (*resultCoincident)->SecondPos == Sketcher::PointPos::mid && geom1 + && geom2 + && (geom1->is() || geom1->is()) + && (geom2->is() || geom2->is())) { + // equality + auto c = std::make_unique(); + c->Type = Sketcher::Equal; + c->First = geoId1; + c->Second = geoId2; + AutoConstraints.push_back(std::move(c)); + } + else { // regular edge to edge tangency + auto c = std::make_unique(); + c->Type = Sketcher::Tangent; + c->First = geoId1; + c->Second = geoId2; + AutoConstraints.push_back(std::move(c)); + } + } break; + default: + break; + } + + return true; + } + /** @brief Convenience function to automatically generate and add to the AutoConstraints vector * the suggested constraints. * @@ -664,214 +873,9 @@ protected: return; } - if (autoConstrs.empty()) { - return; - } - - auto isStartOrEnd = [](const Sketcher::PointPos posId) { - return posId == Sketcher::PointPos::start || posId == Sketcher::PointPos::end; - }; - for (auto& ac : autoConstrs) { - int geoId2 = ac.GeoId; - Sketcher::PointPos posId2 = ac.PosId; - - switch (ac.Type) { - case Sketcher::Coincident: { - if (posId1 == Sketcher::PointPos::none) { - continue; - } - - // find if there is already a matching tangency - auto itOfTangentConstraint = AutoConstraints.end(); - if (isStartOrEnd(posId1) && isStartOrEnd(posId2)) { - itOfTangentConstraint = - std::ranges::find_if(AutoConstraints, [&](const auto& ace) { - return ace->Type == Sketcher::Tangent && ace->First == geoId1 - && ace->Second == geoId2; - }); - } - - if (itOfTangentConstraint != AutoConstraints.end()) { - // modify tangency to endpoint-to-endpoint - (*itOfTangentConstraint)->FirstPos = posId1; - (*itOfTangentConstraint)->SecondPos = posId2; - } - else { - auto c = std::make_unique(); - c->Type = Sketcher::Coincident; - c->First = geoId1; - c->FirstPos = posId1; - c->Second = geoId2; - c->SecondPos = posId2; - AutoConstraints.push_back(std::move(c)); - } - } break; - case Sketcher::PointOnObject: { - if (posId1 == Sketcher::PointPos::none) { - // Auto constraining an edge so swap parameters - std::swap(geoId1, geoId2); - std::swap(posId1, posId2); - } - - auto itOfTangentConstraint = AutoConstraints.end(); - if (isStartOrEnd(posId1)) { - itOfTangentConstraint = - std::ranges::find_if(AutoConstraints, [&](const auto& ace) { - return ace->Type == Sketcher::Tangent && ace->involvesGeoId(geoId1) - && ace->involvesGeoId(geoId2); - }); - } - - // if tangency, convert to point-to-edge tangency - if (itOfTangentConstraint != AutoConstraints.end()) { - if ((*itOfTangentConstraint)->First != geoId1) { - std::swap((*itOfTangentConstraint)->Second, - (*itOfTangentConstraint)->First); - } - - (*itOfTangentConstraint)->FirstPos = posId1; - } - else { - auto c = std::make_unique(); - c->Type = Sketcher::PointOnObject; - c->First = geoId1; - c->FirstPos = posId1; - c->Second = geoId2; - AutoConstraints.push_back(std::move(c)); - } - } break; - case Sketcher::Symmetric: { - auto c = std::make_unique(); - c->Type = Sketcher::Symmetric; - c->First = geoId2; - c->FirstPos = Sketcher::PointPos::start; - c->Second = geoId2; - c->SecondPos = Sketcher::PointPos::end; - c->Third = geoId1; - c->ThirdPos = posId1; - AutoConstraints.push_back(std::move(c)); - } break; - // In special case of Horizontal/Vertical constraint, geoId2 is normally - // unused and should be 'Constraint::GeoUndef' However it can be used as a - // way to require the function to apply these constraints on another - // geometry In this case the caller as to set geoId2, then it will be used - // as target instead of geoId2 - case Sketcher::Horizontal: { - auto c = std::make_unique(); - c->Type = Sketcher::Horizontal; - c->First = (geoId2 != Sketcher::GeoEnum::GeoUndef ? geoId2 : geoId1); - AutoConstraints.push_back(std::move(c)); - } break; - case Sketcher::Vertical: { - auto c = std::make_unique(); - c->Type = Sketcher::Vertical; - c->First = (geoId2 != Sketcher::GeoEnum::GeoUndef ? geoId2 : geoId1); - AutoConstraints.push_back(std::move(c)); - } break; - case Sketcher::Tangent: { - Sketcher::SketchObject* Obj = sketchgui->getObject(); - - const Part::Geometry* geom1 = Obj->getGeometry(geoId1); - const Part::Geometry* geom2 = Obj->getGeometry(geoId2); - - // ellipse tangency support using construction elements (lines) - if (geom1 && geom2 - && (geom1->is() || geom2->is())) { - if (!geom1->is()) { - std::swap(geoId1, geoId2); - } - - // geoId1 is the ellipse - geom1 = Obj->getGeometry(geoId1); - geom2 = Obj->getGeometry(geoId2); - - if (geom2->is() || geom2->is() - || geom2->is() - || geom2->is()) { - // in all these cases an intermediate element is needed - // makeTangentToEllipseviaNewPoint( - // Obj, - // static_cast(geom1), - // geom2, geoId1, geoId2); - // NOTE: Temporarily deactivated - return; - } - } - - // arc of ellipse tangency support using external elements - if (geom1 && geom2 - && (geom1->is() - || geom2->is())) { - - if (!geom1->is()) { - std::swap(geoId1, geoId2); - } - - // geoId1 is the arc of ellipse - geom1 = Obj->getGeometry(geoId1); - geom2 = Obj->getGeometry(geoId2); - - if (geom2->is() || geom2->is() - || geom2->is()) { - // in all these cases an intermediate element is needed - // makeTangentToArcOfEllipseviaNewPoint( - // Obj, - // static_cast(geom1), geom2, - // geoId1, geoId2); - // NOTE: Temporarily deactivated - return; - } - } - - auto resultcoincident = - std::ranges::find_if(AutoConstraints, [&](const auto& ace) { - return ace->Type == Sketcher::Coincident && ace->First == geoId1 - && ace->Second == geoId2; - }); - - auto resultpointonobject = - std::ranges::find_if(AutoConstraints, [&](const auto& ace) { - return ace->Type == Sketcher::PointOnObject - && ace->involvesGeoId(geoId1) && ace->involvesGeoId(geoId2); - }); - - if (resultcoincident != AutoConstraints.end() - && isStartOrEnd((*resultcoincident)->FirstPos) - && isStartOrEnd((*resultcoincident)->SecondPos)) { - // endpoint-to-endpoint tangency - (*resultcoincident)->Type = Sketcher::Tangent; - } - else if (resultpointonobject != AutoConstraints.end() - && isStartOrEnd((*resultpointonobject)->FirstPos)) { - // endpoint-to-edge tangency - (*resultpointonobject)->Type = Sketcher::Tangent; - } - else if (resultcoincident != AutoConstraints.end() - && (*resultcoincident)->FirstPos == Sketcher::PointPos::mid - && (*resultcoincident)->SecondPos == Sketcher::PointPos::mid && geom1 - && geom2 - && (geom1->is() - || geom1->is()) - && (geom2->is() - || geom2->is())) { - // equality - auto c = std::make_unique(); - c->Type = Sketcher::Equal; - c->First = geoId1; - c->Second = geoId2; - AutoConstraints.push_back(std::move(c)); - } - else { // regular edge to edge tangency - auto c = std::make_unique(); - c->Type = Sketcher::Tangent; - c->First = geoId1; - c->Second = geoId2; - AutoConstraints.push_back(std::move(c)); - } - } break; - default: - break; + if (!generateOneAutoConstraintFromSuggestion(ac, geoId1, posId1)) { + return; } } } @@ -1086,9 +1090,9 @@ protected: auto addToShapeConstraints(Sketcher::ConstraintType type, int first, Sketcher::PointPos firstPos = Sketcher::PointPos::none, - int second = -2000, + int second = Sketcher::GeoEnum::GeoUndef, Sketcher::PointPos secondPos = Sketcher::PointPos::none, - int third = -2000, + int third = Sketcher::GeoEnum::GeoUndef, Sketcher::PointPos thirdPos = Sketcher::PointPos::none) { auto constr = std::make_unique();