From a45bb8626f5f1be572f14da3a6acc2e78f18b881 Mon Sep 17 00:00:00 2001 From: Paddle Date: Wed, 22 Nov 2023 16:19:08 +0100 Subject: [PATCH 1/4] Sketcher: Move Distance command next to DistanceX. ONLY move code, nothing changed. --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 1250 +++++++++---------- 1 file changed, 625 insertions(+), 625 deletions(-) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index a181e3e38c..f9d11b6e14 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -3939,631 +3939,6 @@ void CmdSketcherConstrainCoincident::applyConstraint(std::vector& sel // ====================================================================================== -class CmdSketcherConstrainDistance: public CmdSketcherConstraint -{ -public: - CmdSketcherConstrainDistance(); - ~CmdSketcherConstrainDistance() override - {} - void updateAction(int mode) override; - const char* className() const override - { - return "CmdSketcherConstrainDistance"; - } - -protected: - void activated(int iMsg) override; - void applyConstraint(std::vector& selSeq, int seqIndex) override; -}; - -CmdSketcherConstrainDistance::CmdSketcherConstrainDistance() - : CmdSketcherConstraint("Sketcher_ConstrainDistance") -{ - sAppModule = "Sketcher"; - sGroup = "Sketcher"; - sMenuText = QT_TR_NOOP("Constrain distance"); - sToolTipText = QT_TR_NOOP("Fix a length of a line or the distance between a line and a vertex " - "or between two circles"); - sWhatsThis = "Sketcher_ConstrainDistance"; - sStatusTip = sToolTipText; - sPixmap = "Constraint_Length"; - sAccel = "K, D"; - eType = ForEdit; - - allowedSelSequences = {{SelVertex, SelVertexOrRoot}, - {SelRoot, SelVertex}, - {SelEdge}, - {SelExternalEdge}, - {SelVertex, SelEdgeOrAxis}, - {SelRoot, SelEdge}, - {SelVertex, SelExternalEdge}, - {SelRoot, SelExternalEdge}, - {SelEdge, SelEdge}}; -} - -void CmdSketcherConstrainDistance::activated(int iMsg) -{ - Q_UNUSED(iMsg); - // get the selection - std::vector selection = getSelection().getSelectionEx(); - - // only one sketch with its subelements are allowed to be selected - if (selection.size() != 1 - || !selection[0].isObjectTypeOf(Sketcher::SketchObject::getClassTypeId())) { - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( - "User parameter:BaseApp/Preferences/Mod/Sketcher"); - bool constraintMode = hGrp->GetBool("ContinuousConstraintMode", true); - - if (constraintMode) { - ActivateHandler(getActiveGuiDocument(), new DrawSketchHandlerGenConstraint(this)); - - getSelection().clearSelection(); - } - else { - Gui::TranslatedUserWarning(getActiveGuiDocument(), - QObject::tr("Wrong selection"), - QObject::tr("Select vertices from the sketch.")); - } - return; - } - - // get the needed lists and objects - const std::vector& SubNames = selection[0].getSubNames(); - Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); - - if (SubNames.empty() || SubNames.size() > 2) { - Gui::TranslatedUserWarning(Obj, - QObject::tr("Wrong selection"), - QObject::tr("Select exactly one line or one point and one line " - "or two points from the sketch.")); - return; - } - - int GeoId1, GeoId2 = GeoEnum::GeoUndef; - Sketcher::PointPos PosId1, PosId2 = Sketcher::PointPos::none; - getIdsFromName(SubNames[0], Obj, GeoId1, PosId1); - if (SubNames.size() == 2) { - getIdsFromName(SubNames[1], Obj, GeoId2, PosId2); - } - - bool arebothpointsorsegmentsfixed = areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2); - - if (isVertex(GeoId1, PosId1) - && (GeoId2 == Sketcher::GeoEnum::VAxis || GeoId2 == Sketcher::GeoEnum::HAxis)) { - std::swap(GeoId1, GeoId2); - std::swap(PosId1, PosId2); - } - - if ((isVertex(GeoId1, PosId1) || GeoId1 == Sketcher::GeoEnum::VAxis - || GeoId1 == Sketcher::GeoEnum::HAxis) - && isVertex(GeoId2, PosId2)) {// point to point distance - - Base::Vector3d pnt2 = Obj->getPoint(GeoId2, PosId2); - - if (GeoId1 == Sketcher::GeoEnum::HAxis && PosId1 == Sketcher::PointPos::none) { - PosId1 = Sketcher::PointPos::start; - - openCommand( - QT_TRANSLATE_NOOP("Command", "Add distance from horizontal axis constraint")); - Gui::cmdAppObjectArgs(selection[0].getObject(), - "addConstraint(Sketcher.Constraint('DistanceY',%d,%d,%d,%d,%f))", - GeoId1, - static_cast(PosId1), - GeoId2, - static_cast(PosId2), - pnt2.y); - } - else if (GeoId1 == Sketcher::GeoEnum::VAxis && PosId1 == Sketcher::PointPos::none) { - PosId1 = Sketcher::PointPos::start; - - openCommand(QT_TRANSLATE_NOOP("Command", "Add distance from vertical axis constraint")); - Gui::cmdAppObjectArgs(selection[0].getObject(), - "addConstraint(Sketcher.Constraint('DistanceX',%d,%d,%d,%d,%f))", - GeoId1, - static_cast(PosId1), - GeoId2, - static_cast(PosId2), - pnt2.x); - } - else { - Base::Vector3d pnt1 = Obj->getPoint(GeoId1, PosId1); - - openCommand(QT_TRANSLATE_NOOP("Command", "Add point to point distance constraint")); - Gui::cmdAppObjectArgs(selection[0].getObject(), - "addConstraint(Sketcher.Constraint('Distance',%d,%d,%d,%d,%f))", - GeoId1, - static_cast(PosId1), - GeoId2, - static_cast(PosId2), - (pnt2 - pnt1).Length()); - } - - if (arebothpointsorsegmentsfixed || constraintCreationMode == Reference) { - // it is a constraint on a external line, make it non-driving - const std::vector& ConStr = Obj->Constraints.getValues(); - - Gui::cmdAppObjectArgs(selection[0].getObject(), - "setDriving(%d,%s)", - ConStr.size() - 1, - "False"); - finishDatumConstraint(this, Obj, false); - } - else { - finishDatumConstraint(this, Obj, true); - } - return; - } - else if ((isVertex(GeoId1, PosId1) && isEdge(GeoId2, PosId2)) - || (isEdge(GeoId1, PosId1) && isVertex(GeoId2, PosId2))) {// point to line distance - if (isVertex(GeoId2, PosId2)) { - std::swap(GeoId1, GeoId2); - std::swap(PosId1, PosId2); - } - Base::Vector3d pnt = Obj->getPoint(GeoId1, PosId1); - const Part::Geometry* geom = Obj->getGeometry(GeoId2); - - if (isLineSegment(*geom)) { - auto lineSeg = static_cast(geom); - Base::Vector3d pnt1 = lineSeg->getStartPoint(); - Base::Vector3d pnt2 = lineSeg->getEndPoint(); - Base::Vector3d d = pnt2 - pnt1; - double ActDist = - std::abs(-pnt.x * d.y + pnt.y * d.x + pnt1.x * pnt2.y - pnt2.x * pnt1.y) - / d.Length(); - - openCommand(QT_TRANSLATE_NOOP("Command", "Add point to line Distance constraint")); - Gui::cmdAppObjectArgs(selection[0].getObject(), - "addConstraint(Sketcher.Constraint('Distance',%d,%d,%d,%f))", - GeoId1, - static_cast(PosId1), - GeoId2, - ActDist); - - if (arebothpointsorsegmentsfixed - || constraintCreationMode - == Reference) {// it is a constraint on a external line, make it non-driving - const std::vector& ConStr = Obj->Constraints.getValues(); - - Gui::cmdAppObjectArgs(selection[0].getObject(), - "setDriving(%d,%s)", - ConStr.size() - 1, - "False"); - finishDatumConstraint(this, Obj, false); - } - else { - finishDatumConstraint(this, Obj, true); - } - - return; - } - else if (isCircle(*geom)) { - auto circleSeg = static_cast(geom); - Base::Vector3d ct = circleSeg->getCenter(); - Base::Vector3d d = ct - pnt; - double ActDist = std::abs(d.Length() - circleSeg->getRadius()); - - openCommand(QT_TRANSLATE_NOOP("Command", "Add point to circle Distance constraint")); - Gui::cmdAppObjectArgs(selection[0].getObject(), - "addConstraint(Sketcher.Constraint('Distance',%d,%d,%d,%f))", - GeoId1, - static_cast(PosId1), - GeoId2, - ActDist); - - if (arebothpointsorsegmentsfixed - || constraintCreationMode - == Reference) {// it is a constraint on a external line, make it non-driving - const std::vector& ConStr = Obj->Constraints.getValues(); - - Gui::cmdAppObjectArgs(selection[0].getObject(), - "setDriving(%d,%s)", - ConStr.size() - 1, - "False"); - finishDatumConstraint(this, Obj, false); - } - else { - finishDatumConstraint(this, Obj, true); - } - - return; - } - } - else if (isEdge(GeoId1, PosId1) && isEdge(GeoId2, PosId2)) { - const Part::Geometry* geom1 = Obj->getGeometry(GeoId1); - const Part::Geometry* geom2 = Obj->getGeometry(GeoId2); - - if (isCircle(*geom1) && isCircle(*geom2)) {// circle to circle distance - auto circleSeg1 = static_cast(geom1); - double radius1 = circleSeg1->getRadius(); - Base::Vector3d center1 = circleSeg1->getCenter(); - - auto circleSeg2 = static_cast(geom2); - double radius2 = circleSeg2->getRadius(); - Base::Vector3d center2 = circleSeg2->getCenter(); - - double ActDist = 0.; - - Base::Vector3d intercenter = center1 - center2; - double intercenterdistance = intercenter.Length(); - - if (intercenterdistance >= radius1 && intercenterdistance >= radius2) { - - ActDist = intercenterdistance - radius1 - radius2; - } - else { - double bigradius = std::max(radius1, radius2); - double smallradius = std::min(radius1, radius2); - - ActDist = bigradius - smallradius - intercenterdistance; - } - - openCommand(QT_TRANSLATE_NOOP("Command", "Add circle to circle distance constraint")); - Gui::cmdAppObjectArgs(selection[0].getObject(), - "addConstraint(Sketcher.Constraint('Distance',%d,%d,%f))", - GeoId1, - GeoId2, - ActDist); - - if (arebothpointsorsegmentsfixed - || constraintCreationMode - == Reference) {// it is a constraint on a external line, make it non-driving - const std::vector& ConStr = Obj->Constraints.getValues(); - - Gui::cmdAppObjectArgs(selection[0].getObject(), - "setDriving(%d,%s)", - ConStr.size() - 1, - "False"); - finishDatumConstraint(this, Obj, false); - } - else { - finishDatumConstraint(this, Obj, true); - } - - return; - } - else if ((isCircle(*geom1) && isLineSegment(*geom2)) - || (isLineSegment(*geom1) && isCircle(*geom2))) {// circle to line distance - - if (isLineSegment(*geom1)) { - std::swap(geom1, geom2);// Assume circle is first - std::swap(GeoId1, GeoId2); - } - - auto circleSeg = static_cast(geom1); - double radius = circleSeg->getRadius(); - Base::Vector3d center = circleSeg->getCenter(); - - auto lineSeg = static_cast(geom2); - Base::Vector3d pnt1 = lineSeg->getStartPoint(); - Base::Vector3d pnt2 = lineSeg->getEndPoint(); - Base::Vector3d d = pnt2 - pnt1; - double ActDist = - std::abs(-center.x * d.y + center.y * d.x + pnt1.x * pnt2.y - pnt2.x * pnt1.y) - / d.Length() - - radius; - - openCommand(QT_TRANSLATE_NOOP("Command", "Add circle to line distance constraint")); - Gui::cmdAppObjectArgs(selection[0].getObject(), - "addConstraint(Sketcher.Constraint('Distance',%d,%d,%f)) ", - GeoId1, - GeoId2, - ActDist); - - if (arebothpointsorsegmentsfixed - || constraintCreationMode - == Reference) {// it is a constraint on a external line, make it non-driving - const std::vector& ConStr = Obj->Constraints.getValues(); - - Gui::cmdAppObjectArgs(selection[0].getObject(), - "setDriving(%i,%s)", - ConStr.size() - 1, - "False"); - finishDatumConstraint(this, Obj, false); - } - else { - finishDatumConstraint(this, Obj, true); - } - - return; - } - } - else if (isEdge(GeoId1, PosId1)) {// line length - if (GeoId1 < 0 && GeoId1 >= Sketcher::GeoEnum::VAxis) { - Gui::TranslatedUserWarning(Obj, - QObject::tr("Wrong selection"), - QObject::tr("Cannot add a length constraint on an axis!")); - return; - } - - arebothpointsorsegmentsfixed = isPointOrSegmentFixed(Obj, GeoId1); - - const Part::Geometry* geom = Obj->getGeometry(GeoId1); - - if (isLineSegment(*geom)) { - auto lineSeg = static_cast(geom); - double ActLength = (lineSeg->getEndPoint() - lineSeg->getStartPoint()).Length(); - - openCommand(QT_TRANSLATE_NOOP("Command", "Add length constraint")); - Gui::cmdAppObjectArgs(selection[0].getObject(), - "addConstraint(Sketcher.Constraint('Distance',%d,%f))", - GeoId1, - ActLength); - - // it is a constraint on a external line, make it non-driving - if (arebothpointsorsegmentsfixed || GeoId1 <= Sketcher::GeoEnum::RefExt - || constraintCreationMode == Reference) { - const std::vector& ConStr = Obj->Constraints.getValues(); - - Gui::cmdAppObjectArgs(selection[0].getObject(), - "setDriving(%d,%s)", - ConStr.size() - 1, - "False"); - finishDatumConstraint(this, Obj, false); - } - else { - finishDatumConstraint(this, Obj, true); - } - - return; - } - } - - Gui::TranslatedUserWarning(Obj, - QObject::tr("Wrong selection"), - QObject::tr("Select exactly one line or one point and one line or " - "two points or two circles from the sketch.")); - return; -} - -void CmdSketcherConstrainDistance::applyConstraint(std::vector& selSeq, int seqIndex) -{ - SketcherGui::ViewProviderSketch* sketchgui = - static_cast(getActiveGuiDocument()->getInEdit()); - Sketcher::SketchObject* Obj = sketchgui->getSketchObject(); - - int GeoId1 = GeoEnum::GeoUndef, GeoId2 = GeoEnum::GeoUndef; - Sketcher::PointPos PosId1 = Sketcher::PointPos::none, PosId2 = Sketcher::PointPos::none; - - bool arebothpointsorsegmentsfixed = areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2); - - switch (seqIndex) { - case 0:// {SelVertex, SelVertexOrRoot} - case 1:// {SelRoot, SelVertex} - { - GeoId1 = selSeq.at(0).GeoId; - GeoId2 = selSeq.at(1).GeoId; - PosId1 = selSeq.at(0).PosId; - PosId2 = selSeq.at(1).PosId; - - Base::Vector3d pnt2 = Obj->getPoint(GeoId2, PosId2); - - if (GeoId1 == Sketcher::GeoEnum::HAxis && PosId1 == Sketcher::PointPos::none) { - PosId1 = Sketcher::PointPos::start; - - openCommand( - QT_TRANSLATE_NOOP("Command", "Add distance from horizontal axis constraint")); - Gui::cmdAppObjectArgs( - Obj, - "addConstraint(Sketcher.Constraint('DistanceY',%d,%d,%d,%d,%f))", - GeoId1, - static_cast(PosId1), - GeoId2, - static_cast(PosId2), - pnt2.y); - } - else if (GeoId1 == Sketcher::GeoEnum::VAxis && PosId1 == Sketcher::PointPos::none) { - PosId1 = Sketcher::PointPos::start; - - openCommand( - QT_TRANSLATE_NOOP("Command", "Add distance from vertical axis constraint")); - Gui::cmdAppObjectArgs( - Obj, - "addConstraint(Sketcher.Constraint('DistanceX',%d,%d,%d,%d,%f))", - GeoId1, - static_cast(PosId1), - GeoId2, - static_cast(PosId2), - pnt2.x); - } - else { - Base::Vector3d pnt1 = Obj->getPoint(GeoId1, PosId1); - - openCommand(QT_TRANSLATE_NOOP("Command", "Add point to point distance constraint")); - Gui::cmdAppObjectArgs( - Obj, - "addConstraint(Sketcher.Constraint('Distance',%d,%d,%d,%d,%f))", - GeoId1, - static_cast(PosId1), - GeoId2, - static_cast(PosId2), - (pnt2 - pnt1).Length()); - } - - if (arebothpointsorsegmentsfixed || constraintCreationMode == Reference) { - // it is a constraint on a external line, make it non-driving - const std::vector& ConStr = Obj->Constraints.getValues(); - - Gui::cmdAppObjectArgs(Obj, "setDriving(%d,%s)", ConStr.size() - 1, "False"); - finishDatumConstraint(this, Obj, false); - } - else { - finishDatumConstraint(this, Obj, true); - } - - return; - } - case 2:// {SelEdge} - case 3:// {SelExternalEdge} - { - GeoId1 = selSeq.at(0).GeoId; - - arebothpointsorsegmentsfixed = isPointOrSegmentFixed(Obj, GeoId1); - - const Part::Geometry* geom = Obj->getGeometry(GeoId1); - - if (isLineSegment(*geom)) { - auto lineSeg = static_cast(geom); - double ActLength = (lineSeg->getEndPoint() - lineSeg->getStartPoint()).Length(); - - openCommand(QT_TRANSLATE_NOOP("Command", "Add length constraint")); - Gui::cmdAppObjectArgs(Obj, - "addConstraint(Sketcher.Constraint('Distance',%d,%f))", - GeoId1, - ActLength); - - if (arebothpointsorsegmentsfixed || GeoId1 <= Sketcher::GeoEnum::RefExt - || constraintCreationMode == Reference) { - // it is a constraint on a external line, make it non-driving - const std::vector& ConStr = Obj->Constraints.getValues(); - - Gui::cmdAppObjectArgs(Obj, "setDriving(%d,%s)", ConStr.size() - 1, "False"); - finishDatumConstraint(this, Obj, false); - } - else { - finishDatumConstraint(this, Obj, true); - } - } - else if (isCircle(*geom)) { - // allow this selection but do nothing as it needs 2 circles or 1 circle and 1 line - } - else { - Gui::TranslatedUserWarning( - Obj, - QObject::tr("Wrong selection"), - QObject::tr("This constraint does not make sense for non-linear curves.")); - } - - return; - } - case 4:// {SelVertex, SelEdgeOrAxis} - case 5:// {SelRoot, SelEdge} - case 6:// {SelVertex, SelExternalEdge} - case 7:// {SelRoot, SelExternalEdge} - { - GeoId1 = selSeq.at(0).GeoId; - GeoId2 = selSeq.at(1).GeoId; - PosId1 = selSeq.at(0).PosId; - - Base::Vector3d pnt = Obj->getPoint(GeoId1, PosId1); - const Part::Geometry* geom = Obj->getGeometry(GeoId2); - - if (isLineSegment(*geom)) { - auto lineSeg = static_cast(geom); - Base::Vector3d pnt1 = lineSeg->getStartPoint(); - Base::Vector3d pnt2 = lineSeg->getEndPoint(); - Base::Vector3d d = pnt2 - pnt1; - double ActDist = - std::abs(-pnt.x * d.y + pnt.y * d.x + pnt1.x * pnt2.y - pnt2.x * pnt1.y) - / d.Length(); - - openCommand(QT_TRANSLATE_NOOP("Command", "Add point to line Distance constraint")); - Gui::cmdAppObjectArgs(Obj, - "addConstraint(Sketcher.Constraint('Distance',%d,%d,%d,%f))", - GeoId1, - static_cast(PosId1), - GeoId2, - ActDist); - - if (arebothpointsorsegmentsfixed || constraintCreationMode == Reference) { - // it is a constraint on a external line, make it non-driving - const std::vector& ConStr = Obj->Constraints.getValues(); - - Gui::cmdAppObjectArgs(Obj, "setDriving(%d,%s)", ConStr.size() - 1, "False"); - finishDatumConstraint(this, Obj, false); - } - else { - finishDatumConstraint(this, Obj, true); - } - } - - return; - } - case 8:// {SelEdge, SelEdge} - { - GeoId1 = selSeq.at(0).GeoId; - GeoId2 = selSeq.at(1).GeoId; - const Part::Geometry* geom1 = Obj->getGeometry(GeoId1); - const Part::Geometry* geom2 = Obj->getGeometry(GeoId2); - - if (isCircle(*geom1) && isCircle(*geom2)) {// circle to circle distance - auto circleSeg1 = static_cast(geom1); - double radius1 = circleSeg1->getRadius(); - Base::Vector3d center1 = circleSeg1->getCenter(); - - auto circleSeg2 = static_cast(geom2); - double radius2 = circleSeg2->getRadius(); - Base::Vector3d center2 = circleSeg2->getCenter(); - - double ActDist = 0.; - - Base::Vector3d intercenter = center1 - center2; - double intercenterdistance = intercenter.Length(); - - if (intercenterdistance >= radius1 && intercenterdistance >= radius2) { - - ActDist = intercenterdistance - radius1 - radius2; - } - else { - double bigradius = std::max(radius1, radius2); - double smallradius = std::min(radius1, radius2); - - ActDist = bigradius - smallradius - intercenterdistance; - } - - openCommand( - QT_TRANSLATE_NOOP("Command", "Add circle to circle distance constraint")); - Gui::cmdAppObjectArgs(Obj, - "addConstraint(Sketcher.Constraint('Distance',%d,%d,%f))", - GeoId1, - GeoId2, - ActDist); - - if (arebothpointsorsegmentsfixed - || constraintCreationMode - == Reference) {// it is a constraint on a external line, make it non-driving - const std::vector& ConStr = Obj->Constraints.getValues(); - - Gui::cmdAppObjectArgs(Obj, "setDriving(%d,%s)", ConStr.size() - 1, "False"); - finishDatumConstraint(this, Obj, false); - } - else { - finishDatumConstraint(this, Obj, true); - } - - return; - } - else { - Gui::TranslatedUserWarning( - Obj, - QObject::tr("Wrong selection"), - QObject::tr("Select exactly one line or one point and one line or two points " - "or two circles from the sketch.")); - } - } - default: - break; - } -} - -void CmdSketcherConstrainDistance::updateAction(int mode) -{ - switch (mode) { - case Reference: - if (getAction()) { - getAction()->setIcon( - Gui::BitmapFactory().iconFromTheme("Constraint_Length_Driven")); - } - break; - case Driving: - if (getAction()) { - getAction()->setIcon(Gui::BitmapFactory().iconFromTheme("Constraint_Length")); - } - break; - } -} - -// ====================================================================================== - class CmdSketcherConstrainPointOnObject: public CmdSketcherConstraint { public: @@ -4828,6 +4203,631 @@ void CmdSketcherConstrainPointOnObject::applyConstraint(std::vector& // ====================================================================================== +class CmdSketcherConstrainDistance : public CmdSketcherConstraint +{ +public: + CmdSketcherConstrainDistance(); + ~CmdSketcherConstrainDistance() override + {} + void updateAction(int mode) override; + const char* className() const override + { + return "CmdSketcherConstrainDistance"; + } + +protected: + void activated(int iMsg) override; + void applyConstraint(std::vector& selSeq, int seqIndex) override; +}; + +CmdSketcherConstrainDistance::CmdSketcherConstrainDistance() + : CmdSketcherConstraint("Sketcher_ConstrainDistance") +{ + sAppModule = "Sketcher"; + sGroup = "Sketcher"; + sMenuText = QT_TR_NOOP("Constrain distance"); + sToolTipText = QT_TR_NOOP("Fix a length of a line or the distance between a line and a vertex " + "or between two circles"); + sWhatsThis = "Sketcher_ConstrainDistance"; + sStatusTip = sToolTipText; + sPixmap = "Constraint_Length"; + sAccel = "K, D"; + eType = ForEdit; + + allowedSelSequences = { {SelVertex, SelVertexOrRoot}, + {SelRoot, SelVertex}, + {SelEdge}, + {SelExternalEdge}, + {SelVertex, SelEdgeOrAxis}, + {SelRoot, SelEdge}, + {SelVertex, SelExternalEdge}, + {SelRoot, SelExternalEdge}, + {SelEdge, SelEdge} }; +} + +void CmdSketcherConstrainDistance::activated(int iMsg) +{ + Q_UNUSED(iMsg); + // get the selection + std::vector selection = getSelection().getSelectionEx(); + + // only one sketch with its subelements are allowed to be selected + if (selection.size() != 1 + || !selection[0].isObjectTypeOf(Sketcher::SketchObject::getClassTypeId())) { + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Sketcher"); + bool constraintMode = hGrp->GetBool("ContinuousConstraintMode", true); + + if (constraintMode) { + ActivateHandler(getActiveGuiDocument(), new DrawSketchHandlerGenConstraint(this)); + + getSelection().clearSelection(); + } + else { + Gui::TranslatedUserWarning(getActiveGuiDocument(), + QObject::tr("Wrong selection"), + QObject::tr("Select vertices from the sketch.")); + } + return; + } + + // get the needed lists and objects + const std::vector& SubNames = selection[0].getSubNames(); + Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); + + if (SubNames.empty() || SubNames.size() > 2) { + Gui::TranslatedUserWarning(Obj, + QObject::tr("Wrong selection"), + QObject::tr("Select exactly one line or one point and one line " + "or two points from the sketch.")); + return; + } + + int GeoId1, GeoId2 = GeoEnum::GeoUndef; + Sketcher::PointPos PosId1, PosId2 = Sketcher::PointPos::none; + getIdsFromName(SubNames[0], Obj, GeoId1, PosId1); + if (SubNames.size() == 2) { + getIdsFromName(SubNames[1], Obj, GeoId2, PosId2); + } + + bool arebothpointsorsegmentsfixed = areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2); + + if (isVertex(GeoId1, PosId1) + && (GeoId2 == Sketcher::GeoEnum::VAxis || GeoId2 == Sketcher::GeoEnum::HAxis)) { + std::swap(GeoId1, GeoId2); + std::swap(PosId1, PosId2); + } + + if ((isVertex(GeoId1, PosId1) || GeoId1 == Sketcher::GeoEnum::VAxis + || GeoId1 == Sketcher::GeoEnum::HAxis) + && isVertex(GeoId2, PosId2)) {// point to point distance + + Base::Vector3d pnt2 = Obj->getPoint(GeoId2, PosId2); + + if (GeoId1 == Sketcher::GeoEnum::HAxis && PosId1 == Sketcher::PointPos::none) { + PosId1 = Sketcher::PointPos::start; + + openCommand( + QT_TRANSLATE_NOOP("Command", "Add distance from horizontal axis constraint")); + Gui::cmdAppObjectArgs(selection[0].getObject(), + "addConstraint(Sketcher.Constraint('DistanceY',%d,%d,%d,%d,%f))", + GeoId1, + static_cast(PosId1), + GeoId2, + static_cast(PosId2), + pnt2.y); + } + else if (GeoId1 == Sketcher::GeoEnum::VAxis && PosId1 == Sketcher::PointPos::none) { + PosId1 = Sketcher::PointPos::start; + + openCommand(QT_TRANSLATE_NOOP("Command", "Add distance from vertical axis constraint")); + Gui::cmdAppObjectArgs(selection[0].getObject(), + "addConstraint(Sketcher.Constraint('DistanceX',%d,%d,%d,%d,%f))", + GeoId1, + static_cast(PosId1), + GeoId2, + static_cast(PosId2), + pnt2.x); + } + else { + Base::Vector3d pnt1 = Obj->getPoint(GeoId1, PosId1); + + openCommand(QT_TRANSLATE_NOOP("Command", "Add point to point distance constraint")); + Gui::cmdAppObjectArgs(selection[0].getObject(), + "addConstraint(Sketcher.Constraint('Distance',%d,%d,%d,%d,%f))", + GeoId1, + static_cast(PosId1), + GeoId2, + static_cast(PosId2), + (pnt2 - pnt1).Length()); + } + + if (arebothpointsorsegmentsfixed || constraintCreationMode == Reference) { + // it is a constraint on a external line, make it non-driving + const std::vector& ConStr = Obj->Constraints.getValues(); + + Gui::cmdAppObjectArgs(selection[0].getObject(), + "setDriving(%d,%s)", + ConStr.size() - 1, + "False"); + finishDatumConstraint(this, Obj, false); + } + else { + finishDatumConstraint(this, Obj, true); + } + return; + } + else if ((isVertex(GeoId1, PosId1) && isEdge(GeoId2, PosId2)) + || (isEdge(GeoId1, PosId1) && isVertex(GeoId2, PosId2))) {// point to line distance + if (isVertex(GeoId2, PosId2)) { + std::swap(GeoId1, GeoId2); + std::swap(PosId1, PosId2); + } + Base::Vector3d pnt = Obj->getPoint(GeoId1, PosId1); + const Part::Geometry* geom = Obj->getGeometry(GeoId2); + + if (isLineSegment(*geom)) { + auto lineSeg = static_cast(geom); + Base::Vector3d pnt1 = lineSeg->getStartPoint(); + Base::Vector3d pnt2 = lineSeg->getEndPoint(); + Base::Vector3d d = pnt2 - pnt1; + double ActDist = + std::abs(-pnt.x * d.y + pnt.y * d.x + pnt1.x * pnt2.y - pnt2.x * pnt1.y) + / d.Length(); + + openCommand(QT_TRANSLATE_NOOP("Command", "Add point to line Distance constraint")); + Gui::cmdAppObjectArgs(selection[0].getObject(), + "addConstraint(Sketcher.Constraint('Distance',%d,%d,%d,%f))", + GeoId1, + static_cast(PosId1), + GeoId2, + ActDist); + + if (arebothpointsorsegmentsfixed + || constraintCreationMode + == Reference) {// it is a constraint on a external line, make it non-driving + const std::vector& ConStr = Obj->Constraints.getValues(); + + Gui::cmdAppObjectArgs(selection[0].getObject(), + "setDriving(%d,%s)", + ConStr.size() - 1, + "False"); + finishDatumConstraint(this, Obj, false); + } + else { + finishDatumConstraint(this, Obj, true); + } + + return; + } + else if (isCircle(*geom)) { + auto circleSeg = static_cast(geom); + Base::Vector3d ct = circleSeg->getCenter(); + Base::Vector3d d = ct - pnt; + double ActDist = std::abs(d.Length() - circleSeg->getRadius()); + + openCommand(QT_TRANSLATE_NOOP("Command", "Add point to circle Distance constraint")); + Gui::cmdAppObjectArgs(selection[0].getObject(), + "addConstraint(Sketcher.Constraint('Distance',%d,%d,%d,%f))", + GeoId1, + static_cast(PosId1), + GeoId2, + ActDist); + + if (arebothpointsorsegmentsfixed + || constraintCreationMode + == Reference) {// it is a constraint on a external line, make it non-driving + const std::vector& ConStr = Obj->Constraints.getValues(); + + Gui::cmdAppObjectArgs(selection[0].getObject(), + "setDriving(%d,%s)", + ConStr.size() - 1, + "False"); + finishDatumConstraint(this, Obj, false); + } + else { + finishDatumConstraint(this, Obj, true); + } + + return; + } + } + else if (isEdge(GeoId1, PosId1) && isEdge(GeoId2, PosId2)) { + const Part::Geometry* geom1 = Obj->getGeometry(GeoId1); + const Part::Geometry* geom2 = Obj->getGeometry(GeoId2); + + if (isCircle(*geom1) && isCircle(*geom2)) {// circle to circle distance + auto circleSeg1 = static_cast(geom1); + double radius1 = circleSeg1->getRadius(); + Base::Vector3d center1 = circleSeg1->getCenter(); + + auto circleSeg2 = static_cast(geom2); + double radius2 = circleSeg2->getRadius(); + Base::Vector3d center2 = circleSeg2->getCenter(); + + double ActDist = 0.; + + Base::Vector3d intercenter = center1 - center2; + double intercenterdistance = intercenter.Length(); + + if (intercenterdistance >= radius1 && intercenterdistance >= radius2) { + + ActDist = intercenterdistance - radius1 - radius2; + } + else { + double bigradius = std::max(radius1, radius2); + double smallradius = std::min(radius1, radius2); + + ActDist = bigradius - smallradius - intercenterdistance; + } + + openCommand(QT_TRANSLATE_NOOP("Command", "Add circle to circle distance constraint")); + Gui::cmdAppObjectArgs(selection[0].getObject(), + "addConstraint(Sketcher.Constraint('Distance',%d,%d,%f))", + GeoId1, + GeoId2, + ActDist); + + if (arebothpointsorsegmentsfixed + || constraintCreationMode + == Reference) {// it is a constraint on a external line, make it non-driving + const std::vector& ConStr = Obj->Constraints.getValues(); + + Gui::cmdAppObjectArgs(selection[0].getObject(), + "setDriving(%d,%s)", + ConStr.size() - 1, + "False"); + finishDatumConstraint(this, Obj, false); + } + else { + finishDatumConstraint(this, Obj, true); + } + + return; + } + else if ((isCircle(*geom1) && isLineSegment(*geom2)) + || (isLineSegment(*geom1) && isCircle(*geom2))) {// circle to line distance + + if (isLineSegment(*geom1)) { + std::swap(geom1, geom2);// Assume circle is first + std::swap(GeoId1, GeoId2); + } + + auto circleSeg = static_cast(geom1); + double radius = circleSeg->getRadius(); + Base::Vector3d center = circleSeg->getCenter(); + + auto lineSeg = static_cast(geom2); + Base::Vector3d pnt1 = lineSeg->getStartPoint(); + Base::Vector3d pnt2 = lineSeg->getEndPoint(); + Base::Vector3d d = pnt2 - pnt1; + double ActDist = + std::abs(-center.x * d.y + center.y * d.x + pnt1.x * pnt2.y - pnt2.x * pnt1.y) + / d.Length() + - radius; + + openCommand(QT_TRANSLATE_NOOP("Command", "Add circle to line distance constraint")); + Gui::cmdAppObjectArgs(selection[0].getObject(), + "addConstraint(Sketcher.Constraint('Distance',%d,%d,%f)) ", + GeoId1, + GeoId2, + ActDist); + + if (arebothpointsorsegmentsfixed + || constraintCreationMode + == Reference) {// it is a constraint on a external line, make it non-driving + const std::vector& ConStr = Obj->Constraints.getValues(); + + Gui::cmdAppObjectArgs(selection[0].getObject(), + "setDriving(%i,%s)", + ConStr.size() - 1, + "False"); + finishDatumConstraint(this, Obj, false); + } + else { + finishDatumConstraint(this, Obj, true); + } + + return; + } + } + else if (isEdge(GeoId1, PosId1)) {// line length + if (GeoId1 < 0 && GeoId1 >= Sketcher::GeoEnum::VAxis) { + Gui::TranslatedUserWarning(Obj, + QObject::tr("Wrong selection"), + QObject::tr("Cannot add a length constraint on an axis!")); + return; + } + + arebothpointsorsegmentsfixed = isPointOrSegmentFixed(Obj, GeoId1); + + const Part::Geometry* geom = Obj->getGeometry(GeoId1); + + if (isLineSegment(*geom)) { + auto lineSeg = static_cast(geom); + double ActLength = (lineSeg->getEndPoint() - lineSeg->getStartPoint()).Length(); + + openCommand(QT_TRANSLATE_NOOP("Command", "Add length constraint")); + Gui::cmdAppObjectArgs(selection[0].getObject(), + "addConstraint(Sketcher.Constraint('Distance',%d,%f))", + GeoId1, + ActLength); + + // it is a constraint on a external line, make it non-driving + if (arebothpointsorsegmentsfixed || GeoId1 <= Sketcher::GeoEnum::RefExt + || constraintCreationMode == Reference) { + const std::vector& ConStr = Obj->Constraints.getValues(); + + Gui::cmdAppObjectArgs(selection[0].getObject(), + "setDriving(%d,%s)", + ConStr.size() - 1, + "False"); + finishDatumConstraint(this, Obj, false); + } + else { + finishDatumConstraint(this, Obj, true); + } + + return; + } + } + + Gui::TranslatedUserWarning(Obj, + QObject::tr("Wrong selection"), + QObject::tr("Select exactly one line or one point and one line or " + "two points or two circles from the sketch.")); + return; +} + +void CmdSketcherConstrainDistance::applyConstraint(std::vector& selSeq, int seqIndex) +{ + SketcherGui::ViewProviderSketch* sketchgui = + static_cast(getActiveGuiDocument()->getInEdit()); + Sketcher::SketchObject* Obj = sketchgui->getSketchObject(); + + int GeoId1 = GeoEnum::GeoUndef, GeoId2 = GeoEnum::GeoUndef; + Sketcher::PointPos PosId1 = Sketcher::PointPos::none, PosId2 = Sketcher::PointPos::none; + + bool arebothpointsorsegmentsfixed = areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2); + + switch (seqIndex) { + case 0:// {SelVertex, SelVertexOrRoot} + case 1:// {SelRoot, SelVertex} + { + GeoId1 = selSeq.at(0).GeoId; + GeoId2 = selSeq.at(1).GeoId; + PosId1 = selSeq.at(0).PosId; + PosId2 = selSeq.at(1).PosId; + + Base::Vector3d pnt2 = Obj->getPoint(GeoId2, PosId2); + + if (GeoId1 == Sketcher::GeoEnum::HAxis && PosId1 == Sketcher::PointPos::none) { + PosId1 = Sketcher::PointPos::start; + + openCommand( + QT_TRANSLATE_NOOP("Command", "Add distance from horizontal axis constraint")); + Gui::cmdAppObjectArgs( + Obj, + "addConstraint(Sketcher.Constraint('DistanceY',%d,%d,%d,%d,%f))", + GeoId1, + static_cast(PosId1), + GeoId2, + static_cast(PosId2), + pnt2.y); + } + else if (GeoId1 == Sketcher::GeoEnum::VAxis && PosId1 == Sketcher::PointPos::none) { + PosId1 = Sketcher::PointPos::start; + + openCommand( + QT_TRANSLATE_NOOP("Command", "Add distance from vertical axis constraint")); + Gui::cmdAppObjectArgs( + Obj, + "addConstraint(Sketcher.Constraint('DistanceX',%d,%d,%d,%d,%f))", + GeoId1, + static_cast(PosId1), + GeoId2, + static_cast(PosId2), + pnt2.x); + } + else { + Base::Vector3d pnt1 = Obj->getPoint(GeoId1, PosId1); + + openCommand(QT_TRANSLATE_NOOP("Command", "Add point to point distance constraint")); + Gui::cmdAppObjectArgs( + Obj, + "addConstraint(Sketcher.Constraint('Distance',%d,%d,%d,%d,%f))", + GeoId1, + static_cast(PosId1), + GeoId2, + static_cast(PosId2), + (pnt2 - pnt1).Length()); + } + + if (arebothpointsorsegmentsfixed || constraintCreationMode == Reference) { + // it is a constraint on a external line, make it non-driving + const std::vector& ConStr = Obj->Constraints.getValues(); + + Gui::cmdAppObjectArgs(Obj, "setDriving(%d,%s)", ConStr.size() - 1, "False"); + finishDatumConstraint(this, Obj, false); + } + else { + finishDatumConstraint(this, Obj, true); + } + + return; + } + case 2:// {SelEdge} + case 3:// {SelExternalEdge} + { + GeoId1 = selSeq.at(0).GeoId; + + arebothpointsorsegmentsfixed = isPointOrSegmentFixed(Obj, GeoId1); + + const Part::Geometry* geom = Obj->getGeometry(GeoId1); + + if (isLineSegment(*geom)) { + auto lineSeg = static_cast(geom); + double ActLength = (lineSeg->getEndPoint() - lineSeg->getStartPoint()).Length(); + + openCommand(QT_TRANSLATE_NOOP("Command", "Add length constraint")); + Gui::cmdAppObjectArgs(Obj, + "addConstraint(Sketcher.Constraint('Distance',%d,%f))", + GeoId1, + ActLength); + + if (arebothpointsorsegmentsfixed || GeoId1 <= Sketcher::GeoEnum::RefExt + || constraintCreationMode == Reference) { + // it is a constraint on a external line, make it non-driving + const std::vector& ConStr = Obj->Constraints.getValues(); + + Gui::cmdAppObjectArgs(Obj, "setDriving(%d,%s)", ConStr.size() - 1, "False"); + finishDatumConstraint(this, Obj, false); + } + else { + finishDatumConstraint(this, Obj, true); + } + } + else if (isCircle(*geom)) { + // allow this selection but do nothing as it needs 2 circles or 1 circle and 1 line + } + else { + Gui::TranslatedUserWarning( + Obj, + QObject::tr("Wrong selection"), + QObject::tr("This constraint does not make sense for non-linear curves.")); + } + + return; + } + case 4:// {SelVertex, SelEdgeOrAxis} + case 5:// {SelRoot, SelEdge} + case 6:// {SelVertex, SelExternalEdge} + case 7:// {SelRoot, SelExternalEdge} + { + GeoId1 = selSeq.at(0).GeoId; + GeoId2 = selSeq.at(1).GeoId; + PosId1 = selSeq.at(0).PosId; + + Base::Vector3d pnt = Obj->getPoint(GeoId1, PosId1); + const Part::Geometry* geom = Obj->getGeometry(GeoId2); + + if (isLineSegment(*geom)) { + auto lineSeg = static_cast(geom); + Base::Vector3d pnt1 = lineSeg->getStartPoint(); + Base::Vector3d pnt2 = lineSeg->getEndPoint(); + Base::Vector3d d = pnt2 - pnt1; + double ActDist = + std::abs(-pnt.x * d.y + pnt.y * d.x + pnt1.x * pnt2.y - pnt2.x * pnt1.y) + / d.Length(); + + openCommand(QT_TRANSLATE_NOOP("Command", "Add point to line Distance constraint")); + Gui::cmdAppObjectArgs(Obj, + "addConstraint(Sketcher.Constraint('Distance',%d,%d,%d,%f))", + GeoId1, + static_cast(PosId1), + GeoId2, + ActDist); + + if (arebothpointsorsegmentsfixed || constraintCreationMode == Reference) { + // it is a constraint on a external line, make it non-driving + const std::vector& ConStr = Obj->Constraints.getValues(); + + Gui::cmdAppObjectArgs(Obj, "setDriving(%d,%s)", ConStr.size() - 1, "False"); + finishDatumConstraint(this, Obj, false); + } + else { + finishDatumConstraint(this, Obj, true); + } + } + + return; + } + case 8:// {SelEdge, SelEdge} + { + GeoId1 = selSeq.at(0).GeoId; + GeoId2 = selSeq.at(1).GeoId; + const Part::Geometry* geom1 = Obj->getGeometry(GeoId1); + const Part::Geometry* geom2 = Obj->getGeometry(GeoId2); + + if (isCircle(*geom1) && isCircle(*geom2)) {// circle to circle distance + auto circleSeg1 = static_cast(geom1); + double radius1 = circleSeg1->getRadius(); + Base::Vector3d center1 = circleSeg1->getCenter(); + + auto circleSeg2 = static_cast(geom2); + double radius2 = circleSeg2->getRadius(); + Base::Vector3d center2 = circleSeg2->getCenter(); + + double ActDist = 0.; + + Base::Vector3d intercenter = center1 - center2; + double intercenterdistance = intercenter.Length(); + + if (intercenterdistance >= radius1 && intercenterdistance >= radius2) { + + ActDist = intercenterdistance - radius1 - radius2; + } + else { + double bigradius = std::max(radius1, radius2); + double smallradius = std::min(radius1, radius2); + + ActDist = bigradius - smallradius - intercenterdistance; + } + + openCommand( + QT_TRANSLATE_NOOP("Command", "Add circle to circle distance constraint")); + Gui::cmdAppObjectArgs(Obj, + "addConstraint(Sketcher.Constraint('Distance',%d,%d,%f))", + GeoId1, + GeoId2, + ActDist); + + if (arebothpointsorsegmentsfixed + || constraintCreationMode + == Reference) {// it is a constraint on a external line, make it non-driving + const std::vector& ConStr = Obj->Constraints.getValues(); + + Gui::cmdAppObjectArgs(Obj, "setDriving(%d,%s)", ConStr.size() - 1, "False"); + finishDatumConstraint(this, Obj, false); + } + else { + finishDatumConstraint(this, Obj, true); + } + + return; + } + else { + Gui::TranslatedUserWarning( + Obj, + QObject::tr("Wrong selection"), + QObject::tr("Select exactly one line or one point and one line or two points " + "or two circles from the sketch.")); + } + } + default: + break; + } +} + +void CmdSketcherConstrainDistance::updateAction(int mode) +{ + switch (mode) { + case Reference: + if (getAction()) { + getAction()->setIcon( + Gui::BitmapFactory().iconFromTheme("Constraint_Length_Driven")); + } + break; + case Driving: + if (getAction()) { + getAction()->setIcon(Gui::BitmapFactory().iconFromTheme("Constraint_Length")); + } + break; + } +} + +// ====================================================================================== + class CmdSketcherConstrainDistanceX: public CmdSketcherConstraint { public: From 4c7ff0a6beaabe03d5cf7bb66213b02ff33e1aad Mon Sep 17 00:00:00 2001 From: Paddle Date: Wed, 22 Nov 2023 16:47:51 +0100 Subject: [PATCH 2/4] Sketcher: remove unused cursor_createcoincident[] and DrawSketchHandlerCoincident. They are not used anymore. --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 146 -------------------- 1 file changed, 146 deletions(-) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index f9d11b6e14..2b64c58af0 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -3492,152 +3492,6 @@ void CmdSketcherConstrainBlock::applyConstraint(std::vector& selSeq, // ====================================================================================== -/* XPM */ -static const char* cursor_createcoincident[] = {"32 32 3 1", - "+ c white", - "# c red", - ". c None", - "......+.........................", - "......+.........................", - "......+.........................", - "......+.........................", - "......+.........................", - "................................", - "+++++...+++++...................", - "................................", - "......+.........................", - "......+.........................", - "......+.........................", - "......+.........................", - "......+.........................", - "................................", - "................................", - "................................", - ".................####...........", - "................######..........", - "...............########.........", - "...............########.........", - "...............########.........", - "...............########.........", - "................######..........", - ".................####...........", - "................................", - "................................", - "................................", - "................................", - "................................", - "................................", - "................................", - "................................"}; - -class DrawSketchHandlerCoincident: public DrawSketchHandler -{ -public: - DrawSketchHandlerCoincident() - { - GeoId1 = GeoId2 = GeoEnum::GeoUndef; - PosId1 = PosId2 = Sketcher::PointPos::none; - } - ~DrawSketchHandlerCoincident() override - { - Gui::Selection().rmvSelectionGate(); - } - - void mouseMove(Base::Vector2d onSketchPos) override - { - Q_UNUSED(onSketchPos); - } - - bool pressButton(Base::Vector2d onSketchPos) override - { - Q_UNUSED(onSketchPos); - return true; - } - - bool releaseButton(Base::Vector2d onSketchPos) override - { - int VtId = getPreselectPoint(); - int CrsId = getPreselectCross(); - std::stringstream ss; - int GeoId_temp; - Sketcher::PointPos PosId_temp; - - if (VtId != -1) { - sketchgui->getSketchObject()->getGeoVertexIndex(VtId, GeoId_temp, PosId_temp); - ss << "Vertex" << VtId + 1; - } - else if (CrsId == 0) { - GeoId_temp = Sketcher::GeoEnum::RtPnt; - PosId_temp = Sketcher::PointPos::start; - ss << "RootPoint"; - } - else { - GeoId1 = GeoId2 = GeoEnum::GeoUndef; - PosId1 = PosId2 = Sketcher::PointPos::none; - Gui::Selection().clearSelection(); - - return true; - } - - if (GeoId1 == GeoEnum::GeoUndef) { - GeoId1 = GeoId_temp; - PosId1 = PosId_temp; - Gui::Selection().addSelection(sketchgui->getSketchObject()->getDocument()->getName(), - sketchgui->getSketchObject()->getNameInDocument(), - ss.str().c_str(), - onSketchPos.x, - onSketchPos.y, - 0.f); - } - else { - GeoId2 = GeoId_temp; - PosId2 = PosId_temp; - - // Apply the constraint - Sketcher::SketchObject* Obj = - static_cast(sketchgui->getObject()); - - // undo command open - Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add coincident constraint")); - - // check if this coincidence is already enforced (even indirectly) - bool constraintExists = Obj->arePointsCoincident(GeoId1, PosId1, GeoId2, PosId2); - if (!constraintExists && (GeoId1 != GeoId2)) { - Gui::cmdAppObjectArgs( - sketchgui->getObject(), - "addConstraint(Sketcher.Constraint('Coincident',%d,%d,%d,%d))", - GeoId1, - static_cast(PosId1), - GeoId2, - static_cast(PosId2)); - Gui::Command::commitCommand(); - } - else { - Gui::Command::abortCommand(); - } - } - - return true; - } - -private: - void activated() override - { - Gui::Selection().rmvSelectionGate(); - GenericConstraintSelection* selFilterGate = - new GenericConstraintSelection(sketchgui->getObject()); - selFilterGate->setAllowedSelTypes(SelVertex | SelRoot); - Gui::Selection().addSelectionGate(selFilterGate); - int hotX = 8; - int hotY = 8; - setCursor(QPixmap(cursor_createcoincident), hotX, hotY); - } - -protected: - int GeoId1, GeoId2; - Sketcher::PointPos PosId1, PosId2; -}; - class CmdSketcherConstrainCoincident: public CmdSketcherConstraint { public: From d94fdf795e3c795f7870758dde66b089db721c2d Mon Sep 17 00:00:00 2001 From: Paddle Date: Wed, 22 Nov 2023 18:05:25 +0100 Subject: [PATCH 3/4] Introduce CmdSketcherConstrainCoincidentUnified. This is a unified version of coincident + pointOnObject. This is disabled by default. Nothing changes by default. --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 843 +++++++++++--------- src/Mod/Sketcher/Gui/SketcherSettings.cpp | 2 + src/Mod/Sketcher/Gui/SketcherSettings.ui | 19 + src/Mod/Sketcher/Gui/Workbench.cpp | 31 +- 4 files changed, 500 insertions(+), 395 deletions(-) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 2b64c58af0..7ea8e5d434 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -3489,57 +3489,103 @@ void CmdSketcherConstrainBlock::applyConstraint(std::vector& selSeq, } } - // ====================================================================================== -class CmdSketcherConstrainCoincident: public CmdSketcherConstraint +class CmdSketcherConstrainCoincidentUnified : public CmdSketcherConstraint { public: - CmdSketcherConstrainCoincident(); - ~CmdSketcherConstrainCoincident() override + CmdSketcherConstrainCoincidentUnified(const char* initName = "Sketcher_ConstrainCoincidentUnified"); + ~CmdSketcherConstrainCoincidentUnified() override {} const char* className() const override { - return "CmdSketcherConstrainCoincident"; + return "CmdSketcherConstrainCoincidentUnified"; } protected: + enum class CoincicenceType { + Coincident, + PointOnObject, + Both + }; + void activated(int iMsg) override; + void onActivated(CoincicenceType type); + void activatedCoincident(SketchObject* obj, std::vector points, std::vector curves); + void activatedPointOnObject(SketchObject* obj, std::vector points, std::vector curves); + void applyConstraint(std::vector& selSeq, int seqIndex) override; + void applyConstraintCoincident(std::vector& selSeq, int seqIndex); + void applyConstraintPointOnObject(std::vector& selSeq, int seqIndex); + // returns true if a substitution took place - static bool substituteConstraintCombinations(SketchObject* Obj, - int GeoId1, - PointPos PosId1, - int GeoId2, - PointPos PosId2); + static bool substituteConstraintCombinationsPointOnObject(SketchObject* Obj, int GeoId1, PointPos PosId1, int GeoId2); + static bool substituteConstraintCombinationsCoincident(SketchObject* Obj, int GeoId1, PointPos PosId1, int GeoId2, PointPos PosId2); }; -CmdSketcherConstrainCoincident::CmdSketcherConstrainCoincident() - : CmdSketcherConstraint("Sketcher_ConstrainCoincident") +CmdSketcherConstrainCoincidentUnified::CmdSketcherConstrainCoincidentUnified(const char* initName) + : CmdSketcherConstraint(initName) { sAppModule = "Sketcher"; sGroup = "Sketcher"; sMenuText = QT_TR_NOOP("Constrain coincident"); - sToolTipText = QT_TR_NOOP("Create a coincident constraint between points, or a concentric " - "constraint between circles, arcs, and ellipses"); - sWhatsThis = "Sketcher_ConstrainCoincident"; + sToolTipText = QT_TR_NOOP("Create a coincident constraint between points, or fix a point on an edge, " + "or a concentric constraint between circles, arcs, and ellipses"); + sWhatsThis = "Sketcher_ConstrainCoincidentUnified"; sStatusTip = sToolTipText; - sPixmap = "Constraint_PointOnPoint"; - sAccel = "C"; + sPixmap = "Constraint_PointOnObject"; + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Sketcher/Constraints"); + sAccel = hGrp->GetBool("UnifiedCoincident", false) ? "C" :"C,O"; + eType = ForEdit; - allowedSelSequences = {{SelVertex, SelVertexOrRoot}, + allowedSelSequences = { {SelVertex, SelEdgeOrAxis}, + {SelRoot, SelEdge}, + {SelVertex, SelExternalEdge}, + {SelEdge, SelVertexOrRoot}, + {SelEdgeOrAxis, SelVertex}, + {SelExternalEdge, SelVertex}, + + {SelVertex, SelVertexOrRoot}, {SelRoot, SelVertex}, {SelEdge, SelEdge}, {SelEdge, SelExternalEdge}, - {SelExternalEdge, SelEdge}}; + {SelExternalEdge, SelEdge} }; } -bool CmdSketcherConstrainCoincident::substituteConstraintCombinations(SketchObject* Obj, - int GeoId1, - PointPos PosId1, - int GeoId2, - PointPos PosId2) +bool CmdSketcherConstrainCoincidentUnified::substituteConstraintCombinationsPointOnObject(SketchObject* Obj, int GeoId1, PointPos PosId1, int GeoId2) +{ + const std::vector& cvals = Obj->Constraints.getValues(); + + int cid = 0; + for (std::vector::const_iterator it = cvals.begin(); it != cvals.end(); + ++it, ++cid) { + if ((*it)->Type == Sketcher::Tangent && (*it)->FirstPos == Sketcher::PointPos::none + && (*it)->SecondPos == Sketcher::PointPos::none && (*it)->Third == GeoEnum::GeoUndef + && (((*it)->First == GeoId1 && (*it)->Second == GeoId2) + || ((*it)->Second == GeoId1 && (*it)->First == GeoId2))) { + + // NOTE: This function does not either open or commit a command as it is used for group + // addition it relies on such infrastructure being provided by the caller. + + Gui::cmdAppObjectArgs(Obj, "delConstraint(%d)", cid); + + doEndpointToEdgeTangency(Obj, GeoId1, PosId1, GeoId2); + + notifyConstraintSubstitutions( + QObject::tr("Endpoint to edge tangency was applied instead.")); + + getSelection().clearSelection(); + return true; + } + } + + return false; +} + +bool CmdSketcherConstrainCoincidentUnified::substituteConstraintCombinationsCoincident(SketchObject* Obj, int GeoId1, PointPos PosId1, int GeoId2, PointPos PosId2) { // checks for direct and indirect coincidence constraints bool constraintExists = Obj->arePointsCoincident(GeoId1, PosId1, GeoId2, PosId2); @@ -3551,7 +3597,7 @@ bool CmdSketcherConstrainCoincident::substituteConstraintCombinations(SketchObje int j = 0; for (std::vector::const_iterator it = cvals.begin(); it != cvals.end(); - ++it, ++j) { + ++it, ++j) { if ((*it)->Type == Sketcher::Tangent && (*it)->Third == GeoEnum::GeoUndef && (((*it)->First == GeoId1 && (*it)->Second == GeoId2) || ((*it)->Second == GeoId1 && (*it)->First == GeoId2))) { @@ -3561,9 +3607,9 @@ bool CmdSketcherConstrainCoincident::substituteConstraintCombinations(SketchObje if (constraintExists) { // try to remove any pre-existing direct coincident constraints Gui::cmdAppObjectArgs(Obj, - "delConstraintOnPoint(%d,%d)", - GeoId1, - static_cast(PosId1)); + "delConstraintOnPoint(%d,%d)", + GeoId1, + static_cast(PosId1)); } Gui::cmdAppObjectArgs(Obj, "delConstraint(%d)", j); @@ -3603,9 +3649,25 @@ bool CmdSketcherConstrainCoincident::substituteConstraintCombinations(SketchObje return false; } -void CmdSketcherConstrainCoincident::activated(int iMsg) +void CmdSketcherConstrainCoincidentUnified::activated(int iMsg) { Q_UNUSED(iMsg); + onActivated(CoincicenceType::Both); +} + +void CmdSketcherConstrainCoincidentUnified::onActivated(CoincicenceType type) +{ + QString errorMess; + if (type == CoincicenceType::Coincident) { + errorMess = QObject::tr("Select either several points, or several conics for concentricity."); + } + else if (type == CoincicenceType::PointOnObject) { + errorMess = QObject::tr("Select either one point and several curves, or one curve and several points"); + } + else { + errorMess = QObject::tr("Select either one point and several curves or one curve and several" + " points for pointOnObject, or several points for coincidence, or several conics for concentricity."); + } // get the selection std::vector selection = getSelection().getSelectionEx(); @@ -3622,272 +3684,7 @@ void CmdSketcherConstrainCoincident::activated(int iMsg) getSelection().clearSelection(); } else { - // TODO: Get the exact message from git history and put it here - Gui::TranslatedUserWarning(getActiveGuiDocument(), - QObject::tr("Wrong selection"), - QObject::tr("Select two or more points from the sketch.")); - } - return; - } - - // get the needed lists and objects - const std::vector& SubNames = selection[0].getSubNames(); - Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); - - if (SubNames.size() < 2) { - Gui::TranslatedUserWarning(Obj, - QObject::tr("Wrong selection"), - QObject::tr("Select two or more vertices from the sketch.")); - return; - } - - bool allConicsEdges = true;// If user selects only conics (circle, ellipse, arc, arcOfEllipse) - // then we make concentric constraint. - bool atLeastOneEdge = false; - for (std::vector::const_iterator it = SubNames.begin(); it != SubNames.end(); - ++it) { - int GeoId; - Sketcher::PointPos PosId; - getIdsFromName(*it, Obj, GeoId, PosId); - if (isEdge(GeoId, PosId)) { - atLeastOneEdge = true; - if (!isGeoConcentricCompatible(Obj->getGeometry(GeoId))) { - allConicsEdges = false; - } - } - else { - allConicsEdges = false;// at least one point is selected, so concentric can't be - // applied. - } - - if (atLeastOneEdge && !allConicsEdges) { - Gui::TranslatedUserWarning( - Obj, - QObject::tr("Wrong selection"), - QObject::tr("Select two or more vertices from the sketch for a coincident " - "constraint, or two or more circles, ellipses, arcs or arcs of ellipse " - "for a concentric constraint.")); - return; - } - } - - int GeoId1, GeoId2; - Sketcher::PointPos PosId1, PosId2; - getIdsFromName(SubNames[0], Obj, GeoId1, PosId1); - if (allConicsEdges) { - PosId1 = Sketcher::PointPos::mid; - } - - // undo command open - bool constraintsAdded = false; - openCommand(QT_TRANSLATE_NOOP("Command", "Add coincident constraint")); - for (std::size_t i = 1; i < SubNames.size(); i++) { - getIdsFromName(SubNames[i], Obj, GeoId2, PosId2); - if (allConicsEdges) { - PosId2 = Sketcher::PointPos::mid; - } - - // check if the edge already has a Block constraint - if (areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2)) { - showNoConstraintBetweenFixedGeometry(Obj); - return; - } - - // check if as a consequence of this command undesirable combinations of constraints would - // arise and substitute them with more appropriate counterparts, examples: - // - coincidence + tangency on edge - // - point on object + tangency on edge - if (substituteConstraintCombinations(Obj, GeoId1, PosId1, GeoId2, PosId2)) { - constraintsAdded = true; - break; - } - - // check if this coincidence is already enforced (even indirectly) - bool constraintExists = Obj->arePointsCoincident(GeoId1, PosId1, GeoId2, PosId2); - - if (!constraintExists) { - constraintsAdded = true; - Gui::cmdAppObjectArgs(selection[0].getObject(), - "addConstraint(Sketcher.Constraint('Coincident',%d,%d,%d,%d))", - GeoId1, - static_cast(PosId1), - GeoId2, - static_cast(PosId2)); - } - } - - // finish or abort the transaction and update - if (constraintsAdded) { - commitCommand(); - } - else { - abortCommand(); - } - - tryAutoRecompute(Obj); - - // clear the selection (convenience) - getSelection().clearSelection(); -} - -void CmdSketcherConstrainCoincident::applyConstraint(std::vector& selSeq, int seqIndex) -{ - SketcherGui::ViewProviderSketch* sketchgui = - static_cast(getActiveGuiDocument()->getInEdit()); - Sketcher::SketchObject* Obj = sketchgui->getSketchObject(); - - int GeoId1 = selSeq.at(0).GeoId, GeoId2 = selSeq.at(1).GeoId; - Sketcher::PointPos PosId1 = selSeq.at(0).PosId, PosId2 = selSeq.at(1).PosId; - - switch (seqIndex) { - case 0:// {SelVertex, SelVertexOrRoot} - case 1:// {SelRoot, SelVertex} - // Nothing specific. - break; - case 2:// {SelEdge, SelEdge} - case 3:// {SelEdge, SelExternalEdge} - case 4:// {SelExternalEdge, SelEdge} - // Concentric for circles, ellipse, arc, arcofEllipse only. - if (!isGeoConcentricCompatible(Obj->getGeometry(GeoId1)) - || !isGeoConcentricCompatible(Obj->getGeometry(GeoId2))) { - Gui::TranslatedUserWarning( - Obj, - QObject::tr("Wrong selection"), - QObject::tr( - "Select two vertices from the sketch for a coincident constraint, or two " - "circles, ellipses, arcs or arcs of ellipse for a concentric constraint.")); - return; - } - PosId1 = Sketcher::PointPos::mid; - PosId2 = Sketcher::PointPos::mid; - break; - } - - // check if the edge already has a Block constraint - if (areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2)) { - showNoConstraintBetweenFixedGeometry(Obj); - return; - } - - // undo command open - Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add coincident constraint")); - - // check if this coincidence is already enforced (even indirectly) - bool constraintExists = Obj->arePointsCoincident(GeoId1, PosId1, GeoId2, PosId2); - if (substituteConstraintCombinations(Obj, GeoId1, PosId1, GeoId2, PosId2)) {} - else if (!constraintExists && (GeoId1 != GeoId2)) { - Gui::cmdAppObjectArgs(sketchgui->getObject(), - "addConstraint(Sketcher.Constraint('Coincident', %d, %d, %d, %d))", - GeoId1, - static_cast(PosId1), - GeoId2, - static_cast(PosId2)); - } - else { - Gui::Command::abortCommand(); - return; - } - Gui::Command::commitCommand(); - tryAutoRecompute(Obj); -} - -// ====================================================================================== - -class CmdSketcherConstrainPointOnObject: public CmdSketcherConstraint -{ -public: - CmdSketcherConstrainPointOnObject(); - ~CmdSketcherConstrainPointOnObject() override - {} - const char* className() const override - { - return "CmdSketcherConstrainPointOnObject"; - } - -protected: - void activated(int iMsg) override; - void applyConstraint(std::vector& selSeq, int seqIndex) override; - // returns true if a substitution took place - static bool - substituteConstraintCombinations(SketchObject* Obj, int GeoId1, PointPos PosId1, int GeoId2); -}; - -CmdSketcherConstrainPointOnObject::CmdSketcherConstrainPointOnObject() - : CmdSketcherConstraint("Sketcher_ConstrainPointOnObject") -{ - sAppModule = "Sketcher"; - sGroup = "Sketcher"; - sMenuText = QT_TR_NOOP("Constrain point onto object"); - sToolTipText = QT_TR_NOOP("Fix a point onto an object"); - sWhatsThis = "Sketcher_ConstrainPointOnObject"; - sStatusTip = sToolTipText; - sPixmap = "Constraint_PointOnObject"; - sAccel = "O"; - eType = ForEdit; - - allowedSelSequences = {{SelVertex, SelEdgeOrAxis}, - {SelRoot, SelEdge}, - {SelVertex, SelExternalEdge}, - {SelEdge, SelVertexOrRoot}, - {SelEdgeOrAxis, SelVertex}, - {SelExternalEdge, SelVertex}}; -} - -bool CmdSketcherConstrainPointOnObject::substituteConstraintCombinations(SketchObject* Obj, - int GeoId1, - PointPos PosId1, - int GeoId2) -{ - const std::vector& cvals = Obj->Constraints.getValues(); - - int cid = 0; - for (std::vector::const_iterator it = cvals.begin(); it != cvals.end(); - ++it, ++cid) { - if ((*it)->Type == Sketcher::Tangent && (*it)->FirstPos == Sketcher::PointPos::none - && (*it)->SecondPos == Sketcher::PointPos::none && (*it)->Third == GeoEnum::GeoUndef - && (((*it)->First == GeoId1 && (*it)->Second == GeoId2) - || ((*it)->Second == GeoId1 && (*it)->First == GeoId2))) { - - // NOTE: This function does not either open or commit a command as it is used for group - // addition it relies on such infrastructure being provided by the caller. - - Gui::cmdAppObjectArgs(Obj, "delConstraint(%d)", cid); - - doEndpointToEdgeTangency(Obj, GeoId1, PosId1, GeoId2); - - notifyConstraintSubstitutions( - QObject::tr("Endpoint to edge tangency was applied instead.")); - - getSelection().clearSelection(); - return true; - } - } - - return false; -} - -void CmdSketcherConstrainPointOnObject::activated(int iMsg) -{ - Q_UNUSED(iMsg); - // get the selection - std::vector selection = getSelection().getSelectionEx(); - - // only one sketch with its subelements are allowed to be selected - if (selection.size() != 1 - || !selection[0].isObjectTypeOf(Sketcher::SketchObject::getClassTypeId())) { - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( - "User parameter:BaseApp/Preferences/Mod/Sketcher"); - bool constraintMode = hGrp->GetBool("ContinuousConstraintMode", true); - - if (constraintMode) { - ActivateHandler(getActiveGuiDocument(), new DrawSketchHandlerGenConstraint(this)); - getSelection().clearSelection(); - } - else { - // TODO: Get the exact message from git history and put it here - Gui::TranslatedUserWarning(getActiveGuiDocument(), - QObject::tr("Wrong selection"), - QObject::tr("Select the right things from the sketch.")); + Gui::TranslatedUserWarning(getActiveGuiDocument(), QObject::tr("Wrong selection"), errorMess); } return; } @@ -3910,99 +3707,203 @@ void CmdSketcherConstrainPointOnObject::activated(int iMsg) } } - if ((points.size() == 1 && !curves.empty()) || (!points.empty() && curves.size() == 1)) { - - openCommand(QT_TRANSLATE_NOOP("Command", "Add point on object constraint")); - int cnt = 0; - for (std::size_t iPnt = 0; iPnt < points.size(); iPnt++) { - for (std::size_t iCrv = 0; iCrv < curves.size(); iCrv++) { - if (areBothPointsOrSegmentsFixed(Obj, points[iPnt].GeoId, curves[iCrv].GeoId)) { - showNoConstraintBetweenFixedGeometry(Obj); - continue; - } - if (points[iPnt].GeoId == curves[iCrv].GeoId) { - continue;// constraining a point of an element onto the element is a bad idea... - } - - const Part::Geometry* geom = Obj->getGeometry(curves[iCrv].GeoId); - - if (geom && isBsplinePole(geom)) { - Gui::TranslatedUserWarning( - Obj, - QObject::tr("Wrong selection"), - QObject::tr("Select an edge that is not a B-spline weight.")); - abortCommand(); - - continue; - } - - if (substituteConstraintCombinations(Obj, - points[iPnt].GeoId, - points[iPnt].PosId, - curves[iCrv].GeoId)) { - cnt++; - continue; - } - - cnt++; - Gui::cmdAppObjectArgs( - selection[0].getObject(), - "addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))", - points[iPnt].GeoId, - static_cast(points[iPnt].PosId), - curves[iCrv].GeoId); - } - } - if (cnt) { - commitCommand(); - getSelection().clearSelection(); - } - else { - abortCommand(); - Gui::TranslatedUserWarning(Obj, - QObject::tr("Wrong selection"), - QObject::tr("None of the selected points were constrained " - "onto the respective curves, " - "because they are parts " - "of the same element, " - "because they are both external geometry, " - "or because the edge is not eligible.")); - } - return; + if (type != CoincicenceType::Coincident && ((points.size() == 1 && !curves.empty()) || (!points.empty() && curves.size() == 1))) { + activatedPointOnObject(Obj, points, curves); } + else if (type != CoincicenceType::PointOnObject && ((!points.empty() && curves.empty()) || (points.empty() && !curves.empty()))) { + activatedCoincident(Obj, points, curves); + } + else { + Gui::TranslatedUserWarning(Obj, QObject::tr("Wrong selection"), errorMess); + } +} - Gui::TranslatedUserWarning(Obj, - QObject::tr("Wrong selection"), - QObject::tr("Select either one point and several curves, " - "or one curve and several points.")); +void CmdSketcherConstrainCoincidentUnified::activatedPointOnObject(SketchObject* obj, std::vector points, std::vector curves) +{ + openCommand(QT_TRANSLATE_NOOP("Command", "Add point on object constraint")); + int cnt = 0; + for (std::size_t iPnt = 0; iPnt < points.size(); iPnt++) { + for (std::size_t iCrv = 0; iCrv < curves.size(); iCrv++) { + if (areBothPointsOrSegmentsFixed(obj, points[iPnt].GeoId, curves[iCrv].GeoId)) { + showNoConstraintBetweenFixedGeometry(obj); + continue; + } + if (points[iPnt].GeoId == curves[iCrv].GeoId) { + continue;// constraining a point of an element onto the element is a bad idea... + } + + const Part::Geometry* geom = obj->getGeometry(curves[iCrv].GeoId); + + if (geom && isBsplinePole(geom)) { + Gui::TranslatedUserWarning( + obj, + QObject::tr("Wrong selection"), + QObject::tr("Select an edge that is not a B-spline weight.")); + abortCommand(); + + continue; + } + + if (substituteConstraintCombinationsPointOnObject(obj, + points[iPnt].GeoId, + points[iPnt].PosId, + curves[iCrv].GeoId)) { + cnt++; + continue; + } + + cnt++; + Gui::cmdAppObjectArgs( + obj, + "addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))", + points[iPnt].GeoId, + static_cast(points[iPnt].PosId), + curves[iCrv].GeoId); + } + } + if (cnt) { + commitCommand(); + getSelection().clearSelection(); + } + else { + abortCommand(); + Gui::TranslatedUserWarning(obj, + QObject::tr("Wrong selection"), + QObject::tr("None of the selected points were constrained " + "onto the respective curves, " + "because they are parts " + "of the same element, " + "because they are both external geometry, " + "or because the edge is not eligible.")); + } return; } -void CmdSketcherConstrainPointOnObject::applyConstraint(std::vector& selSeq, - int seqIndex) +void CmdSketcherConstrainCoincidentUnified::activatedCoincident(SketchObject* obj, std::vector points, std::vector curves) +{ + bool allConicsEdges = true;// If user selects only conics (circle, ellipse, arc, arcOfEllipse) + // then we make concentric constraint. + for (auto& curve : curves) { + if (!isGeoConcentricCompatible(obj->getGeometry(curve.GeoId))) { + allConicsEdges = false; + } + + if (!allConicsEdges) { + Gui::TranslatedUserWarning( + obj, + QObject::tr("Wrong selection"), + QObject::tr("Select two or more vertices from the sketch for a coincident " + "constraint, or two or more circles, ellipses, arcs or arcs of ellipse " + "for a concentric constraint.")); + return; + } + curve.PosId = Sketcher::PointPos::mid; + } + + std::vector vecOfSelIdToUse = curves.empty() ? points : curves; + + int GeoId1 = vecOfSelIdToUse[0].GeoId; + Sketcher::PointPos PosId1 = vecOfSelIdToUse[0].PosId; + + // undo command open + bool constraintsAdded = false; + openCommand(QT_TRANSLATE_NOOP("Command", "Add coincident constraint")); + + for (std::size_t i = 1; i < vecOfSelIdToUse.size(); i++) { + int GeoId2 = vecOfSelIdToUse[i].GeoId; + Sketcher::PointPos PosId2 = vecOfSelIdToUse[i].PosId; + + // check if the edge already has a Block constraint + if (areBothPointsOrSegmentsFixed(obj, GeoId1, GeoId2)) { + showNoConstraintBetweenFixedGeometry(obj); + return; + } + + // check if as a consequence of this command undesirable combinations of constraints would + // arise and substitute them with more appropriate counterparts, examples: + // - coincidence + tangency on edge + // - point on object + tangency on edge + if (substituteConstraintCombinationsCoincident(obj, GeoId1, PosId1, GeoId2, PosId2)) { + constraintsAdded = true; + break; + } + + // check if this coincidence is already enforced (even indirectly) + bool constraintExists = obj->arePointsCoincident(GeoId1, PosId1, GeoId2, PosId2); + + if (!constraintExists) { + constraintsAdded = true; + Gui::cmdAppObjectArgs(obj, + "addConstraint(Sketcher.Constraint('Coincident',%d,%d,%d,%d))", + GeoId1, + static_cast(PosId1), + GeoId2, + static_cast(PosId2)); + } + } + + // finish or abort the transaction and update + if (constraintsAdded) { + commitCommand(); + } + else { + abortCommand(); + } + + tryAutoRecompute(obj); + + // clear the selection (convenience) + getSelection().clearSelection(); +} + +void CmdSketcherConstrainCoincidentUnified::applyConstraint(std::vector& selSeq, int seqIndex) +{ + switch (seqIndex) { + case 0:// {SelVertex, SelEdgeOrAxis} + case 1:// {SelRoot, SelEdge} + case 2:// {SelVertex, SelExternalEdge} + case 3:// {SelEdge, SelVertexOrRoot} + case 4:// {SelEdgeOrAxis, SelVertex} + case 5:// {SelExternalEdge, SelVertex} + applyConstraintPointOnObject(selSeq, seqIndex); + break; + case 6:// {SelVertex, SelVertexOrRoot} + case 7:// {SelRoot, SelVertex} + case 8:// {SelEdge, SelEdge} + case 9:// {SelEdge, SelExternalEdge} + case 10:// {SelExternalEdge, SelEdge} + seqIndex -= 6; + applyConstraintCoincident(selSeq, seqIndex); + break; + default: + return; + } +} + +void CmdSketcherConstrainCoincidentUnified::applyConstraintPointOnObject(std::vector& selSeq, int seqIndex) { int GeoIdVt, GeoIdCrv; Sketcher::PointPos PosIdVt; switch (seqIndex) { - case 0:// {SelVertex, SelEdgeOrAxis} - case 1:// {SelRoot, SelEdge} - case 2:// {SelVertex, SelExternalEdge} - GeoIdVt = selSeq.at(0).GeoId; - GeoIdCrv = selSeq.at(1).GeoId; - PosIdVt = selSeq.at(0).PosId; + case 0:// {SelVertex, SelEdgeOrAxis} + case 1:// {SelRoot, SelEdge} + case 2:// {SelVertex, SelExternalEdge} + GeoIdVt = selSeq.at(0).GeoId; + GeoIdCrv = selSeq.at(1).GeoId; + PosIdVt = selSeq.at(0).PosId; - break; - case 3:// {SelEdge, SelVertexOrRoot} - case 4:// {SelEdgeOrAxis, SelVertex} - case 5:// {SelExternalEdge, SelVertex} - GeoIdVt = selSeq.at(1).GeoId; - GeoIdCrv = selSeq.at(0).GeoId; - PosIdVt = selSeq.at(1).PosId; + break; + case 3:// {SelEdge, SelVertexOrRoot} + case 4:// {SelEdgeOrAxis, SelVertex} + case 5:// {SelExternalEdge, SelVertex} + GeoIdVt = selSeq.at(1).GeoId; + GeoIdCrv = selSeq.at(0).GeoId; + PosIdVt = selSeq.at(1).PosId; - break; - default: - return; + break; + default: + return; } SketcherGui::ViewProviderSketch* sketchgui = @@ -4024,20 +3925,20 @@ void CmdSketcherConstrainPointOnObject::applyConstraint(std::vector& if (geom && isBsplinePole(geom)) { Gui::TranslatedUserWarning(Obj, - QObject::tr("Wrong selection"), - QObject::tr("Select an edge that is not a B-spline weight.")); + QObject::tr("Wrong selection"), + QObject::tr("Select an edge that is not a B-spline weight.")); abortCommand(); return; } if (allOK) { - if (!substituteConstraintCombinations(Obj, GeoIdVt, PosIdVt, GeoIdCrv)) { + if (!substituteConstraintCombinationsPointOnObject(Obj, GeoIdVt, PosIdVt, GeoIdCrv)) { Gui::cmdAppObjectArgs(sketchgui->getObject(), - "addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))", - GeoIdVt, - static_cast(PosIdVt), - GeoIdCrv); + "addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))", + GeoIdVt, + static_cast(PosIdVt), + GeoIdCrv); } commitCommand(); @@ -4046,15 +3947,180 @@ void CmdSketcherConstrainPointOnObject::applyConstraint(std::vector& else { abortCommand(); Gui::TranslatedUserWarning(Obj, - QObject::tr("Wrong selection"), - QObject::tr("None of the selected points " - "were constrained onto the respective curves, " - "either because they are parts of the same element, " - "or because they are both external geometry.")); + QObject::tr("Wrong selection"), + QObject::tr("None of the selected points " + "were constrained onto the respective curves, " + "either because they are parts of the same element, " + "or because they are both external geometry.")); } return; } +void CmdSketcherConstrainCoincidentUnified::applyConstraintCoincident(std::vector& selSeq, int seqIndex) +{ + SketcherGui::ViewProviderSketch* sketchgui = + static_cast(getActiveGuiDocument()->getInEdit()); + Sketcher::SketchObject* Obj = sketchgui->getSketchObject(); + + int GeoId1 = selSeq.at(0).GeoId, GeoId2 = selSeq.at(1).GeoId; + Sketcher::PointPos PosId1 = selSeq.at(0).PosId, PosId2 = selSeq.at(1).PosId; + + switch (seqIndex) { + case 0:// {SelVertex, SelVertexOrRoot} + case 1:// {SelRoot, SelVertex} + // Nothing specific. + break; + case 2:// {SelEdge, SelEdge} + case 3:// {SelEdge, SelExternalEdge} + case 4:// {SelExternalEdge, SelEdge} + // Concentric for circles, ellipse, arc, arcofEllipse only. + if (!isGeoConcentricCompatible(Obj->getGeometry(GeoId1)) + || !isGeoConcentricCompatible(Obj->getGeometry(GeoId2))) { + Gui::TranslatedUserWarning( + Obj, + QObject::tr("Wrong selection"), + QObject::tr( + "Select two vertices from the sketch for a coincident constraint, or two " + "circles, ellipses, arcs or arcs of ellipse for a concentric constraint.")); + return; + } + PosId1 = Sketcher::PointPos::mid; + PosId2 = Sketcher::PointPos::mid; + break; + } + + // check if the edge already has a Block constraint + if (areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2)) { + showNoConstraintBetweenFixedGeometry(Obj); + return; + } + + // undo command open + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add coincident constraint")); + + // check if this coincidence is already enforced (even indirectly) + bool constraintExists = Obj->arePointsCoincident(GeoId1, PosId1, GeoId2, PosId2); + if (substituteConstraintCombinationsCoincident(Obj, GeoId1, PosId1, GeoId2, PosId2)) {} + else if (!constraintExists && (GeoId1 != GeoId2)) { + Gui::cmdAppObjectArgs(sketchgui->getObject(), + "addConstraint(Sketcher.Constraint('Coincident', %d, %d, %d, %d))", + GeoId1, + static_cast(PosId1), + GeoId2, + static_cast(PosId2)); + } + else { + Gui::Command::abortCommand(); + return; + } + Gui::Command::commitCommand(); + tryAutoRecompute(Obj); +} + + +// ====================================================================================== + +class CmdSketcherConstrainCoincident: public CmdSketcherConstrainCoincidentUnified +{ +public: + CmdSketcherConstrainCoincident(); + ~CmdSketcherConstrainCoincident() override + {} + const char* className() const override + { + return "CmdSketcherConstrainCoincident"; + } + +protected: + void activated(int iMsg) override; + void applyConstraint(std::vector& selSeq, int seqIndex) override; +}; + +CmdSketcherConstrainCoincident::CmdSketcherConstrainCoincident() + : CmdSketcherConstrainCoincidentUnified("Sketcher_ConstrainCoincident") +{ + sAppModule = "Sketcher"; + sGroup = "Sketcher"; + sMenuText = QT_TR_NOOP("Constrain coincident"); + sToolTipText = QT_TR_NOOP("Create a coincident constraint between points, or a concentric " + "constraint between circles, arcs, and ellipses"); + sWhatsThis = "Sketcher_ConstrainCoincident"; + sStatusTip = sToolTipText; + sPixmap = "Constraint_PointOnPoint"; + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Sketcher/Constraints"); + sAccel = hGrp->GetBool("UnifiedCoincident", false) ? "C,C" : "C"; + eType = ForEdit; + + allowedSelSequences = {{SelVertex, SelVertexOrRoot}, + {SelRoot, SelVertex}, + {SelEdge, SelEdge}, + {SelEdge, SelExternalEdge}, + {SelExternalEdge, SelEdge}}; +} + +void CmdSketcherConstrainCoincident::activated(int iMsg) +{ + Q_UNUSED(iMsg); + onActivated(CoincicenceType::Coincident); +} + +void CmdSketcherConstrainCoincident::applyConstraint(std::vector& selSeq, int seqIndex) +{ + applyConstraintCoincident(selSeq, seqIndex); +} + +// ====================================================================================== + +class CmdSketcherConstrainPointOnObject: public CmdSketcherConstrainCoincidentUnified +{ +public: + CmdSketcherConstrainPointOnObject(); + ~CmdSketcherConstrainPointOnObject() override + {} + const char* className() const override + { + return "CmdSketcherConstrainPointOnObject"; + } + +protected: + void activated(int iMsg) override; + void applyConstraint(std::vector& selSeq, int seqIndex) override; +}; + +CmdSketcherConstrainPointOnObject::CmdSketcherConstrainPointOnObject() + : CmdSketcherConstrainCoincidentUnified("Sketcher_ConstrainPointOnObject") +{ + sAppModule = "Sketcher"; + sGroup = "Sketcher"; + sMenuText = QT_TR_NOOP("Constrain point onto object"); + sToolTipText = QT_TR_NOOP("Fix a point onto an object"); + sWhatsThis = "Sketcher_ConstrainPointOnObject"; + sStatusTip = sToolTipText; + sPixmap = "Constraint_PointOnObject"; + sAccel = "O"; + eType = ForEdit; + + allowedSelSequences = {{SelVertex, SelEdgeOrAxis}, + {SelRoot, SelEdge}, + {SelVertex, SelExternalEdge}, + {SelEdge, SelVertexOrRoot}, + {SelEdgeOrAxis, SelVertex}, + {SelExternalEdge, SelVertex}}; +} + +void CmdSketcherConstrainPointOnObject::activated(int iMsg) +{ + Q_UNUSED(iMsg); + onActivated(CoincicenceType::PointOnObject); +} + +void CmdSketcherConstrainPointOnObject::applyConstraint(std::vector& selSeq, + int seqIndex) +{ + applyConstraintPointOnObject(selSeq, seqIndex); +} + // ====================================================================================== class CmdSketcherConstrainDistance : public CmdSketcherConstraint @@ -9784,6 +9850,7 @@ void CreateSketcherCommandsConstraints() rcCmdMgr.addCommand(new CmdSketcherCompHorizontalVertical()); rcCmdMgr.addCommand(new CmdSketcherConstrainLock()); rcCmdMgr.addCommand(new CmdSketcherConstrainBlock()); + rcCmdMgr.addCommand(new CmdSketcherConstrainCoincidentUnified()); rcCmdMgr.addCommand(new CmdSketcherConstrainCoincident()); rcCmdMgr.addCommand(new CmdSketcherDimension()); rcCmdMgr.addCommand(new CmdSketcherConstrainParallel()); diff --git a/src/Mod/Sketcher/Gui/SketcherSettings.cpp b/src/Mod/Sketcher/Gui/SketcherSettings.cpp index 973957b259..69fff96822 100644 --- a/src/Mod/Sketcher/Gui/SketcherSettings.cpp +++ b/src/Mod/Sketcher/Gui/SketcherSettings.cpp @@ -66,6 +66,7 @@ void SketcherSettings::saveSettings() ui->checkBoxEnableEscape->onSave(); ui->checkBoxNotifyConstraintSubstitutions->onSave(); ui->checkBoxAutoRemoveRedundants->onSave(); + ui->checkBoxUnifiedCoincident->onSave(); enum { @@ -133,6 +134,7 @@ void SketcherSettings::loadSettings() ui->checkBoxEnableEscape->onRestore(); ui->checkBoxNotifyConstraintSubstitutions->onRestore(); ui->checkBoxAutoRemoveRedundants->onRestore(); + ui->checkBoxUnifiedCoincident->onRestore(); // Dimensioning constraints mode ui->dimensioningMode->clear(); diff --git a/src/Mod/Sketcher/Gui/SketcherSettings.ui b/src/Mod/Sketcher/Gui/SketcherSettings.ui index 7d8658c676..2bc1a4da76 100644 --- a/src/Mod/Sketcher/Gui/SketcherSettings.ui +++ b/src/Mod/Sketcher/Gui/SketcherSettings.ui @@ -159,6 +159,25 @@ Requires to re-enter edit mode to take effect. + + + + Unify Coincident and PointOnObject in a single tool. + + + Unify Coincident and PointOnObject + + + false + + + UnifiedCoincident + + + Mod/Sketcher/Constraints + + + diff --git a/src/Mod/Sketcher/Gui/Workbench.cpp b/src/Mod/Sketcher/Gui/Workbench.cpp index bfdf659f1d..3720c7ad8e 100644 --- a/src/Mod/Sketcher/Gui/Workbench.cpp +++ b/src/Mod/Sketcher/Gui/Workbench.cpp @@ -428,9 +428,17 @@ inline void SketcherAddWorkbenchConstraints(T& cons); template<> inline void SketcherAddWorkbenchConstraints(Gui::MenuItem& cons) { - cons << "Sketcher_ConstrainCoincident" - << "Sketcher_ConstrainPointOnObject" - << "Sketcher_ConstrainVertical" + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Sketcher/Constraints"); + + if (hGrp->GetBool("UnifiedCoincident", false)) { + cons << "Sketcher_ConstrainCoincidentUnified"; + } + else { + cons << "Sketcher_ConstrainCoincident" + << "Sketcher_ConstrainPointOnObject"; + } + cons << "Sketcher_ConstrainVertical" << "Sketcher_ConstrainHorizontal" << "Sketcher_ConstrainHorVer" << "Sketcher_ConstrainParallel" @@ -459,11 +467,16 @@ template<> inline void SketcherAddWorkbenchConstraints(Gui::ToolBarItem& cons) { ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( - "User parameter:BaseApp/Preferences/Mod/Sketcher/dimensioning"); + "User parameter:BaseApp/Preferences/Mod/Sketcher/Constraints"); - cons << "Sketcher_ConstrainCoincident" - << "Sketcher_ConstrainPointOnObject" - << "Sketcher_CompHorVer" + if (hGrp->GetBool("UnifiedCoincident", false)) { + cons << "Sketcher_ConstrainCoincidentUnified"; + } + else { + cons << "Sketcher_ConstrainCoincident" + << "Sketcher_ConstrainPointOnObject"; + } + cons << "Sketcher_CompHorVer" << "Sketcher_ConstrainParallel" << "Sketcher_ConstrainPerpendicular" << "Sketcher_ConstrainTangent" @@ -471,6 +484,10 @@ inline void SketcherAddWorkbenchConstraints(Gui::ToolBarItem& << "Sketcher_ConstrainSymmetric" << "Sketcher_ConstrainBlock" << "Separator"; + + hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Sketcher/dimensioning"); + if (hGrp->GetBool("SingleDimensioningTool", true)) { if (!hGrp->GetBool("SeparatedDimensioningTools", false)) { cons << "Sketcher_CompDimensionTools"; From bc4605aa6a21a5842b19f8bfb504e88ae1041f5f Mon Sep 17 00:00:00 2001 From: Paddle Date: Tue, 28 Nov 2023 09:45:35 +0100 Subject: [PATCH 4/4] Add a setting to disable auto horizontal/vertical. --- src/Mod/Sketcher/Gui/SketcherSettings.cpp | 2 ++ src/Mod/Sketcher/Gui/SketcherSettings.ui | 19 +++++++++++++++++++ src/Mod/Sketcher/Gui/Workbench.cpp | 10 ++++++++-- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/Mod/Sketcher/Gui/SketcherSettings.cpp b/src/Mod/Sketcher/Gui/SketcherSettings.cpp index 69fff96822..a316235e49 100644 --- a/src/Mod/Sketcher/Gui/SketcherSettings.cpp +++ b/src/Mod/Sketcher/Gui/SketcherSettings.cpp @@ -67,6 +67,7 @@ void SketcherSettings::saveSettings() ui->checkBoxNotifyConstraintSubstitutions->onSave(); ui->checkBoxAutoRemoveRedundants->onSave(); ui->checkBoxUnifiedCoincident->onSave(); + ui->checkBoxHorVerAuto->onSave(); enum { @@ -135,6 +136,7 @@ void SketcherSettings::loadSettings() ui->checkBoxNotifyConstraintSubstitutions->onRestore(); ui->checkBoxAutoRemoveRedundants->onRestore(); ui->checkBoxUnifiedCoincident->onRestore(); + ui->checkBoxHorVerAuto->onRestore(); // Dimensioning constraints mode ui->dimensioningMode->clear(); diff --git a/src/Mod/Sketcher/Gui/SketcherSettings.ui b/src/Mod/Sketcher/Gui/SketcherSettings.ui index 2bc1a4da76..a3efd77d5f 100644 --- a/src/Mod/Sketcher/Gui/SketcherSettings.ui +++ b/src/Mod/Sketcher/Gui/SketcherSettings.ui @@ -178,6 +178,25 @@ Requires to re-enter edit mode to take effect. + + + + Use the automatic horizontal/vertical constraint tool. This create a command group in which you have the auto tool, horizontal and vertical. + + + Auto tool for Horizontal/Vertical + + + true + + + AutoHorVer + + + Mod/Sketcher/Constraints + + + diff --git a/src/Mod/Sketcher/Gui/Workbench.cpp b/src/Mod/Sketcher/Gui/Workbench.cpp index 3720c7ad8e..0cc9a4a5bc 100644 --- a/src/Mod/Sketcher/Gui/Workbench.cpp +++ b/src/Mod/Sketcher/Gui/Workbench.cpp @@ -476,8 +476,14 @@ inline void SketcherAddWorkbenchConstraints(Gui::ToolBarItem& cons << "Sketcher_ConstrainCoincident" << "Sketcher_ConstrainPointOnObject"; } - cons << "Sketcher_CompHorVer" - << "Sketcher_ConstrainParallel" + if (hGrp->GetBool("AutoHorVer", true)) { + cons << "Sketcher_CompHorVer"; + } + else { + cons << "Sketcher_ConstrainVertical" + << "Sketcher_ConstrainHorizontal"; + } + cons << "Sketcher_ConstrainParallel" << "Sketcher_ConstrainPerpendicular" << "Sketcher_ConstrainTangent" << "Sketcher_ConstrainEqual"