From b10b9bf22d6ac1ae559f8da3005a8e7313f0b7b0 Mon Sep 17 00:00:00 2001 From: Paddle Date: Thu, 22 Jun 2023 22:32:28 +0200 Subject: [PATCH 01/12] Sketcher: Constrain Contextual implementation. --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 1161 ++++++++++++++++- src/Mod/Sketcher/Gui/DrawSketchHandler.cpp | 13 + src/Mod/Sketcher/Gui/DrawSketchHandler.h | 3 + src/Mod/Sketcher/Gui/EditDatumDialog.cpp | 15 +- src/Mod/Sketcher/Gui/EditDatumDialog.h | 4 +- src/Mod/Sketcher/Gui/Resources/Sketcher.qrc | 2 + .../constraints/Constraint_Contextual.svg | 253 ++++ .../Constraint_Contextual_Driven.svg | 276 ++++ src/Mod/Sketcher/Gui/SketcherSettings.cpp | 68 + src/Mod/Sketcher/Gui/SketcherSettings.h | 1 + src/Mod/Sketcher/Gui/SketcherSettings.ui | 50 + src/Mod/Sketcher/Gui/Workbench.cpp | 27 +- 12 files changed, 1859 insertions(+), 14 deletions(-) create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/constraints/Constraint_Contextual.svg create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/constraints/Constraint_Contextual_Driven.svg diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 37b1701d4b..8e5ca0f432 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -50,7 +50,7 @@ #include "Utils.h" #include "ViewProviderSketch.h" #include "ui_InsertDatum.h" - +#include using namespace std; using namespace SketcherGui; @@ -990,6 +990,1163 @@ void CmdSketcherConstraint::activated(int /*iMsg*/) getSelection().clearSelection(); } + +// Contextual Constraint tool ======================================================= + +class DrawSketchHandlerConstrainContextual : public DrawSketchHandler +{ +public: + DrawSketchHandlerConstrainContextual() + : specialConstraint(SpecialConstraint::None) + , availableConstraint(AvailableConstraint::FIRST) + , previousOnSketchPos(Base::Vector2d(0.f, 0.f)) + , selPoints({}) + , selLine({}) + , selCircleArc({}) + , selEllipseAndCo({}) + , numberOfConstraintsCreated(0) + { + } + virtual ~DrawSketchHandlerConstrainContextual() + { + } + + enum class AvailableConstraint { + FIRST, + SECOND, + THIRD, + FOURTH, + FIFTH, + RESET + }; + + enum class SpecialConstraint { + LineOr2PointsDistance, + Block, + None + }; + + void activated() override + { + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Contextual Constrain")); + + Obj = sketchgui->getSketchObject(); + + // Constrain icon size in px + qreal pixelRatio = devicePixelRatio(); + const unsigned long defaultCrosshairColor = 0xFFFFFF; + unsigned long color = getCrosshairColor(); + auto colorMapping = std::map(); + colorMapping[defaultCrosshairColor] = color; + + qreal fullIconWidth = 32 * pixelRatio; + qreal iconWidth = 16 * pixelRatio; + QPixmap cursorPixmap = Gui::BitmapFactory().pixmapFromSvg("Sketcher_Crosshair", QSizeF(fullIconWidth, fullIconWidth), colorMapping), + icon = Gui::BitmapFactory().pixmapFromSvg("Constraint_Contextual", QSizeF(iconWidth, iconWidth)); + QPainter cursorPainter; + cursorPainter.begin(&cursorPixmap); + cursorPainter.drawPixmap(16 * pixelRatio, 16 * pixelRatio, icon); + cursorPainter.end(); + int hotX = 8; + int hotY = 8; + cursorPixmap.setDevicePixelRatio(pixelRatio); + // only X11 needs hot point coordinates to be scaled + if (qGuiApp->platformName() == QLatin1String("xcb")) { + hotX *= pixelRatio; + hotY *= pixelRatio; + } + setCursor(cursorPixmap, hotX, hotY, false); + } + + void deactivated() override + { + Gui::Command::abortCommand(); + //TODO: When user exit sketch edit while tool is activated solve() crashes. solve is needed to refresh the sketch after abortCommand + Obj->solve(); + sketchgui->draw(false, false); // Redraw + } + + virtual void registerPressedKey(bool pressed, int key) + { + if ((key == SoKeyboardEvent::RIGHT_SHIFT || key == SoKeyboardEvent::LEFT_SHIFT) && pressed) { + if (availableConstraint == AvailableConstraint::FIRST) { + availableConstraint = AvailableConstraint::SECOND; + } + else if (availableConstraint == AvailableConstraint::SECOND) { + availableConstraint = AvailableConstraint::THIRD; + } + else if (availableConstraint == AvailableConstraint::THIRD) { + availableConstraint = AvailableConstraint::FOURTH; + } + else if (availableConstraint == AvailableConstraint::FOURTH) { + availableConstraint = AvailableConstraint::FIFTH; + } + else if (availableConstraint == AvailableConstraint::FIFTH || availableConstraint == AvailableConstraint::RESET) { + availableConstraint = AvailableConstraint::FIRST; + } + makeAppropriateConstraint(previousOnSketchPos); + } + } + + virtual void mouseMove(Base::Vector2d onSketchPos) + { + const std::vector& ConStr = Obj->Constraints.getValues(); + previousOnSketchPos = onSketchPos; + + //Change distance constraint based on position of mouse. + if (specialConstraint == SpecialConstraint::LineOr2PointsDistance) + updateDistanceType(onSketchPos); + + //Move constraints + if (numberOfConstraintsCreated > 0) { + bool oneMoved = false; + for (int i = 0; i < numberOfConstraintsCreated; i++) { + if (ConStr[ConStr.size() - 1 - i]->isDimensional()) { + Base::Vector2d pointWhereToMove = onSketchPos; + + if (specialConstraint == SpecialConstraint::Block) { + if (i == 0) + pointWhereToMove.x = Obj->getPoint(selPoints[0].GeoId, selPoints[0].PosId).x; + else + pointWhereToMove.y = Obj->getPoint(selPoints[0].GeoId, selPoints[0].PosId).y; + } + moveConstraint(ConStr.size() - 1 - i, pointWhereToMove); + oneMoved = true; + } + } + if (oneMoved) + sketchgui->draw(false, false); // Redraw + } + } + + virtual bool pressButton(Base::Vector2d onSketchPos) + { + return true; + } + + virtual bool releaseButton(Base::Vector2d onSketchPos) + { + Q_UNUSED(onSketchPos); + + availableConstraint = AvailableConstraint::FIRST; + SelIdPair selIdPair; + selIdPair.GeoId = GeoEnum::GeoUndef; + selIdPair.PosId = Sketcher::PointPos::none; + std::stringstream ss; + Base::Type newselGeoType = Base::Type::badType(); + + int VtId = getPreselectPoint(); + int CrvId = getPreselectCurve(); + int CrsId = getPreselectCross(); + + if (VtId >= 0) { //Vertex + Obj->getGeoVertexIndex(VtId, + selIdPair.GeoId, selIdPair.PosId); + newselGeoType = Part::GeomPoint::getClassTypeId(); + ss << "Vertex" << VtId + 1; + } + else if (CrsId == 0) { //RootPoint + selIdPair.GeoId = Sketcher::GeoEnum::RtPnt; + selIdPair.PosId = Sketcher::PointPos::start; + newselGeoType = Part::GeomPoint::getClassTypeId(); + ss << "RootPoint"; + } + else if (CrsId == 1) { //H_Axis + selIdPair.GeoId = Sketcher::GeoEnum::HAxis; + newselGeoType = Part::GeomLineSegment::getClassTypeId(); + ss << "H_Axis"; + } + else if (CrsId == 2) { //V_Axis + selIdPair.GeoId = Sketcher::GeoEnum::VAxis; + newselGeoType = Part::GeomLineSegment::getClassTypeId(); + ss << "V_Axis"; + } + else if (CrvId >= 0 || CrvId <= Sketcher::GeoEnum::RefExt) { //Curves + selIdPair.GeoId = CrvId; + const Part::Geometry* geo = Obj->getGeometry(CrvId); + + newselGeoType = geo->getTypeId(); + + if (CrvId >= 0) { + ss << "Edge" << CrvId + 1; + } + else { + ss << "ExternalEdge" << Sketcher::GeoEnum::RefExt + 1 - CrvId; + } + } + + + if (selIdPair.GeoId == GeoEnum::GeoUndef) { + // If mouse is released on "blank" space, finalize and start over + // Ask for the value of datum constraints + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); + bool show = hGrp->GetBool("ShowDialogOnDistanceConstraint", true); + const std::vector& ConStr = Obj->Constraints.getValues(); + + bool commandHandledInEditDatum = false; + for (int i = numberOfConstraintsCreated - 1; i >= 0; i--) { + if (show && ConStr[ConStr.size() - 1 - i]->isDimensional() && ConStr[ConStr.size() - 1 - i]->isDriving) { + commandHandledInEditDatum = true; + EditDatumDialog editDatumDialog(sketchgui, ConStr.size() - 1 - i); + editDatumDialog.exec(); + if (!editDatumDialog.isSuccess()) { + break; + } + } + } + + if (!commandHandledInEditDatum) + Gui::Command::commitCommand(); + + // This code enables the continuous creation mode. + bool continuousMode = hGrp->GetBool("ContinuousCreationMode", true); + if (continuousMode) { + Gui::Selection().clearSelection(); + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Constrain contextually")); + numberOfConstraintsCreated = 0; + specialConstraint = SpecialConstraint::None; + previousOnSketchPos = Base::Vector2d(0.f, 0.f); + selPoints.clear(); + selLine.clear(); + selCircleArc.clear(); + selEllipseAndCo.clear(); + } + else { + sketchgui->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider + } + } + + else if (notSelectedYet(selIdPair)) { + //add the geometry to its type vector. Temporarily if not selAllowed + if (newselGeoType == Part::GeomPoint::getClassTypeId()) { + selPoints.push_back(selIdPair); + } + else if (newselGeoType == Part::GeomLineSegment::getClassTypeId()) { + selLine.push_back(selIdPair); + } + else if (newselGeoType == Part::GeomArcOfCircle::getClassTypeId() + || newselGeoType == Part::GeomCircle::getClassTypeId()) { + selCircleArc.push_back(selIdPair); + } + else if (newselGeoType == Part::GeomEllipse::getClassTypeId() + || newselGeoType == Part::GeomArcOfEllipse::getClassTypeId() + || newselGeoType == Part::GeomArcOfHyperbola::getClassTypeId() + || newselGeoType == Part::GeomArcOfParabola::getClassTypeId()) { + selEllipseAndCo.push_back(selIdPair); + } + + bool selAllowed = makeAppropriateConstraint(onSketchPos); + + if (selAllowed) { + // If mouse is released on something allowed, select it + Gui::Selection().addSelection(Obj->getDocument()->getName(), + Obj->getNameInDocument(), + ss.str().c_str(), onSketchPos.x, onSketchPos.y, 0.f); + sketchgui->draw(false, false); // Redraw + } + else { + if (newselGeoType == Part::GeomPoint::getClassTypeId()) { + selPoints.pop_back(); + } + else if (newselGeoType == Part::GeomLineSegment::getClassTypeId()) { + selLine.pop_back(); + } + else if (newselGeoType == Part::GeomArcOfCircle::getClassTypeId() + || newselGeoType == Part::GeomCircle::getClassTypeId()) { + selCircleArc.pop_back(); + } + else if (newselGeoType == Part::GeomEllipse::getClassTypeId() + || newselGeoType == Part::GeomArcOfEllipse::getClassTypeId() + || newselGeoType == Part::GeomArcOfHyperbola::getClassTypeId() + || newselGeoType == Part::GeomArcOfParabola::getClassTypeId()) { + selEllipseAndCo.pop_back(); + } + } + } + return true; + } +protected: + SpecialConstraint specialConstraint; + AvailableConstraint availableConstraint; + + Base::Vector2d previousOnSketchPos; + + std::vector selPoints; + std::vector selLine; + std::vector selCircleArc; + std::vector selEllipseAndCo; + + int numberOfConstraintsCreated; + + Sketcher::SketchObject* Obj; + + bool notSelectedYet(const SelIdPair& elem) + { + auto contains = [&](const std::vector& vec, const SelIdPair& elem) { + for (const auto& x : vec) + { + if (x.GeoId == elem.GeoId && x.PosId == elem.PosId) + return true; + } + return false; + }; + + return !contains(selPoints, elem) + && !contains(selLine, elem) + && !contains(selCircleArc, elem) + && !contains(selEllipseAndCo, elem); + } + + bool makeAppropriateConstraint(Base::Vector2d onSketchPos) { + bool selAllowed = false; + if (selPoints.size() > 0) { + if (selPoints.size() == 1 && selLine.size() == 0 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + //Lock, autodistance + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add lock constraint")); + specialConstraint = SpecialConstraint::Block; + createDistanceXYConstrain(Sketcher::DistanceX, selPoints[0].GeoId, selPoints[0].PosId, Sketcher::GeoEnum::RtPnt, Sketcher::PointPos::start, onSketchPos); + createDistanceXYConstrain(Sketcher::DistanceY, selPoints[0].GeoId, selPoints[0].PosId, Sketcher::GeoEnum::RtPnt, Sketcher::PointPos::start, onSketchPos); + selAllowed = true; + } + if (availableConstraint == AvailableConstraint::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Distance to origin' constraint")); + createDistanceConstrain(selPoints[0].GeoId, selPoints[0].PosId, Sketcher::GeoEnum::RtPnt, Sketcher::PointPos::start, onSketchPos); + availableConstraint = AvailableConstraint::RESET; + } + } + else if (selPoints.size() == 2 && selLine.size() == 0 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + //distance, horizontal, vertical + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance constraint")); + createDistanceConstrain(selPoints[0].GeoId, selPoints[0].PosId, selPoints[1].GeoId, selPoints[1].PosId, onSketchPos); + selAllowed = true; + } + if (availableConstraint == AvailableConstraint::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Horizontal' constraints")); + createHorizontalConstrain(selPoints[0].GeoId, selPoints[0].PosId, selPoints[1].GeoId, selPoints[1].PosId); + } + if (availableConstraint == AvailableConstraint::THIRD) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Vertical' constraints")); + createVerticalConstrain(selPoints[0].GeoId, selPoints[0].PosId, selPoints[1].GeoId, selPoints[1].PosId); + availableConstraint = AvailableConstraint::RESET; + } + } + else if (selPoints.size() == 1 && selLine.size() == 1 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + //distance, Symmetry + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add point to line Distance constraint")); + createDistanceConstrain(selPoints[0].GeoId, selPoints[0].PosId, selLine[0].GeoId, selLine[0].PosId, onSketchPos); // line to be on second parameter + selAllowed = true; + } + if (availableConstraint == AvailableConstraint::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Symmetry constraint")); + createSymmetryConstrain(selLine[0].GeoId, Sketcher::PointPos::start, selLine[0].GeoId, Sketcher::PointPos::end, selPoints[0].GeoId, selPoints[0].PosId); + availableConstraint = AvailableConstraint::RESET; + } + } + else if (selPoints.size() == 3 && selLine.size() == 0 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + //Horizontal, vertical, symmetry + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Horizontal' constraints")); + for (int i = 0; i < selPoints.size() - 1; i++) { + createHorizontalConstrain(selPoints[i].GeoId, selPoints[i].PosId, selPoints[i + 1].GeoId, selPoints[i + 1].PosId); + } + selAllowed = true; + } + if (availableConstraint == AvailableConstraint::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Vertical' constraints")); + for (int i = 0; i < selPoints.size() - 1; i++) { + createVerticalConstrain(selPoints[i].GeoId, selPoints[i].PosId, selPoints[i + 1].GeoId, selPoints[i + 1].PosId); + } + } + if (availableConstraint == AvailableConstraint::THIRD) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Symmetry constraints")); + createSymmetryConstrain(selPoints[0].GeoId, selPoints[0].PosId, selPoints[1].GeoId, selPoints[1].PosId, selPoints[2].GeoId, selPoints[2].PosId); + availableConstraint = AvailableConstraint::RESET; + } + } + else if (selPoints.size() >= 4 && selLine.size() == 0 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + //Horizontal, vertical + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Horizontal' constraints")); + for (int i = 0; i < selPoints.size() - 1; i++) { + createHorizontalConstrain(selPoints[i].GeoId, selPoints[i].PosId, selPoints[i + 1].GeoId, selPoints[i + 1].PosId); + } + selAllowed = true; + } + if (availableConstraint == AvailableConstraint::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Vertical' constraints")); + for (int i = 0; i < selPoints.size() - 1; i++) { + createVerticalConstrain(selPoints[i].GeoId, selPoints[i].PosId, selPoints[i + 1].GeoId, selPoints[i + 1].PosId); + } + availableConstraint = AvailableConstraint::RESET; + } + } + else if (selPoints.size() == 2 && selLine.size() == 1 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + //symmetry, distances + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Symmetry constraint")); + createSymmetryConstrain(selPoints[0].GeoId, selPoints[0].PosId, selPoints[1].GeoId, selPoints[1].PosId, selLine[0].GeoId, selLine[0].PosId); + selAllowed = true; + } + if (availableConstraint == AvailableConstraint::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance constraints")); + for (int i = 0; i < selPoints.size(); i++) { + createDistanceConstrain(selPoints[i].GeoId, selPoints[i].PosId, selLine[0].GeoId, selLine[0].PosId, onSketchPos); + } + availableConstraint = AvailableConstraint::RESET; + } + } + else if (selPoints.size() >= 3 && selLine.size() == 1 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + //distances + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance constraints")); + for (int i = 0; i < selPoints.size(); i++) { + createDistanceConstrain(selPoints[i].GeoId, selPoints[i].PosId, selLine[0].GeoId, selLine[0].PosId, onSketchPos); + } + selAllowed = true; + availableConstraint = AvailableConstraint::RESET; + } + } + else if (selPoints.size() >= 1 && selLine.size() == 0 && selCircleArc.size() == 1 && selEllipseAndCo.size() == 0) { + //distance between 1 point and circle/arc not supported yet. + if (availableConstraint == AvailableConstraint::FIRST) { + //nothing yet + //availableConstraint = AvailableConstraint::RESET; + } + } + else if (selPoints.size() >= 1 && selLine.size() == 0 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 1) { + //distance between 1 point and elipse/arc of... not supported yet. + if (availableConstraint == AvailableConstraint::FIRST) { + //nothing yet + //availableConstraint = AvailableConstraint::RESET; + } + } + } + else if (selLine.size() > 0) { + if (selPoints.size() == 0 && selLine.size() == 1 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + //axis can be selected but we don't want distance on axis! + if ((selLine[0].GeoId != Sketcher::GeoEnum::VAxis && selLine[0].GeoId != Sketcher::GeoEnum::HAxis)) { + //distance, horizontal, vertical, block + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add length constraint")); + createDistanceConstrain(selLine[0].GeoId, Sketcher::PointPos::start, selLine[0].GeoId, Sketcher::PointPos::end, onSketchPos); + selAllowed = true; + } + if (availableConstraint == AvailableConstraint::SECOND) { + if (isHorizontalVerticalBlock(selLine[0].GeoId)) { + //if the line has a vertical horizontal or block constraint then we don't switch to other modes as they are horizontal, vertical and block. + availableConstraint = AvailableConstraint::RESET; + } + else { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Horizontal constraint")); + createHorizontalConstrain(selLine[0].GeoId, Sketcher::PointPos::none, GeoEnum::GeoUndef, Sketcher::PointPos::none); + } + } + if (availableConstraint == AvailableConstraint::THIRD) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Vertical constraint")); + createVerticalConstrain(selLine[0].GeoId, Sketcher::PointPos::none, GeoEnum::GeoUndef, Sketcher::PointPos::none); + } + if (availableConstraint == AvailableConstraint::FOURTH) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Block constraint")); + createBlockConstrain(selLine[0].GeoId); + availableConstraint = AvailableConstraint::RESET; + } + } + else { + //But axis can still be selected + selAllowed = true; + } + } + else if (selPoints.size() == 0 && selLine.size() == 2 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + //angle (if parallel: Distance (see in createAngleConstrain)), equal. + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Angle constraint")); + createAngleConstrain(selLine[0].GeoId, selLine[1].GeoId, onSketchPos); + selAllowed = true; + } + if (availableConstraint == AvailableConstraint::SECOND) { + if (selLine[0].GeoId == Sketcher::GeoEnum::VAxis || selLine[1].GeoId == Sketcher::GeoEnum::VAxis + || selLine[0].GeoId == Sketcher::GeoEnum::HAxis || selLine[1].GeoId == Sketcher::GeoEnum::HAxis) { + //if one line is axis, then can't equal.. + } + else { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraint")); + createEqualityConstrain(selLine[0].GeoId, selLine[1].GeoId); + } + availableConstraint = AvailableConstraint::RESET; + } + } + else if (selPoints.size() == 0 && selLine.size() >= 3 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + //equality. + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraints")); + for (int i = 0; i < selLine.size() - 1; i++) { + createEqualityConstrain(selLine[i].GeoId, selLine[i + 1].GeoId); + } + selAllowed = true; + availableConstraint = AvailableConstraint::RESET; + } + } + else if (selPoints.size() == 0 && selLine.size() == 1 && selCircleArc.size() == 1 && selEllipseAndCo.size() == 0) { + //Distance. + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add length constraint")); + createDistanceConstrain(selCircleArc[0].GeoId, selCircleArc[0].PosId, selLine[0].GeoId, selLine[0].PosId, onSketchPos); // line to be on second parameter + selAllowed = true; + availableConstraint = AvailableConstraint::RESET; + } + } + else if (selPoints.size() == 0 && selLine.size() == 1 && selCircleArc.size() == 2 && selEllipseAndCo.size() == 0) { + //symmetry. + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Symmetry constraints")); + createSymmetryConstrain(selCircleArc[0].GeoId, Sketcher::PointPos::mid, selCircleArc[1].GeoId, Sketcher::PointPos::mid, selLine[0].GeoId, selLine[0].PosId); + selAllowed = true; + availableConstraint = AvailableConstraint::RESET; + } + } + else if (selPoints.size() == 0 && selLine.size() == 1 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 1) { + //TODO distance between line and ellipse/arc of... not supported yet. + if (availableConstraint == AvailableConstraint::FIRST) { + //selAllowed = true; + //availableConstraint = AvailableConstraint::RESET; + } + } + } + else if (selCircleArc.size() > 0) { + if (selPoints.size() == 0 && selLine.size() == 0 && selCircleArc.size() == 1 && selEllipseAndCo.size() == 0) { + //Radius/diameter. Mode changes in createRadiusDiameterConstrain. + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Radius constraint")); + createRadiusDiameterConstrain(selCircleArc[0].GeoId, onSketchPos); + selAllowed = true; + } + else if (selPoints.size() == 0 && selLine.size() == 0 && selCircleArc.size() == 2 && selEllipseAndCo.size() == 0) { + //Distance, radial distance, equality + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add length constraint")); + createDistanceConstrain(selCircleArc[0].GeoId, selCircleArc[0].PosId, selCircleArc[1].GeoId, selCircleArc[1].PosId, onSketchPos); + selAllowed = true; + } + if (availableConstraint == AvailableConstraint::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add concentric and length constraint")); + createDistanceConstrain(selCircleArc[0].GeoId, selCircleArc[0].PosId, selCircleArc[1].GeoId, selCircleArc[1].PosId, onSketchPos); + bool created = createCoincidenceConstrain(selCircleArc[0].GeoId, Sketcher::PointPos::mid, selCircleArc[1].GeoId, Sketcher::PointPos::mid); + if (!created) { //Already concentric, so skip to next + availableConstraint = AvailableConstraint::THIRD; + } + } + if (availableConstraint == AvailableConstraint::THIRD) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraint")); + for (int i = 0; i < selCircleArc.size() - 1; i++) { + createEqualityConstrain(selCircleArc[i].GeoId, selCircleArc[i + 1].GeoId); + } + availableConstraint = AvailableConstraint::RESET; + } + } + else if (selPoints.size() == 0 && selLine.size() == 0 && selCircleArc.size() > 2 && selEllipseAndCo.size() == 0) { + //equality. + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraint")); + for (int i = 0; i < selCircleArc.size() - 1; i++) { + createEqualityConstrain(selCircleArc[i].GeoId, selCircleArc[i + 1].GeoId); + } + selAllowed = true; + availableConstraint = AvailableConstraint::RESET; + } + } + else if (selPoints.size() == 0 && selLine.size() == 0 && selCircleArc.size() == 1 && selEllipseAndCo.size() == 1) { + //TODO distance between circle and ellipse/arc of... not supported yet. + if (availableConstraint == AvailableConstraint::FIRST) { + //selAllowed = true; + //availableConstraint = AvailableConstraint::RESET; + } + } + } + else if (selEllipseAndCo.size() > 0) { + if (selPoints.size() == 0 && selLine.size() == 0 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 1) { + //One ellipse or arc of ellipse/hyperbola/parabola - no constrain to attribute + selAllowed = true; + } + else if (selPoints.size() == 0 && selLine.size() == 0 && selCircleArc.size() == 0 && selEllipseAndCo.size() > 1) { + //only ellipse or arc of of same kind, then equality of all radius. + bool allTheSame = 1; + const Part::Geometry* geom = Obj->getGeometry(selEllipseAndCo[0].GeoId); + Base::Type typeOf = geom->getTypeId(); + for (int i = 1; i < selEllipseAndCo.size(); i++) { + const Part::Geometry* geomi = Obj->getGeometry(selEllipseAndCo[i].GeoId); + if (typeOf != geomi->getTypeId()) { + allTheSame = 0; + } + } + if (allTheSame) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraint")); + for (int i = 1; i < selEllipseAndCo.size(); i++) { + createEqualityConstrain(selEllipseAndCo[0].GeoId, selEllipseAndCo[i].GeoId); + } + selAllowed = true; + } + } + } + return selAllowed; + } + + void createDistanceConstrain(int GeoId1, Sketcher::PointPos PosId1, int GeoId2, Sketcher::PointPos PosId2, Base::Vector2d onSketchPos) { + //We make sure that if there's a line, it is GeoId2. + if (GeoId1 == GeoId2 || (PosId1 != Sketcher::PointPos::none && PosId2 != Sketcher::PointPos::none)) { + specialConstraint = SpecialConstraint::LineOr2PointsDistance; + } + + bool arebothpointsorsegmentsfixed = isPointOrSegmentFixed(Obj, GeoId1) && isPointOrSegmentFixed(Obj, GeoId2); + + if (PosId1 != Sketcher::PointPos::none && PosId2 == Sketcher::PointPos::none) { // Point-line case (and point-circle in the future) + Base::Vector3d pnt = Obj->getPoint(GeoId1, PosId1); + const Part::Geometry* geom = Obj->getGeometry(GeoId2); + if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { + const Part::GeomLineSegment* 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(); + + Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Distance',%d,%d,%d,%f)) ", + GeoId1, static_cast(PosId1), GeoId2, ActDist); + } + //else if (geom->getTypeId() == Part::GeomCircle::getClassTypeId()) { + // const Part::GeomCircle* circle = static_cast(geom); + //} + } + else if (PosId1 == Sketcher::PointPos::none && PosId2 == Sketcher::PointPos::none) { // Circle - line, circle - circle cases + const Part::Geometry* geo1 = Obj->getGeometry(GeoId1); + const Part::Geometry* geo2 = Obj->getGeometry(GeoId2); + + if (geo1->getTypeId() == Part::GeomCircle::getClassTypeId() + && geo2->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { // Circle - line case + auto circleSeg = static_cast(geo1); + double radius = circleSeg->getRadius(); + Base::Vector3d center = circleSeg->getCenter(); + + auto lineSeg = static_cast(geo2); + 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; + + Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Distance',%d,%d,%f))", + GeoId1, GeoId2, ActDist); + } + else if (geo1->getTypeId() == Part::GeomCircle::getClassTypeId() + && geo2->getTypeId() == Part::GeomCircle::getClassTypeId()) { // Circle - circle case + auto circleSeg1 = static_cast(geo1); + double radius1 = circleSeg1->getRadius(); + Base::Vector3d center1 = circleSeg1->getCenter(); + + auto circleSeg2 = static_cast(geo2); + 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; + } + + Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Distance',%d,%d,%f))", + GeoId1, GeoId2, ActDist); + } + } + else { //both points + Base::Vector3d pnt1 = Obj->getPoint(GeoId1, PosId1); + Base::Vector3d pnt2 = Obj->getPoint(GeoId2, PosId2); + + Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Distance',%d,%d,%d,%d,%f)) ", + GeoId1, static_cast(PosId1), GeoId2, static_cast(PosId2), (pnt2 - pnt1).Length()); + } + + const std::vector& ConStr = Obj->Constraints.getValues(); + if (arebothpointsorsegmentsfixed + || GeoId1 <= Sketcher::GeoEnum::RefExt + || constraintCreationMode == Reference) { + // it is a constraint on a external line, make it non-driving + Gui::cmdAppObjectArgs(Obj, "setDriving(%i,%s)", ConStr.size() - 1, "False"); + } + + numberOfConstraintsCreated++; + moveConstraint(ConStr.size() - 1, onSketchPos); + } + + void createDistanceXYConstrain(Sketcher::ConstraintType type, int GeoId1, Sketcher::PointPos PosId1, int GeoId2, Sketcher::PointPos PosId2, Base::Vector2d onSketchPos) { + Base::Vector3d pnt1 = Obj->getPoint(GeoId1, PosId1); + Base::Vector3d pnt2 = Obj->getPoint(GeoId2, PosId2); + double ActLength = pnt2.x - pnt1.x; + + if (type == Sketcher::DistanceY) { + ActLength = pnt2.y - pnt1.y; + } + + //negative sign avoidance: swap the points to make value positive + if (ActLength < -Precision::Confusion()) { + std::swap(GeoId1, GeoId2); + std::swap(PosId1, PosId2); + std::swap(pnt1, pnt2); + ActLength = -ActLength; + } + + if (type == Sketcher::DistanceY) { + Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('DistanceY',%d,%d,%d,%d,%f)) ", + GeoId1, static_cast(PosId1), GeoId2, static_cast(PosId2), ActLength); + } + else { + Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('DistanceX',%d,%d,%d,%d,%f)) ", + GeoId1, static_cast(PosId1), GeoId2, static_cast(PosId2), ActLength); + } + + const std::vector& ConStr = Obj->Constraints.getValues(); + if (areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2) || constraintCreationMode == Reference) { + // it is a constraint on a external line, make it non-driving + Gui::cmdAppObjectArgs(Obj, "setDriving(%i,%s)", + ConStr.size() - 1, "False"); + } + + numberOfConstraintsCreated++; + moveConstraint(ConStr.size() - 1, onSketchPos); + } + + void createRadiusDiameterConstrain(int GeoId, Base::Vector2d onSketchPos) { + double radius = 0.0; + bool isCircle = true; + + const Part::Geometry* geom = Obj->getGeometry(GeoId); + if (geom && geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { + const Part::GeomArcOfCircle* arc = static_cast(geom); + radius = arc->getRadius(); + isCircle = false; + } + else if (geom && geom->getTypeId() == Part::GeomCircle::getClassTypeId()) { + const Part::GeomCircle* circle = static_cast(geom); + radius = circle->getRadius(); + } + + if (isBsplinePole(geom)) + Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Weight',%d,%f)) ", + GeoId, radius); + else { + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/dimensioning"); + bool dimensioningDiameter = hGrp->GetBool("DimensioningDiameter", true); + bool dimensioningRadius = hGrp->GetBool("DimensioningRadius", true); + + bool firstCstr = true; + if (availableConstraint != AvailableConstraint::FIRST) { + firstCstr = false; + //This way if key is pressed again it goes back to FIRST + availableConstraint = AvailableConstraint::RESET; + } + + if ((firstCstr && dimensioningRadius && !dimensioningDiameter) || + (!firstCstr && !dimensioningRadius && dimensioningDiameter) || + (firstCstr && dimensioningRadius && dimensioningDiameter && !isCircle) || + (!firstCstr && dimensioningRadius && dimensioningDiameter && isCircle) ) { + Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Radius',%d,%f)) ", + GeoId, radius); + } + else { + Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Diameter',%d,%f)) ", + GeoId, radius * 2); + } + } + + const std::vector& ConStr = Obj->Constraints.getValues(); + bool fixed = isPointOrSegmentFixed(Obj, GeoId); + if (fixed || constraintCreationMode == Reference || GeoId <= Sketcher::GeoEnum::RefExt) { + Gui::cmdAppObjectArgs(Obj, "setDriving(%i,%s)", ConStr.size() - 1, "False"); + } + + moveConstraint(ConStr.size() - 1, onSketchPos); + + numberOfConstraintsCreated ++; + } + + bool createCoincidenceConstrain(int GeoId1, Sketcher::PointPos PosId1, int GeoId2, Sketcher::PointPos PosId2) { + // check if the edge already has a Block constraint + if (areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2)) { + return false; + } + + // 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)); + + numberOfConstraintsCreated++; + return true; + } + return false; + } + + void createEqualityConstrain(int GeoId1, int GeoId2) { + // check if the edge already has a Block constraint + if (areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2)) { + return; + } + + const Part::Geometry* geo1 = Obj->getGeometry(GeoId1); + const Part::Geometry* geo2 = Obj->getGeometry(GeoId2); + + if ((geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId() && geo2->getTypeId() != Part::GeomLineSegment::getClassTypeId()) || + (geo1->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() && geo2->getTypeId() != Part::GeomArcOfHyperbola::getClassTypeId()) || + (geo1->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() && geo2->getTypeId() != Part::GeomArcOfParabola::getClassTypeId()) || + (isBsplinePole(geo1) && !isBsplinePole(geo2)) || + ((geo1->getTypeId() == Part::GeomCircle::getClassTypeId() || geo1->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) && + !(geo2->getTypeId() == Part::GeomCircle::getClassTypeId() || geo2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId())) || + ((geo1->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo1->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) && + !(geo2->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()))) { + + Gui::TranslatedUserWarning(Obj, + QObject::tr("Wrong selection"), + QObject::tr("Select two or more edges of similar type.")); + return; + } + + Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Equal',%d,%d)) ", + GeoId1, GeoId2); + numberOfConstraintsCreated++; + } + + void createAngleConstrain(int GeoId1, int GeoId2, Base::Vector2d onSketchPos) { + const Part::Geometry* geom1 = Obj->getGeometry(GeoId1); + const Part::Geometry* geom2 = Obj->getGeometry(GeoId2); + if (geom1->getTypeId() == Part::GeomLineSegment::getClassTypeId() && + geom2->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { + const Part::GeomLineSegment* lineSeg1 = static_cast(geom1); + const Part::GeomLineSegment* lineSeg2 = static_cast(geom2); + + // find the two closest line ends + Sketcher::PointPos PosId1 = Sketcher::PointPos::none; + Sketcher::PointPos PosId2 = Sketcher::PointPos::none; + Base::Vector3d p1[2], p2[2]; + p1[0] = lineSeg1->getStartPoint(); + p1[1] = lineSeg1->getEndPoint(); + p2[0] = lineSeg2->getStartPoint(); + p2[1] = lineSeg2->getEndPoint(); + + // Get the intersection point in 2d of the two lines if possible + Base::Line2d line1(Base::Vector2d(p1[0].x, p1[0].y), Base::Vector2d(p1[1].x, p1[1].y)); + Base::Line2d line2(Base::Vector2d(p2[0].x, p2[0].y), Base::Vector2d(p2[1].x, p2[1].y)); + Base::Vector2d s; + if (line1.Intersect(line2, s)) { + // get the end points of the line segments that are closest to the intersection point + Base::Vector3d s3d(s.x, s.y, p1[0].z); + if (Base::DistanceP2(s3d, p1[0]) < Base::DistanceP2(s3d, p1[1])) + PosId1 = Sketcher::PointPos::start; + else + PosId1 = Sketcher::PointPos::end; + if (Base::DistanceP2(s3d, p2[0]) < Base::DistanceP2(s3d, p2[1])) + PosId2 = Sketcher::PointPos::start; + else + PosId2 = Sketcher::PointPos::end; + } + else { + // if all points are collinear + double length = DBL_MAX; + for (int i = 0; i <= 1; i++) { + for (int j = 0; j <= 1; j++) { + double tmp = Base::DistanceP2(p2[j], p1[i]); + if (tmp < length) { + length = tmp; + PosId1 = i ? Sketcher::PointPos::end : Sketcher::PointPos::start; + PosId2 = j ? Sketcher::PointPos::end : Sketcher::PointPos::start; + } + } + } + } + + Base::Vector3d dir1 = ((PosId1 == Sketcher::PointPos::start) ? 1. : -1.) * + (lineSeg1->getEndPoint() - lineSeg1->getStartPoint()); + Base::Vector3d dir2 = ((PosId2 == Sketcher::PointPos::start) ? 1. : -1.) * + (lineSeg2->getEndPoint() - lineSeg2->getStartPoint()); + + // check if the two lines are parallel, in this case an angle is not possible + Base::Vector3d dir3 = dir1 % dir2; + if (dir3.Length() < Precision::Intersection()) { + Base::Vector3d dist = (p1[0] - p2[0]) % dir1; + if (dist.Sqr() > Precision::Intersection()) { + //distance between 2 points + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance constraint")); + if ((selLine[0].GeoId == Sketcher::GeoEnum::VAxis || selLine[0].GeoId == Sketcher::GeoEnum::HAxis)) { + createDistanceConstrain(selLine[1].GeoId, Sketcher::PointPos::start, selLine[0].GeoId, selLine[0].PosId, onSketchPos); + } + else { + createDistanceConstrain(selLine[0].GeoId, Sketcher::PointPos::start, selLine[1].GeoId, selLine[1].PosId, onSketchPos); + } + return; + } + } + + double ActAngle = atan2(dir1.x * dir2.y - dir1.y * dir2.x, + dir1.y * dir2.y + dir1.x * dir2.x); + if (ActAngle < 0) { + ActAngle *= -1; + std::swap(GeoId1, GeoId2); + std::swap(PosId1, PosId2); + } + + Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Angle',%d,%d,%d,%d,%f)) ", + GeoId1, static_cast(PosId1), GeoId2, static_cast(PosId2), ActAngle); + + const std::vector& ConStr = Obj->Constraints.getValues(); + if (areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2) || constraintCreationMode == Reference) { + // it is a constraint on a external line, make it non-driving + + Gui::cmdAppObjectArgs(Obj, "setDriving(%i,%s)", ConStr.size() - 1, "False"); + } + numberOfConstraintsCreated++; + moveConstraint(ConStr.size() - 1, onSketchPos); + } + } + + void createVerticalConstrain(int GeoId1, Sketcher::PointPos PosId1, int GeoId2, Sketcher::PointPos PosId2) { + if (selLine.size() == 1) { + Gui::cmdAppObjectArgs(sketchgui->getObject(), "addConstraint(Sketcher.Constraint('Vertical',%d)) ", GeoId1); + + } + else { //2points + if (areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2)) { + return; + } + Gui::cmdAppObjectArgs(sketchgui->getObject(), "addConstraint(Sketcher.Constraint('Vertical',%d,%d,%d,%d)) " + , GeoId1, static_cast(PosId1), GeoId2, static_cast(PosId2)); + } + numberOfConstraintsCreated++; + tryAutoRecompute(Obj); + } + void createHorizontalConstrain(int GeoId1, Sketcher::PointPos PosId1, int GeoId2, Sketcher::PointPos PosId2) { + if (selLine.size() == 1) { + Gui::cmdAppObjectArgs(sketchgui->getObject(), "addConstraint(Sketcher.Constraint('Horizontal',%d)) ", GeoId1); + } + else { //2points + if (areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2)) { + return; + } + Gui::cmdAppObjectArgs(sketchgui->getObject(), "addConstraint(Sketcher.Constraint('Horizontal',%d,%d,%d,%d)) " + , GeoId1, static_cast(PosId1), GeoId2, static_cast(PosId2)); + } + numberOfConstraintsCreated++; + tryAutoRecompute(Obj); + } + void createBlockConstrain(int GeoId) { + Gui::cmdAppObjectArgs(sketchgui->getObject(), "addConstraint(Sketcher.Constraint('Block',%d)) ", GeoId); + + numberOfConstraintsCreated++; + tryAutoRecompute(Obj); + } + bool isHorizontalVerticalBlock(int GeoId) { + const std::vector< Sketcher::Constraint* >& vals = Obj->Constraints.getValues(); + + // check if the edge already has a Horizontal/Vertical/Block constraint + for (const auto& constraint : vals) { + if ((constraint->Type == Sketcher::Horizontal || constraint->Type == Sketcher::Vertical || constraint->Type == Sketcher::Block) + && constraint->First == GeoId) { + return true; + } + } + return false; + } + + void createSymmetryConstrain(int GeoId1, Sketcher::PointPos PosId1, int GeoId2, Sketcher::PointPos PosId2, int GeoId3, Sketcher::PointPos PosId3) { + if (selPoints.size() == 2 && selLine.size() == 1) { + if (isEdge(GeoId1, PosId1) && isVertex(GeoId3, PosId3)) { + std::swap(GeoId1, GeoId3); + std::swap(PosId1, PosId3); + } + else if (isEdge(GeoId2, PosId2) && isVertex(GeoId3, PosId3)) { + std::swap(GeoId2, GeoId3); + std::swap(PosId2, PosId3); + } + + if (areAllPointsOrSegmentsFixed(Obj, GeoId1, GeoId2, GeoId3)) { + return; + } + + const Part::Geometry* geom = Obj->getGeometry(GeoId3); + if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { + if (GeoId1 == GeoId2 && GeoId2 == GeoId3) { + Gui::TranslatedUserWarning(Obj, + QObject::tr("Wrong selection"), + QObject::tr("Cannot add a symmetry constraint between a line and its end points!")); + return; + } + + Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Symmetric',%d,%d,%d,%d,%d)) ", + GeoId1, static_cast(PosId1), GeoId2, static_cast(PosId2), GeoId3); + + numberOfConstraintsCreated++; + tryAutoRecompute(Obj); + } + } + else { + if (selPoints.size() == 1 && selLine.size() == 1) { //1line 1 point + if (GeoId1 == GeoId3) { + Gui::TranslatedUserWarning(Obj, + QObject::tr("Wrong selection"), + QObject::tr("Cannot add a symmetry constraint between a line and its end points!")); + return; + } + if (areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2)) { + return; + } + } + else { + if (areAllPointsOrSegmentsFixed(Obj, GeoId1, GeoId2, GeoId3)) { + return; + } + } + Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Symmetric',%d,%d,%d,%d,%d,%d)) ", + GeoId1, static_cast(PosId1), GeoId2, static_cast(PosId2), GeoId3, static_cast(PosId3)); + + numberOfConstraintsCreated++; + tryAutoRecompute(Obj); + } + } + + void updateDistanceType(Base::Vector2d onSketchPos) + { + const std::vector< Sketcher::Constraint* >& vals = Obj->Constraints.getValues(); + Sketcher::ConstraintType type = vals[vals.size() - 1]->Type; + + Base::Vector3d pnt1, pnt2; + bool addedOrigin = false; + if (selPoints.size() == 1) { + //Case of single point selected, for distance constraint. We add temporarily the origin in the vector. + addedOrigin = true; + SelIdPair selIdPair; + selIdPair.GeoId = Sketcher::GeoEnum::RtPnt; + selIdPair.PosId = Sketcher::PointPos::start; + selPoints.push_back(selIdPair); + } + + if (selLine.size() == 1) { + pnt1 = Obj->getPoint(selLine[0].GeoId, Sketcher::PointPos::start); + pnt2 = Obj->getPoint(selLine[0].GeoId, Sketcher::PointPos::end); + } + else { + pnt1 = Obj->getPoint(selPoints[0].GeoId, selPoints[0].PosId); + pnt2 = Obj->getPoint(selPoints[1].GeoId, selPoints[1].PosId); + } + + double minX, minY, maxX, maxY; + minX = min(pnt1.x, pnt2.x); + maxX = max(pnt1.x, pnt2.x); + minY = min(pnt1.y, pnt2.y); + maxY = max(pnt1.y, pnt2.y); + if (onSketchPos.x > minX && onSketchPos.x < maxX + && (onSketchPos.y < minY || onSketchPos.y > maxY) && type != Sketcher::DistanceX) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add DistanceX constraint")); + specialConstraint = SpecialConstraint::LineOr2PointsDistance; + if (selLine.size() == 1) { + createDistanceXYConstrain(Sketcher::DistanceX, selLine[0].GeoId, Sketcher::PointPos::start, selLine[0].GeoId, Sketcher::PointPos::end, onSketchPos); + } + else { + createDistanceXYConstrain(Sketcher::DistanceX, selPoints[0].GeoId, selPoints[0].PosId, selPoints[1].GeoId, selPoints[1].PosId, onSketchPos); + } + } + else if (onSketchPos.y > minY && onSketchPos.y < maxY + && (onSketchPos.x < minX || onSketchPos.x > maxX) && type != Sketcher::DistanceY) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add DistanceY constraint")); + specialConstraint = SpecialConstraint::LineOr2PointsDistance; + if (selLine.size() == 1) { + createDistanceXYConstrain(Sketcher::DistanceY, selLine[0].GeoId, Sketcher::PointPos::start, selLine[0].GeoId, Sketcher::PointPos::end, onSketchPos); + } + else { + createDistanceXYConstrain(Sketcher::DistanceY, selPoints[0].GeoId, selPoints[0].PosId, selPoints[1].GeoId, selPoints[1].PosId, onSketchPos); + } + } + else if ((((onSketchPos.y < minY || onSketchPos.y > maxY) && (onSketchPos.x < minX || onSketchPos.x > maxX)) + || (onSketchPos.y > minY && onSketchPos.y < maxY && onSketchPos.x > minX && onSketchPos.x < maxX)) && type != Sketcher::Distance) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance constraint")); + if (selLine.size() == 1) { + createDistanceConstrain(selLine[0].GeoId, Sketcher::PointPos::start, selLine[0].GeoId, Sketcher::PointPos::end, onSketchPos); + } + else { + createDistanceConstrain(selPoints[0].GeoId, selPoints[0].PosId, selPoints[1].GeoId, selPoints[1].PosId, onSketchPos); + } + + } + + if (addedOrigin) { + //remove origin + selPoints.pop_back(); + } + } + + void restartCommand(const char* cstrName) { + specialConstraint = SpecialConstraint::None; + Gui::Command::abortCommand(); + Obj->solve(); + sketchgui->draw(false, false); // Redraw + Gui::Command::openCommand(cstrName); + + numberOfConstraintsCreated = 0; + } +}; + +DEF_STD_CMD_AU(CmdSketcherConstrainContextual) + +CmdSketcherConstrainContextual::CmdSketcherConstrainContextual() + : Command("Sketcher_ConstrainContextual") +{ + sAppModule = "Sketcher"; + sGroup = "Sketcher"; + sMenuText = QT_TR_NOOP("Contextual constrain"); + sToolTipText = QT_TR_NOOP("Constrain contextually based on your selection.\nDepending on your selection you might have several constraints available. You can cycle through them using SHIFT key.\nLeft clicking on empty space will validate the current constraint. Right clicking or pressing Esc will cancel."); + sWhatsThis = "Sketcher_ConstrainContextual"; + sStatusTip = sToolTipText; + sPixmap = "Constraint_Contextual"; + sAccel = "A"; + eType = ForEdit; +} + +void CmdSketcherConstrainContextual::activated(int iMsg) +{ + Q_UNUSED(iMsg); + ActivateHandler(getActiveGuiDocument(), new DrawSketchHandlerConstrainContextual()); + getSelection().clearSelection(); +} + +void CmdSketcherConstrainContextual::updateAction(int mode) +{ + switch (mode) { + case Reference: + if (getAction()) + getAction()->setIcon(Gui::BitmapFactory().iconFromTheme("Constraint_Contextual_Driven")); + break; + case Driving: + if (getAction()) + getAction()->setIcon(Gui::BitmapFactory().iconFromTheme("Constraint_Contextual")); + break; + } +} + +bool CmdSketcherConstrainContextual::isActive(void) +{ + return isCommandActive(getActiveGuiDocument()); +} + + // ============================================================================ class CmdSketcherConstrainHorizontal: public CmdSketcherConstraint @@ -8371,6 +9528,7 @@ CmdSketcherToggleDrivingConstraint::CmdSketcherToggleDrivingConstraint() rcCmdMgr.addCommandMode("ToggleDrivingConstraint", "Sketcher_ConstrainRadiam"); rcCmdMgr.addCommandMode("ToggleDrivingConstraint", "Sketcher_ConstrainAngle"); rcCmdMgr.addCommandMode("ToggleDrivingConstraint", "Sketcher_CompConstrainRadDia"); + rcCmdMgr.addCommandMode("ToggleDrivingConstraint", "Sketcher_ConstrainContextual"); // rcCmdMgr.addCommandMode("ToggleDrivingConstraint", "Sketcher_ConstrainSnellsLaw"); } @@ -8581,6 +9739,7 @@ void CreateSketcherCommandsConstraints() rcCmdMgr.addCommand(new CmdSketcherConstrainLock()); rcCmdMgr.addCommand(new CmdSketcherConstrainBlock()); rcCmdMgr.addCommand(new CmdSketcherConstrainCoincident()); + rcCmdMgr.addCommand(new CmdSketcherConstrainContextual()); rcCmdMgr.addCommand(new CmdSketcherConstrainParallel()); rcCmdMgr.addCommand(new CmdSketcherConstrainPerpendicular()); rcCmdMgr.addCommand(new CmdSketcherConstrainTangent()); diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp b/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp index bcd2fd8c62..f3eccc92fc 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp +++ b/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp @@ -138,6 +138,13 @@ ViewProviderSketchDrawSketchHandlerAttorney::setAngleSnapping(ViewProviderSketch vp.setAngleSnapping(enable, referencePoint); } +inline void +ViewProviderSketchDrawSketchHandlerAttorney::moveConstraint(ViewProviderSketch& vp, int constNum, + const Base::Vector2d& toPos) +{ + vp.moveConstraint(constNum, toPos); +} + /**************************** CurveConverter **********************************************/ @@ -1086,3 +1093,9 @@ void DrawSketchHandler::setAngleSnapping(bool enable, Base::Vector2d referencePo ViewProviderSketchDrawSketchHandlerAttorney::setAngleSnapping( *sketchgui, enable, referencePoint); } + +void DrawSketchHandler::moveConstraint(int constNum, const Base::Vector2d& toPos) +{ + ViewProviderSketchDrawSketchHandlerAttorney::moveConstraint( + *sketchgui, constNum, toPos); +} \ No newline at end of file diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandler.h b/src/Mod/Sketcher/Gui/DrawSketchHandler.h index d5350ebcfb..a5679b5e46 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandler.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandler.h @@ -104,6 +104,7 @@ private: static inline int getPreselectCurve(const ViewProviderSketch& vp); static inline int getPreselectCross(const ViewProviderSketch& vp); + static inline void moveConstraint(ViewProviderSketch& vp, int constNum, const Base::Vector2d& toPos); friend class DrawSketchHandler; }; @@ -230,6 +231,8 @@ protected: void setAngleSnapping(bool enable, Base::Vector2d referencePoint = Base::Vector2d(0., 0.)); + void moveConstraint(int constNum, const Base::Vector2d& toPos); + private: void setSvgCursor(const QString& svgName, int x, int y, const std::map& colorMapping = diff --git a/src/Mod/Sketcher/Gui/EditDatumDialog.cpp b/src/Mod/Sketcher/Gui/EditDatumDialog.cpp index dbfd423b99..2bced92a6d 100644 --- a/src/Mod/Sketcher/Gui/EditDatumDialog.cpp +++ b/src/Mod/Sketcher/Gui/EditDatumDialog.cpp @@ -53,6 +53,7 @@ using namespace SketcherGui; EditDatumDialog::EditDatumDialog(ViewProviderSketch* vp, int ConstrNbr) : ConstrNbr(ConstrNbr) + , success(false) { sketch = vp->getSketchObject(); const std::vector& Constraints = sketch->Constraints.getValues(); @@ -70,7 +71,7 @@ EditDatumDialog::EditDatumDialog(Sketcher::SketchObject* pcSketch, int ConstrNbr EditDatumDialog::~EditDatumDialog() {} -void EditDatumDialog::exec(bool atCursor) +int EditDatumDialog::exec(bool atCursor) { // Return if constraint doesn't have editable value if (Constr->isDimensional()) { @@ -80,7 +81,7 @@ void EditDatumDialog::exec(bool atCursor) QObject::tr("Dimensional constraint"), QObject::tr("Not allowed to edit the datum because the " "sketch contains conflicting constraints")); - return; + return QDialog::Rejected; } Base::Quantity init_val; @@ -173,8 +174,10 @@ void EditDatumDialog::exec(bool atCursor) dlg.setGeometry(x, y, dlg.geometry().width(), dlg.geometry().height()); } - dlg.exec(); + return dlg.exec(); } + + return QDialog::Rejected; } void EditDatumDialog::accepted() @@ -233,6 +236,7 @@ void EditDatumDialog::accepted() //} tryAutoRecompute(sketch); + success = true; } catch (const Base::Exception& e) { Gui::NotifyUserError( @@ -253,6 +257,11 @@ void EditDatumDialog::rejected() sketch->recomputeFeature(); } +bool EditDatumDialog::isSuccess() +{ + return success; +} + void EditDatumDialog::drivingToggled(bool state) { if (state) { diff --git a/src/Mod/Sketcher/Gui/EditDatumDialog.h b/src/Mod/Sketcher/Gui/EditDatumDialog.h index 85d4695f60..2252a28472 100644 --- a/src/Mod/Sketcher/Gui/EditDatumDialog.h +++ b/src/Mod/Sketcher/Gui/EditDatumDialog.h @@ -47,12 +47,14 @@ public: EditDatumDialog(Sketcher::SketchObject* pcSketch, int ConstrNbr); ~EditDatumDialog() override; - void exec(bool atCursor = true); + int exec(bool atCursor = true); + bool isSuccess(); private: Sketcher::SketchObject* sketch; Sketcher::Constraint* Constr; int ConstrNbr; + bool success; std::unique_ptr ui_ins_datum; private Q_SLOTS: diff --git a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc index 52f4638e45..d1f77b2750 100644 --- a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc +++ b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc @@ -7,6 +7,8 @@ icons/constraints/Constraint_Block.svg icons/constraints/Constraint_Concentric.svg + icons/constraints/Constraint_Contextual.svg + icons/constraints/Constraint_Contextual_Driven.svg icons/constraints/Constraint_Diameter.svg icons/constraints/Constraint_Diameter_Driven.svg icons/constraints/Constraint_Ellipse_Axis_Angle.svg diff --git a/src/Mod/Sketcher/Gui/Resources/icons/constraints/Constraint_Contextual.svg b/src/Mod/Sketcher/Gui/Resources/icons/constraints/Constraint_Contextual.svg new file mode 100644 index 0000000000..a469fb0200 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/constraints/Constraint_Contextual.svg @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + [wmayer] + + + 2011-10-10 + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + FreeCAD + + + FreeCAD/src/Mod/Sketcher/Gui/Resources/icons/Constraint_Radius.svg + + + FreeCAD LGPL2+ + + + https://www.gnu.org/copyleft/lesser.html + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/constraints/Constraint_Contextual_Driven.svg b/src/Mod/Sketcher/Gui/Resources/icons/constraints/Constraint_Contextual_Driven.svg new file mode 100644 index 0000000000..64fb54dbec --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/constraints/Constraint_Contextual_Driven.svg @@ -0,0 +1,276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + [wmayer] + + + 2011-10-10 + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + FreeCAD + + + FreeCAD/src/Mod/Sketcher/Gui/Resources/icons/Constraint_Radius.svg + + + FreeCAD LGPL2+ + + + https://www.gnu.org/copyleft/lesser.html + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/SketcherSettings.cpp b/src/Mod/Sketcher/Gui/SketcherSettings.cpp index 0381280338..37678cac96 100644 --- a/src/Mod/Sketcher/Gui/SketcherSettings.cpp +++ b/src/Mod/Sketcher/Gui/SketcherSettings.cpp @@ -66,6 +66,42 @@ void SketcherSettings::saveSettings() ui->checkBoxEnableEscape->onSave(); ui->checkBoxNotifyConstraintSubstitutions->onSave(); ui->checkBoxAutoRemoveRedundants->onSave(); + + // Dimensioning constraints mode + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/dimensioning"); + bool singleTool = true; + bool SeparatedTools = false; + int index = ui->dimensioningMode->currentIndex(); + switch (index) { + case 1: + singleTool = false; + SeparatedTools = true; + break; + case 2: + singleTool = true; + SeparatedTools = true; + break; + } + hGrp->SetBool("SingleDimensioningTool", singleTool); + hGrp->SetBool("SeparatedDimensioningTools", SeparatedTools); + + ui->radiusDiameterMode->setEnabled(index != 1); + + bool Diameter = true; + bool Radius = true; + index = ui->radiusDiameterMode->currentIndex(); + switch (index) { + case 1: + Diameter = true; + Radius = false; + break; + case 2: + Diameter = false; + Radius = true; + break; + } + hGrp->SetBool("DimensioningDiameter", Diameter); + hGrp->SetBool("DimensioningRadius", Radius); } void SketcherSettings::loadSettings() @@ -76,6 +112,38 @@ void SketcherSettings::loadSettings() ui->checkBoxEnableEscape->onRestore(); ui->checkBoxNotifyConstraintSubstitutions->onRestore(); ui->checkBoxAutoRemoveRedundants->onRestore(); + + // Dimensioning constraints mode + ui->dimensioningMode->clear(); + ui->dimensioningMode->addItem(tr("Single tool")); + ui->dimensioningMode->addItem(tr("Separated tools")); + ui->dimensioningMode->addItem(tr("Both")); + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/dimensioning"); + bool singleTool = hGrp->GetBool("SingleDimensioningTool", true); + bool SeparatedTools = hGrp->GetBool("SeparatedDimensioningTools", false); + int index = SeparatedTools ? (singleTool ? 2 : 1) : 0; + ui->dimensioningMode->setCurrentIndex(index); + connect(ui->dimensioningMode, QOverload::of(&QComboBox::currentIndexChanged), this, &SketcherSettings::dimensioningModeChanged); + + ui->radiusDiameterMode->setEnabled(index != 1); + + // Dimensioning constraints mode + ui->radiusDiameterMode->clear(); + ui->radiusDiameterMode->addItem(tr("Auto")); + ui->radiusDiameterMode->addItem(tr("Diameter")); + ui->radiusDiameterMode->addItem(tr("Radius")); + + bool Diameter = hGrp->GetBool("DimensioningDiameter", true); + bool Radius = hGrp->GetBool("DimensioningRadius", true); + index = Diameter ? (Radius ? 0 : 1) : 2; + ui->radiusDiameterMode->setCurrentIndex(index); +} + +void SketcherSettings::dimensioningModeChanged(int index) +{ + ui->radiusDiameterMode->setEnabled(index != 1); + SketcherSettings::requireRestart(); } /** diff --git a/src/Mod/Sketcher/Gui/SketcherSettings.h b/src/Mod/Sketcher/Gui/SketcherSettings.h index 3a65ca1243..01a6018f10 100644 --- a/src/Mod/Sketcher/Gui/SketcherSettings.h +++ b/src/Mod/Sketcher/Gui/SketcherSettings.h @@ -51,6 +51,7 @@ public: protected: void changeEvent(QEvent* e) override; + void dimensioningModeChanged(int index); private: std::unique_ptr ui; diff --git a/src/Mod/Sketcher/Gui/SketcherSettings.ui b/src/Mod/Sketcher/Gui/SketcherSettings.ui index 47a71f3c80..cd187c5813 100644 --- a/src/Mod/Sketcher/Gui/SketcherSettings.ui +++ b/src/Mod/Sketcher/Gui/SketcherSettings.ui @@ -163,6 +163,56 @@ Requires to re-enter edit mode to take effect. + + + + 0 + 0 + + + + Contextual Constrain + + + + + + Dimensioning constraints: + + + + + + + Selection the type of dimensioning constraints for your toolbar: +'Single tool': You will have a single tool for all dimensioning constraints : Distance, Distance X / Y, Angle, Radius. +'Separated tools': You will have separated tools for each dimensioning constraint. +'Both': You will have both the 'Constrain Contextual' tool and the individual tool. +This setting is only for the toolbar. Whichever you chose, all tools are always available in the menu and through shortcuts. + + + + + + + Dimensioning diameter/radius mode: + + + + + + + While using Constraint Contextually you may chose how to handle circles and arcs: +'Auto': The tool will apply radius to arcs and diameter to circles. +'Diameter': The tool will apply diameter to both arcs and circles. +'Radius': The tool will apply radius to both arcs and circles. + + + + + + + Qt::Vertical diff --git a/src/Mod/Sketcher/Gui/Workbench.cpp b/src/Mod/Sketcher/Gui/Workbench.cpp index 3055e7236e..5967c7c9c7 100644 --- a/src/Mod/Sketcher/Gui/Workbench.cpp +++ b/src/Mod/Sketcher/Gui/Workbench.cpp @@ -408,6 +408,7 @@ inline void SketcherAddWorkbenchConstraints(Gui::MenuItem& cons) << "Sketcher_ConstrainSymmetric" << "Sketcher_ConstrainBlock" << "Separator" + << "Sketcher_ConstrainContextual" << "Sketcher_ConstrainLock" << "Sketcher_ConstrainDistanceX" << "Sketcher_ConstrainDistanceY" @@ -425,6 +426,9 @@ inline void SketcherAddWorkbenchConstraints(Gui::MenuItem& cons) template<> inline void SketcherAddWorkbenchConstraints(Gui::ToolBarItem& cons) { + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Sketcher/dimensioning"); + cons << "Sketcher_ConstrainCoincident" << "Sketcher_ConstrainPointOnObject" << "Sketcher_ConstrainVertical" @@ -435,15 +439,20 @@ inline void SketcherAddWorkbenchConstraints(Gui::ToolBarItem& << "Sketcher_ConstrainEqual" << "Sketcher_ConstrainSymmetric" << "Sketcher_ConstrainBlock" - << "Separator" - << "Sketcher_ConstrainLock" - << "Sketcher_ConstrainDistanceX" - << "Sketcher_ConstrainDistanceY" - << "Sketcher_ConstrainDistance" - << "Sketcher_CompConstrainRadDia" - << "Sketcher_ConstrainAngle" - // << "Sketcher_ConstrainSnellsLaw" // Rarely used, show only in menu - << "Separator" + << "Separator"; + if (hGrp->GetBool("SingleDimensioningTool", true)) { + cons << "Sketcher_ConstrainContextual"; + } + if (hGrp->GetBool("SeparatedDimensioningTools", false)) { + cons << "Sketcher_ConstrainLock" + << "Sketcher_ConstrainDistanceX" + << "Sketcher_ConstrainDistanceY" + << "Sketcher_ConstrainDistance" + << "Sketcher_CompConstrainRadDia" + << "Sketcher_ConstrainAngle"; + // << "Sketcher_ConstrainSnellsLaw" // Rarely used, show only in menu + } + cons << "Separator" << "Sketcher_ToggleDrivingConstraint" << "Sketcher_ToggleActiveConstraint"; } From fe594941a52bb93224d7725ae4849c5ba509ebd6 Mon Sep 17 00:00:00 2001 From: Paddle Date: Mon, 26 Jun 2023 09:08:56 +0200 Subject: [PATCH 02/12] Fix texts in the new settings. --- src/Mod/Sketcher/Gui/SketcherSettings.ui | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Mod/Sketcher/Gui/SketcherSettings.ui b/src/Mod/Sketcher/Gui/SketcherSettings.ui index cd187c5813..e144141587 100644 --- a/src/Mod/Sketcher/Gui/SketcherSettings.ui +++ b/src/Mod/Sketcher/Gui/SketcherSettings.ui @@ -184,10 +184,10 @@ Requires to re-enter edit mode to take effect. - Selection the type of dimensioning constraints for your toolbar: -'Single tool': You will have a single tool for all dimensioning constraints : Distance, Distance X / Y, Angle, Radius. -'Separated tools': You will have separated tools for each dimensioning constraint. -'Both': You will have both the 'Constrain Contextual' tool and the individual tool. + Select the type of dimensioning constraints for your toolbar: +'Single tool': 'Constrain Contextual': A single tool for all dimensioning constraints : Distance, Distance X / Y, Angle, Radius. +'Separated tools': Separated tools for each dimensioning constraint. +'Both': You will have both the 'Constrain Contextual' tool and the separated tools. This setting is only for the toolbar. Whichever you chose, all tools are always available in the menu and through shortcuts. From eee2f141285379a6b41dc28d58ca3fe753893799 Mon Sep 17 00:00:00 2001 From: Paddle Date: Sat, 26 Aug 2023 08:35:27 +0200 Subject: [PATCH 03/12] Change the name to 'Dimension' instead of 'Constrain Contextual' --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 48 ++++++++++--------- src/Mod/Sketcher/Gui/Resources/Sketcher.qrc | 4 +- ...ontextual.svg => Constraint_Dimension.svg} | 0 ...en.svg => Constraint_Dimension_Driven.svg} | 0 src/Mod/Sketcher/Gui/SketcherSettings.ui | 10 ++-- src/Mod/Sketcher/Gui/Workbench.cpp | 4 +- 6 files changed, 34 insertions(+), 32 deletions(-) rename src/Mod/Sketcher/Gui/Resources/icons/constraints/{Constraint_Contextual.svg => Constraint_Dimension.svg} (100%) rename src/Mod/Sketcher/Gui/Resources/icons/constraints/{Constraint_Contextual_Driven.svg => Constraint_Dimension_Driven.svg} (100%) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 8e5ca0f432..cc675131d1 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -991,12 +991,12 @@ void CmdSketcherConstraint::activated(int /*iMsg*/) } -// Contextual Constraint tool ======================================================= +// Dimension tool ======================================================= -class DrawSketchHandlerConstrainContextual : public DrawSketchHandler +class DrawSketchHandlerDimension : public DrawSketchHandler { public: - DrawSketchHandlerConstrainContextual() + DrawSketchHandlerDimension() : specialConstraint(SpecialConstraint::None) , availableConstraint(AvailableConstraint::FIRST) , previousOnSketchPos(Base::Vector2d(0.f, 0.f)) @@ -1007,7 +1007,7 @@ public: , numberOfConstraintsCreated(0) { } - virtual ~DrawSketchHandlerConstrainContextual() + virtual ~DrawSketchHandlerDimension() { } @@ -1028,7 +1028,7 @@ public: void activated() override { - Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Contextual Constrain")); + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Dimension")); Obj = sketchgui->getSketchObject(); @@ -1042,7 +1042,7 @@ public: qreal fullIconWidth = 32 * pixelRatio; qreal iconWidth = 16 * pixelRatio; QPixmap cursorPixmap = Gui::BitmapFactory().pixmapFromSvg("Sketcher_Crosshair", QSizeF(fullIconWidth, fullIconWidth), colorMapping), - icon = Gui::BitmapFactory().pixmapFromSvg("Constraint_Contextual", QSizeF(iconWidth, iconWidth)); + icon = Gui::BitmapFactory().pixmapFromSvg("Constraint_Dimension", QSizeF(iconWidth, iconWidth)); QPainter cursorPainter; cursorPainter.begin(&cursorPixmap); cursorPainter.drawPixmap(16 * pixelRatio, 16 * pixelRatio, icon); @@ -1202,7 +1202,7 @@ public: bool continuousMode = hGrp->GetBool("ContinuousCreationMode", true); if (continuousMode) { Gui::Selection().clearSelection(); - Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Constrain contextually")); + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Dimension")); numberOfConstraintsCreated = 0; specialConstraint = SpecialConstraint::None; previousOnSketchPos = Base::Vector2d(0.f, 0.f); @@ -2104,44 +2104,46 @@ protected: } }; -DEF_STD_CMD_AU(CmdSketcherConstrainContextual) +DEF_STD_CMD_AU(CmdSketcherDimension) -CmdSketcherConstrainContextual::CmdSketcherConstrainContextual() - : Command("Sketcher_ConstrainContextual") +CmdSketcherDimension::CmdSketcherDimension() + : Command("Sketcher_Dimension") { sAppModule = "Sketcher"; sGroup = "Sketcher"; - sMenuText = QT_TR_NOOP("Contextual constrain"); - sToolTipText = QT_TR_NOOP("Constrain contextually based on your selection.\nDepending on your selection you might have several constraints available. You can cycle through them using SHIFT key.\nLeft clicking on empty space will validate the current constraint. Right clicking or pressing Esc will cancel."); - sWhatsThis = "Sketcher_ConstrainContextual"; + sMenuText = QT_TR_NOOP("Dimension"); + sToolTipText = QT_TR_NOOP("Constrain contextually based on your selection.\n" + "Depending on your selection you might have several constraints available. You can cycle through them using SHIFT key.\n" + "Left clicking on empty space will validate the current constraint. Right clicking or pressing Esc will cancel."); + sWhatsThis = "Sketcher_Dimension"; sStatusTip = sToolTipText; - sPixmap = "Constraint_Contextual"; - sAccel = "A"; + sPixmap = "Constraint_Dimension"; + sAccel = "D"; eType = ForEdit; } -void CmdSketcherConstrainContextual::activated(int iMsg) +void CmdSketcherDimension::activated(int iMsg) { Q_UNUSED(iMsg); - ActivateHandler(getActiveGuiDocument(), new DrawSketchHandlerConstrainContextual()); + ActivateHandler(getActiveGuiDocument(), new DrawSketchHandlerDimension()); getSelection().clearSelection(); } -void CmdSketcherConstrainContextual::updateAction(int mode) +void CmdSketcherDimension::updateAction(int mode) { switch (mode) { case Reference: if (getAction()) - getAction()->setIcon(Gui::BitmapFactory().iconFromTheme("Constraint_Contextual_Driven")); + getAction()->setIcon(Gui::BitmapFactory().iconFromTheme("Constraint_Dimension_Driven")); break; case Driving: if (getAction()) - getAction()->setIcon(Gui::BitmapFactory().iconFromTheme("Constraint_Contextual")); + getAction()->setIcon(Gui::BitmapFactory().iconFromTheme("Constraint_Dimension")); break; } } -bool CmdSketcherConstrainContextual::isActive(void) +bool CmdSketcherDimension::isActive(void) { return isCommandActive(getActiveGuiDocument()); } @@ -9528,7 +9530,7 @@ CmdSketcherToggleDrivingConstraint::CmdSketcherToggleDrivingConstraint() rcCmdMgr.addCommandMode("ToggleDrivingConstraint", "Sketcher_ConstrainRadiam"); rcCmdMgr.addCommandMode("ToggleDrivingConstraint", "Sketcher_ConstrainAngle"); rcCmdMgr.addCommandMode("ToggleDrivingConstraint", "Sketcher_CompConstrainRadDia"); - rcCmdMgr.addCommandMode("ToggleDrivingConstraint", "Sketcher_ConstrainContextual"); + rcCmdMgr.addCommandMode("ToggleDrivingConstraint", "Sketcher_Dimension"); // rcCmdMgr.addCommandMode("ToggleDrivingConstraint", "Sketcher_ConstrainSnellsLaw"); } @@ -9739,7 +9741,7 @@ void CreateSketcherCommandsConstraints() rcCmdMgr.addCommand(new CmdSketcherConstrainLock()); rcCmdMgr.addCommand(new CmdSketcherConstrainBlock()); rcCmdMgr.addCommand(new CmdSketcherConstrainCoincident()); - rcCmdMgr.addCommand(new CmdSketcherConstrainContextual()); + rcCmdMgr.addCommand(new CmdSketcherDimension()); rcCmdMgr.addCommand(new CmdSketcherConstrainParallel()); rcCmdMgr.addCommand(new CmdSketcherConstrainPerpendicular()); rcCmdMgr.addCommand(new CmdSketcherConstrainTangent()); diff --git a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc index d1f77b2750..6ee58b00c1 100644 --- a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc +++ b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc @@ -7,8 +7,8 @@ icons/constraints/Constraint_Block.svg icons/constraints/Constraint_Concentric.svg - icons/constraints/Constraint_Contextual.svg - icons/constraints/Constraint_Contextual_Driven.svg + icons/constraints/Constraint_Dimension.svg + icons/constraints/Constraint_Dimension_Driven.svg icons/constraints/Constraint_Diameter.svg icons/constraints/Constraint_Diameter_Driven.svg icons/constraints/Constraint_Ellipse_Axis_Angle.svg diff --git a/src/Mod/Sketcher/Gui/Resources/icons/constraints/Constraint_Contextual.svg b/src/Mod/Sketcher/Gui/Resources/icons/constraints/Constraint_Dimension.svg similarity index 100% rename from src/Mod/Sketcher/Gui/Resources/icons/constraints/Constraint_Contextual.svg rename to src/Mod/Sketcher/Gui/Resources/icons/constraints/Constraint_Dimension.svg diff --git a/src/Mod/Sketcher/Gui/Resources/icons/constraints/Constraint_Contextual_Driven.svg b/src/Mod/Sketcher/Gui/Resources/icons/constraints/Constraint_Dimension_Driven.svg similarity index 100% rename from src/Mod/Sketcher/Gui/Resources/icons/constraints/Constraint_Contextual_Driven.svg rename to src/Mod/Sketcher/Gui/Resources/icons/constraints/Constraint_Dimension_Driven.svg diff --git a/src/Mod/Sketcher/Gui/SketcherSettings.ui b/src/Mod/Sketcher/Gui/SketcherSettings.ui index e144141587..a189572028 100644 --- a/src/Mod/Sketcher/Gui/SketcherSettings.ui +++ b/src/Mod/Sketcher/Gui/SketcherSettings.ui @@ -171,7 +171,7 @@ Requires to re-enter edit mode to take effect. - Contextual Constrain + Dimension Constraint @@ -185,9 +185,9 @@ Requires to re-enter edit mode to take effect. Select the type of dimensioning constraints for your toolbar: -'Single tool': 'Constrain Contextual': A single tool for all dimensioning constraints : Distance, Distance X / Y, Angle, Radius. +'Single tool': A single tool for all dimensioning constraints : Distance, Distance X / Y, Angle, Radius. 'Separated tools': Separated tools for each dimensioning constraint. -'Both': You will have both the 'Constrain Contextual' tool and the separated tools. +'Both': You will have both the 'Dimension' tool and the separated tools. This setting is only for the toolbar. Whichever you chose, all tools are always available in the menu and through shortcuts. @@ -195,14 +195,14 @@ This setting is only for the toolbar. Whichever you chose, all tools are always - Dimensioning diameter/radius mode: + Dimension tool diameter/radius mode: - While using Constraint Contextually you may chose how to handle circles and arcs: + While using the Dimension tool you may chose how to handle circles and arcs: 'Auto': The tool will apply radius to arcs and diameter to circles. 'Diameter': The tool will apply diameter to both arcs and circles. 'Radius': The tool will apply radius to both arcs and circles. diff --git a/src/Mod/Sketcher/Gui/Workbench.cpp b/src/Mod/Sketcher/Gui/Workbench.cpp index 5967c7c9c7..85656398e8 100644 --- a/src/Mod/Sketcher/Gui/Workbench.cpp +++ b/src/Mod/Sketcher/Gui/Workbench.cpp @@ -408,7 +408,7 @@ inline void SketcherAddWorkbenchConstraints(Gui::MenuItem& cons) << "Sketcher_ConstrainSymmetric" << "Sketcher_ConstrainBlock" << "Separator" - << "Sketcher_ConstrainContextual" + << "Sketcher_Dimension" << "Sketcher_ConstrainLock" << "Sketcher_ConstrainDistanceX" << "Sketcher_ConstrainDistanceY" @@ -441,7 +441,7 @@ inline void SketcherAddWorkbenchConstraints(Gui::ToolBarItem& << "Sketcher_ConstrainBlock" << "Separator"; if (hGrp->GetBool("SingleDimensioningTool", true)) { - cons << "Sketcher_ConstrainContextual"; + cons << "Sketcher_Dimension"; } if (hGrp->GetBool("SeparatedDimensioningTools", false)) { cons << "Sketcher_ConstrainLock" From bc3d06fafc7f31b58a84a17916504ab8ce024fe3 Mon Sep 17 00:00:00 2001 From: Paddle Date: Sat, 26 Aug 2023 19:13:52 +0200 Subject: [PATCH 04/12] Remove superfluous virtual add missing override. --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index cc675131d1..b804bc787d 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -1007,7 +1007,7 @@ public: , numberOfConstraintsCreated(0) { } - virtual ~DrawSketchHandlerDimension() + ~DrawSketchHandlerDimension() override { } @@ -1066,7 +1066,7 @@ public: sketchgui->draw(false, false); // Redraw } - virtual void registerPressedKey(bool pressed, int key) + void registerPressedKey(bool pressed, int key) override { if ((key == SoKeyboardEvent::RIGHT_SHIFT || key == SoKeyboardEvent::LEFT_SHIFT) && pressed) { if (availableConstraint == AvailableConstraint::FIRST) { @@ -1088,7 +1088,7 @@ public: } } - virtual void mouseMove(Base::Vector2d onSketchPos) + void mouseMove(Base::Vector2d onSketchPos) override { const std::vector& ConStr = Obj->Constraints.getValues(); previousOnSketchPos = onSketchPos; @@ -1119,12 +1119,12 @@ public: } } - virtual bool pressButton(Base::Vector2d onSketchPos) + bool pressButton(Base::Vector2d onSketchPos) override { return true; } - virtual bool releaseButton(Base::Vector2d onSketchPos) + bool releaseButton(Base::Vector2d onSketchPos) override { Q_UNUSED(onSketchPos); From b95713599a66ec18e55f2ef944cd3472336f1757 Mon Sep 17 00:00:00 2001 From: Paddle Date: Sat, 26 Aug 2023 19:47:23 +0200 Subject: [PATCH 05/12] refactor Sketcher Dimension releaseButton --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 135 ++++++++++---------- 1 file changed, 67 insertions(+), 68 deletions(-) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index b804bc787d..d2549a2ee9 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -1178,62 +1178,14 @@ public: if (selIdPair.GeoId == GeoEnum::GeoUndef) { // If mouse is released on "blank" space, finalize and start over - // Ask for the value of datum constraints - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); - bool show = hGrp->GetBool("ShowDialogOnDistanceConstraint", true); - const std::vector& ConStr = Obj->Constraints.getValues(); - - bool commandHandledInEditDatum = false; - for (int i = numberOfConstraintsCreated - 1; i >= 0; i--) { - if (show && ConStr[ConStr.size() - 1 - i]->isDimensional() && ConStr[ConStr.size() - 1 - i]->isDriving) { - commandHandledInEditDatum = true; - EditDatumDialog editDatumDialog(sketchgui, ConStr.size() - 1 - i); - editDatumDialog.exec(); - if (!editDatumDialog.isSuccess()) { - break; - } - } - } - - if (!commandHandledInEditDatum) - Gui::Command::commitCommand(); - - // This code enables the continuous creation mode. - bool continuousMode = hGrp->GetBool("ContinuousCreationMode", true); - if (continuousMode) { - Gui::Selection().clearSelection(); - Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Dimension")); - numberOfConstraintsCreated = 0; - specialConstraint = SpecialConstraint::None; - previousOnSketchPos = Base::Vector2d(0.f, 0.f); - selPoints.clear(); - selLine.clear(); - selCircleArc.clear(); - selEllipseAndCo.clear(); - } - else { - sketchgui->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider - } + finalizeCommand(); } else if (notSelectedYet(selIdPair)) { + std::vector& selVector = getSelectionVector(newselGeoType); + //add the geometry to its type vector. Temporarily if not selAllowed - if (newselGeoType == Part::GeomPoint::getClassTypeId()) { - selPoints.push_back(selIdPair); - } - else if (newselGeoType == Part::GeomLineSegment::getClassTypeId()) { - selLine.push_back(selIdPair); - } - else if (newselGeoType == Part::GeomArcOfCircle::getClassTypeId() - || newselGeoType == Part::GeomCircle::getClassTypeId()) { - selCircleArc.push_back(selIdPair); - } - else if (newselGeoType == Part::GeomEllipse::getClassTypeId() - || newselGeoType == Part::GeomArcOfEllipse::getClassTypeId() - || newselGeoType == Part::GeomArcOfHyperbola::getClassTypeId() - || newselGeoType == Part::GeomArcOfParabola::getClassTypeId()) { - selEllipseAndCo.push_back(selIdPair); - } + selVector.push_back(selIdPair); bool selAllowed = makeAppropriateConstraint(onSketchPos); @@ -1245,22 +1197,7 @@ public: sketchgui->draw(false, false); // Redraw } else { - if (newselGeoType == Part::GeomPoint::getClassTypeId()) { - selPoints.pop_back(); - } - else if (newselGeoType == Part::GeomLineSegment::getClassTypeId()) { - selLine.pop_back(); - } - else if (newselGeoType == Part::GeomArcOfCircle::getClassTypeId() - || newselGeoType == Part::GeomCircle::getClassTypeId()) { - selCircleArc.pop_back(); - } - else if (newselGeoType == Part::GeomEllipse::getClassTypeId() - || newselGeoType == Part::GeomArcOfEllipse::getClassTypeId() - || newselGeoType == Part::GeomArcOfHyperbola::getClassTypeId() - || newselGeoType == Part::GeomArcOfParabola::getClassTypeId()) { - selEllipseAndCo.pop_back(); - } + selVector.pop_back(); } } return true; @@ -1280,6 +1217,68 @@ protected: Sketcher::SketchObject* Obj; + void finalizeCommand() + { + // Ask for the value of datum constraints + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); + bool show = hGrp->GetBool("ShowDialogOnDistanceConstraint", true); + const std::vector& ConStr = Obj->Constraints.getValues(); + + bool commandHandledInEditDatum = false; + for (int i = numberOfConstraintsCreated - 1; i >= 0; i--) { + if (show && ConStr[ConStr.size() - 1 - i]->isDimensional() && ConStr[ConStr.size() - 1 - i]->isDriving) { + commandHandledInEditDatum = true; + EditDatumDialog editDatumDialog(sketchgui, ConStr.size() - 1 - i); + editDatumDialog.exec(); + if (!editDatumDialog.isSuccess()) { + break; + } + } + } + + if (!commandHandledInEditDatum) + Gui::Command::commitCommand(); + + // This code enables the continuous creation mode. + bool continuousMode = hGrp->GetBool("ContinuousCreationMode", true); + if (continuousMode) { + Gui::Selection().clearSelection(); + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Dimension")); + numberOfConstraintsCreated = 0; + specialConstraint = SpecialConstraint::None; + previousOnSketchPos = Base::Vector2d(0.f, 0.f); + selPoints.clear(); + selLine.clear(); + selCircleArc.clear(); + selEllipseAndCo.clear(); + } + else { + sketchgui->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider + } + } + + std::vector& getSelectionVector(Base::Type selGeoType) { + if (selGeoType == Part::GeomPoint::getClassTypeId()) { + return selPoints; + } + else if (selGeoType == Part::GeomLineSegment::getClassTypeId()) { + return selLine; + } + else if (selGeoType == Part::GeomArcOfCircle::getClassTypeId() || + selGeoType == Part::GeomCircle::getClassTypeId()) { + return selCircleArc; + } + else if (selGeoType == Part::GeomEllipse::getClassTypeId() || + selGeoType == Part::GeomArcOfEllipse::getClassTypeId() || + selGeoType == Part::GeomArcOfHyperbola::getClassTypeId() || + selGeoType == Part::GeomArcOfParabola::getClassTypeId()) { + return selEllipseAndCo; + } + + static std::vector emptyVector; + return emptyVector; + } + bool notSelectedYet(const SelIdPair& elem) { auto contains = [&](const std::vector& vec, const SelIdPair& elem) { From f3bca0d641df135404a318fa7a109623ad988e3a Mon Sep 17 00:00:00 2001 From: Paddle Date: Sat, 26 Aug 2023 19:55:17 +0200 Subject: [PATCH 06/12] Sketcher settings Dimension Add enums instead of magic numbers --- src/Mod/Sketcher/Gui/SketcherSettings.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/Mod/Sketcher/Gui/SketcherSettings.cpp b/src/Mod/Sketcher/Gui/SketcherSettings.cpp index 37678cac96..17b4deb15f 100644 --- a/src/Mod/Sketcher/Gui/SketcherSettings.cpp +++ b/src/Mod/Sketcher/Gui/SketcherSettings.cpp @@ -67,17 +67,23 @@ void SketcherSettings::saveSettings() ui->checkBoxNotifyConstraintSubstitutions->onSave(); ui->checkBoxAutoRemoveRedundants->onSave(); + enum { + DimensionSingleTool, + DimensionSeparateTools, + DimensionBoth + }; + // Dimensioning constraints mode ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/dimensioning"); bool singleTool = true; bool SeparatedTools = false; int index = ui->dimensioningMode->currentIndex(); switch (index) { - case 1: + case DimensionSeparateTools: singleTool = false; SeparatedTools = true; break; - case 2: + case DimensionBoth: singleTool = true; SeparatedTools = true; break; @@ -87,15 +93,21 @@ void SketcherSettings::saveSettings() ui->radiusDiameterMode->setEnabled(index != 1); + enum { + DimensionAutoRadiusDiam, + DimensionDiameter, + DimensionRadius + }; + bool Diameter = true; bool Radius = true; index = ui->radiusDiameterMode->currentIndex(); switch (index) { - case 1: + case DimensionDiameter: Diameter = true; Radius = false; break; - case 2: + case DimensionRadius: Diameter = false; Radius = true; break; From 3598dd48202ae268eb2efb2c59dbe17d56159b59 Mon Sep 17 00:00:00 2001 From: Paddle Date: Sat, 26 Aug 2023 22:13:11 +0200 Subject: [PATCH 07/12] Small simplification by removing useless tests in makeAppropriateConstraint --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 30 ++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index d2549a2ee9..59f7aa3bbe 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -1423,8 +1423,8 @@ protected: } } } - else if (selLine.size() > 0) { - if (selPoints.size() == 0 && selLine.size() == 1 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + else if (selLine.size() > 0) { //selPoints.size() is necessarily 0 + if (selLine.size() == 1 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { //axis can be selected but we don't want distance on axis! if ((selLine[0].GeoId != Sketcher::GeoEnum::VAxis && selLine[0].GeoId != Sketcher::GeoEnum::HAxis)) { //distance, horizontal, vertical, block @@ -1458,7 +1458,7 @@ protected: selAllowed = true; } } - else if (selPoints.size() == 0 && selLine.size() == 2 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + else if (selLine.size() == 2 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { //angle (if parallel: Distance (see in createAngleConstrain)), equal. if (availableConstraint == AvailableConstraint::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Angle constraint")); @@ -1477,7 +1477,7 @@ protected: availableConstraint = AvailableConstraint::RESET; } } - else if (selPoints.size() == 0 && selLine.size() >= 3 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + else if (selLine.size() >= 3 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { //equality. if (availableConstraint == AvailableConstraint::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraints")); @@ -1488,7 +1488,7 @@ protected: availableConstraint = AvailableConstraint::RESET; } } - else if (selPoints.size() == 0 && selLine.size() == 1 && selCircleArc.size() == 1 && selEllipseAndCo.size() == 0) { + else if (selLine.size() == 1 && selCircleArc.size() == 1 && selEllipseAndCo.size() == 0) { //Distance. if (availableConstraint == AvailableConstraint::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add length constraint")); @@ -1497,7 +1497,7 @@ protected: availableConstraint = AvailableConstraint::RESET; } } - else if (selPoints.size() == 0 && selLine.size() == 1 && selCircleArc.size() == 2 && selEllipseAndCo.size() == 0) { + else if (selLine.size() == 1 && selCircleArc.size() == 2 && selEllipseAndCo.size() == 0) { //symmetry. if (availableConstraint == AvailableConstraint::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Symmetry constraints")); @@ -1506,7 +1506,7 @@ protected: availableConstraint = AvailableConstraint::RESET; } } - else if (selPoints.size() == 0 && selLine.size() == 1 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 1) { + else if (selLine.size() == 1 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 1) { //TODO distance between line and ellipse/arc of... not supported yet. if (availableConstraint == AvailableConstraint::FIRST) { //selAllowed = true; @@ -1514,14 +1514,14 @@ protected: } } } - else if (selCircleArc.size() > 0) { - if (selPoints.size() == 0 && selLine.size() == 0 && selCircleArc.size() == 1 && selEllipseAndCo.size() == 0) { + else if (selCircleArc.size() > 0) { //selPoints.size() & selLine.size() are necessarily 0 + if (selCircleArc.size() == 1 && selEllipseAndCo.size() == 0) { //Radius/diameter. Mode changes in createRadiusDiameterConstrain. restartCommand(QT_TRANSLATE_NOOP("Command", "Add Radius constraint")); createRadiusDiameterConstrain(selCircleArc[0].GeoId, onSketchPos); selAllowed = true; } - else if (selPoints.size() == 0 && selLine.size() == 0 && selCircleArc.size() == 2 && selEllipseAndCo.size() == 0) { + else if (selCircleArc.size() == 2 && selEllipseAndCo.size() == 0) { //Distance, radial distance, equality if (availableConstraint == AvailableConstraint::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add length constraint")); @@ -1544,7 +1544,7 @@ protected: availableConstraint = AvailableConstraint::RESET; } } - else if (selPoints.size() == 0 && selLine.size() == 0 && selCircleArc.size() > 2 && selEllipseAndCo.size() == 0) { + else if (selCircleArc.size() > 2 && selEllipseAndCo.size() == 0) { //equality. if (availableConstraint == AvailableConstraint::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraint")); @@ -1555,7 +1555,7 @@ protected: availableConstraint = AvailableConstraint::RESET; } } - else if (selPoints.size() == 0 && selLine.size() == 0 && selCircleArc.size() == 1 && selEllipseAndCo.size() == 1) { + else if (selCircleArc.size() == 1 && selEllipseAndCo.size() == 1) { //TODO distance between circle and ellipse/arc of... not supported yet. if (availableConstraint == AvailableConstraint::FIRST) { //selAllowed = true; @@ -1563,12 +1563,12 @@ protected: } } } - else if (selEllipseAndCo.size() > 0) { - if (selPoints.size() == 0 && selLine.size() == 0 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 1) { + else if (selEllipseAndCo.size() > 0) { //selPoints.size() & selLine.size() & selCircleArc.size() are necessarily 0 + if (selEllipseAndCo.size() == 1) { //One ellipse or arc of ellipse/hyperbola/parabola - no constrain to attribute selAllowed = true; } - else if (selPoints.size() == 0 && selLine.size() == 0 && selCircleArc.size() == 0 && selEllipseAndCo.size() > 1) { + else if (selEllipseAndCo.size() > 1) { //only ellipse or arc of of same kind, then equality of all radius. bool allTheSame = 1; const Part::Geometry* geom = Obj->getGeometry(selEllipseAndCo[0].GeoId); From 1fcfdedb05c1f96b6c2db1e39c6e990fce1d2592 Mon Sep 17 00:00:00 2001 From: Paddle Date: Sun, 27 Aug 2023 07:26:53 +0200 Subject: [PATCH 08/12] Replace multiple occurence of selVec.size() by s_vec to clean the makeAppropriateConstraint function --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 78 +++++++++++---------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 59f7aa3bbe..c59059bd78 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -1298,8 +1298,14 @@ protected: bool makeAppropriateConstraint(Base::Vector2d onSketchPos) { bool selAllowed = false; - if (selPoints.size() > 0) { - if (selPoints.size() == 1 && selLine.size() == 0 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + + size_t s_pts = selPoints.size(); + size_t s_lns = selLine.size(); + size_t s_cir = selCircleArc.size(); + size_t s_ell = selEllipseAndCo.size(); + + if (s_pts > 0) { + if (s_pts == 1 && s_lns == 0 && s_cir == 0 && s_ell == 0) { //Lock, autodistance if (availableConstraint == AvailableConstraint::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add lock constraint")); @@ -1314,7 +1320,7 @@ protected: availableConstraint = AvailableConstraint::RESET; } } - else if (selPoints.size() == 2 && selLine.size() == 0 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + else if (s_pts == 2 && s_lns == 0 && s_cir == 0 && s_ell == 0) { //distance, horizontal, vertical if (availableConstraint == AvailableConstraint::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance constraint")); @@ -1331,7 +1337,7 @@ protected: availableConstraint = AvailableConstraint::RESET; } } - else if (selPoints.size() == 1 && selLine.size() == 1 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + else if (s_pts == 1 && s_lns == 1 && s_cir == 0 && s_ell == 0) { //distance, Symmetry if (availableConstraint == AvailableConstraint::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add point to line Distance constraint")); @@ -1344,18 +1350,18 @@ protected: availableConstraint = AvailableConstraint::RESET; } } - else if (selPoints.size() == 3 && selLine.size() == 0 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + else if (s_pts == 3 && s_lns == 0 && s_cir == 0 && s_ell == 0) { //Horizontal, vertical, symmetry if (availableConstraint == AvailableConstraint::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Horizontal' constraints")); - for (int i = 0; i < selPoints.size() - 1; i++) { + for (int i = 0; i < s_pts - 1; i++) { createHorizontalConstrain(selPoints[i].GeoId, selPoints[i].PosId, selPoints[i + 1].GeoId, selPoints[i + 1].PosId); } selAllowed = true; } if (availableConstraint == AvailableConstraint::SECOND) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Vertical' constraints")); - for (int i = 0; i < selPoints.size() - 1; i++) { + for (int i = 0; i < s_pts - 1; i++) { createVerticalConstrain(selPoints[i].GeoId, selPoints[i].PosId, selPoints[i + 1].GeoId, selPoints[i + 1].PosId); } } @@ -1365,24 +1371,24 @@ protected: availableConstraint = AvailableConstraint::RESET; } } - else if (selPoints.size() >= 4 && selLine.size() == 0 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + else if (s_pts >= 4 && s_lns == 0 && s_cir == 0 && s_ell == 0) { //Horizontal, vertical if (availableConstraint == AvailableConstraint::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Horizontal' constraints")); - for (int i = 0; i < selPoints.size() - 1; i++) { + for (int i = 0; i < s_pts - 1; i++) { createHorizontalConstrain(selPoints[i].GeoId, selPoints[i].PosId, selPoints[i + 1].GeoId, selPoints[i + 1].PosId); } selAllowed = true; } if (availableConstraint == AvailableConstraint::SECOND) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Vertical' constraints")); - for (int i = 0; i < selPoints.size() - 1; i++) { + for (int i = 0; i < s_pts - 1; i++) { createVerticalConstrain(selPoints[i].GeoId, selPoints[i].PosId, selPoints[i + 1].GeoId, selPoints[i + 1].PosId); } availableConstraint = AvailableConstraint::RESET; } } - else if (selPoints.size() == 2 && selLine.size() == 1 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + else if (s_pts == 2 && s_lns == 1 && s_cir == 0 && s_ell == 0) { //symmetry, distances if (availableConstraint == AvailableConstraint::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Symmetry constraint")); @@ -1391,31 +1397,31 @@ protected: } if (availableConstraint == AvailableConstraint::SECOND) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance constraints")); - for (int i = 0; i < selPoints.size(); i++) { + for (int i = 0; i < s_pts; i++) { createDistanceConstrain(selPoints[i].GeoId, selPoints[i].PosId, selLine[0].GeoId, selLine[0].PosId, onSketchPos); } availableConstraint = AvailableConstraint::RESET; } } - else if (selPoints.size() >= 3 && selLine.size() == 1 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + else if (s_pts >= 3 && s_lns == 1 && s_cir == 0 && s_ell == 0) { //distances if (availableConstraint == AvailableConstraint::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance constraints")); - for (int i = 0; i < selPoints.size(); i++) { + for (int i = 0; i < s_pts; i++) { createDistanceConstrain(selPoints[i].GeoId, selPoints[i].PosId, selLine[0].GeoId, selLine[0].PosId, onSketchPos); } selAllowed = true; availableConstraint = AvailableConstraint::RESET; } } - else if (selPoints.size() >= 1 && selLine.size() == 0 && selCircleArc.size() == 1 && selEllipseAndCo.size() == 0) { + else if (s_pts >= 1 && s_lns == 0 && s_cir == 1 && s_ell == 0) { //distance between 1 point and circle/arc not supported yet. if (availableConstraint == AvailableConstraint::FIRST) { //nothing yet //availableConstraint = AvailableConstraint::RESET; } } - else if (selPoints.size() >= 1 && selLine.size() == 0 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 1) { + else if (s_pts >= 1 && s_lns == 0 && s_cir == 0 && s_ell == 1) { //distance between 1 point and elipse/arc of... not supported yet. if (availableConstraint == AvailableConstraint::FIRST) { //nothing yet @@ -1423,8 +1429,8 @@ protected: } } } - else if (selLine.size() > 0) { //selPoints.size() is necessarily 0 - if (selLine.size() == 1 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + else if (s_lns > 0) { //s_pts is necessarily 0 + if (s_lns == 1 && s_cir == 0 && s_ell == 0) { //axis can be selected but we don't want distance on axis! if ((selLine[0].GeoId != Sketcher::GeoEnum::VAxis && selLine[0].GeoId != Sketcher::GeoEnum::HAxis)) { //distance, horizontal, vertical, block @@ -1458,7 +1464,7 @@ protected: selAllowed = true; } } - else if (selLine.size() == 2 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + else if (s_lns == 2 && s_cir == 0 && s_ell == 0) { //angle (if parallel: Distance (see in createAngleConstrain)), equal. if (availableConstraint == AvailableConstraint::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Angle constraint")); @@ -1477,18 +1483,18 @@ protected: availableConstraint = AvailableConstraint::RESET; } } - else if (selLine.size() >= 3 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 0) { + else if (s_lns >= 3 && s_cir == 0 && s_ell == 0) { //equality. if (availableConstraint == AvailableConstraint::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraints")); - for (int i = 0; i < selLine.size() - 1; i++) { + for (int i = 0; i < s_lns - 1; i++) { createEqualityConstrain(selLine[i].GeoId, selLine[i + 1].GeoId); } selAllowed = true; availableConstraint = AvailableConstraint::RESET; } } - else if (selLine.size() == 1 && selCircleArc.size() == 1 && selEllipseAndCo.size() == 0) { + else if (s_lns == 1 && s_cir == 1 && s_ell == 0) { //Distance. if (availableConstraint == AvailableConstraint::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add length constraint")); @@ -1497,7 +1503,7 @@ protected: availableConstraint = AvailableConstraint::RESET; } } - else if (selLine.size() == 1 && selCircleArc.size() == 2 && selEllipseAndCo.size() == 0) { + else if (s_lns == 1 && s_cir == 2 && s_ell == 0) { //symmetry. if (availableConstraint == AvailableConstraint::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Symmetry constraints")); @@ -1506,7 +1512,7 @@ protected: availableConstraint = AvailableConstraint::RESET; } } - else if (selLine.size() == 1 && selCircleArc.size() == 0 && selEllipseAndCo.size() == 1) { + else if (s_lns == 1 && s_cir == 0 && s_ell == 1) { //TODO distance between line and ellipse/arc of... not supported yet. if (availableConstraint == AvailableConstraint::FIRST) { //selAllowed = true; @@ -1514,14 +1520,14 @@ protected: } } } - else if (selCircleArc.size() > 0) { //selPoints.size() & selLine.size() are necessarily 0 - if (selCircleArc.size() == 1 && selEllipseAndCo.size() == 0) { + else if (s_cir > 0) { //s_pts & s_lns are necessarily 0 + if (s_cir == 1 && s_ell == 0) { //Radius/diameter. Mode changes in createRadiusDiameterConstrain. restartCommand(QT_TRANSLATE_NOOP("Command", "Add Radius constraint")); createRadiusDiameterConstrain(selCircleArc[0].GeoId, onSketchPos); selAllowed = true; } - else if (selCircleArc.size() == 2 && selEllipseAndCo.size() == 0) { + else if (s_cir == 2 && s_ell == 0) { //Distance, radial distance, equality if (availableConstraint == AvailableConstraint::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add length constraint")); @@ -1538,24 +1544,24 @@ protected: } if (availableConstraint == AvailableConstraint::THIRD) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraint")); - for (int i = 0; i < selCircleArc.size() - 1; i++) { + for (int i = 0; i < s_cir - 1; i++) { createEqualityConstrain(selCircleArc[i].GeoId, selCircleArc[i + 1].GeoId); } availableConstraint = AvailableConstraint::RESET; } } - else if (selCircleArc.size() > 2 && selEllipseAndCo.size() == 0) { + else if (s_cir > 2 && s_ell == 0) { //equality. if (availableConstraint == AvailableConstraint::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraint")); - for (int i = 0; i < selCircleArc.size() - 1; i++) { + for (int i = 0; i < s_cir - 1; i++) { createEqualityConstrain(selCircleArc[i].GeoId, selCircleArc[i + 1].GeoId); } selAllowed = true; availableConstraint = AvailableConstraint::RESET; } } - else if (selCircleArc.size() == 1 && selEllipseAndCo.size() == 1) { + else if (s_cir == 1 && s_ell == 1) { //TODO distance between circle and ellipse/arc of... not supported yet. if (availableConstraint == AvailableConstraint::FIRST) { //selAllowed = true; @@ -1563,17 +1569,17 @@ protected: } } } - else if (selEllipseAndCo.size() > 0) { //selPoints.size() & selLine.size() & selCircleArc.size() are necessarily 0 - if (selEllipseAndCo.size() == 1) { + else if (s_ell > 0) { //s_pts & s_lns & s_cir are necessarily 0 + if (s_ell == 1) { //One ellipse or arc of ellipse/hyperbola/parabola - no constrain to attribute selAllowed = true; } - else if (selEllipseAndCo.size() > 1) { + else if (s_ell > 1) { //only ellipse or arc of of same kind, then equality of all radius. bool allTheSame = 1; const Part::Geometry* geom = Obj->getGeometry(selEllipseAndCo[0].GeoId); Base::Type typeOf = geom->getTypeId(); - for (int i = 1; i < selEllipseAndCo.size(); i++) { + for (int i = 1; i < s_ell; i++) { const Part::Geometry* geomi = Obj->getGeometry(selEllipseAndCo[i].GeoId); if (typeOf != geomi->getTypeId()) { allTheSame = 0; @@ -1581,7 +1587,7 @@ protected: } if (allTheSame) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraint")); - for (int i = 1; i < selEllipseAndCo.size(); i++) { + for (int i = 1; i < s_ell; i++) { createEqualityConstrain(selEllipseAndCo[0].GeoId, selEllipseAndCo[i].GeoId); } selAllowed = true; From f1f31fd3df61687321d09d8153910a90f0189365 Mon Sep 17 00:00:00 2001 From: Paddle Date: Sun, 27 Aug 2023 08:25:20 +0200 Subject: [PATCH 09/12] Refactor makeAppropriateConstraint --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 610 +++++++++++--------- 1 file changed, 328 insertions(+), 282 deletions(-) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index c59059bd78..61452d0d4a 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -1305,298 +1305,344 @@ protected: size_t s_ell = selEllipseAndCo.size(); if (s_pts > 0) { - if (s_pts == 1 && s_lns == 0 && s_cir == 0 && s_ell == 0) { - //Lock, autodistance - if (availableConstraint == AvailableConstraint::FIRST) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add lock constraint")); - specialConstraint = SpecialConstraint::Block; - createDistanceXYConstrain(Sketcher::DistanceX, selPoints[0].GeoId, selPoints[0].PosId, Sketcher::GeoEnum::RtPnt, Sketcher::PointPos::start, onSketchPos); - createDistanceXYConstrain(Sketcher::DistanceY, selPoints[0].GeoId, selPoints[0].PosId, Sketcher::GeoEnum::RtPnt, Sketcher::PointPos::start, onSketchPos); - selAllowed = true; - } - if (availableConstraint == AvailableConstraint::SECOND) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Distance to origin' constraint")); - createDistanceConstrain(selPoints[0].GeoId, selPoints[0].PosId, Sketcher::GeoEnum::RtPnt, Sketcher::PointPos::start, onSketchPos); - availableConstraint = AvailableConstraint::RESET; - } - } - else if (s_pts == 2 && s_lns == 0 && s_cir == 0 && s_ell == 0) { - //distance, horizontal, vertical - if (availableConstraint == AvailableConstraint::FIRST) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance constraint")); - createDistanceConstrain(selPoints[0].GeoId, selPoints[0].PosId, selPoints[1].GeoId, selPoints[1].PosId, onSketchPos); - selAllowed = true; - } - if (availableConstraint == AvailableConstraint::SECOND) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Horizontal' constraints")); - createHorizontalConstrain(selPoints[0].GeoId, selPoints[0].PosId, selPoints[1].GeoId, selPoints[1].PosId); - } - if (availableConstraint == AvailableConstraint::THIRD) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Vertical' constraints")); - createVerticalConstrain(selPoints[0].GeoId, selPoints[0].PosId, selPoints[1].GeoId, selPoints[1].PosId); - availableConstraint = AvailableConstraint::RESET; - } - } - else if (s_pts == 1 && s_lns == 1 && s_cir == 0 && s_ell == 0) { - //distance, Symmetry - if (availableConstraint == AvailableConstraint::FIRST) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add point to line Distance constraint")); - createDistanceConstrain(selPoints[0].GeoId, selPoints[0].PosId, selLine[0].GeoId, selLine[0].PosId, onSketchPos); // line to be on second parameter - selAllowed = true; - } - if (availableConstraint == AvailableConstraint::SECOND) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add Symmetry constraint")); - createSymmetryConstrain(selLine[0].GeoId, Sketcher::PointPos::start, selLine[0].GeoId, Sketcher::PointPos::end, selPoints[0].GeoId, selPoints[0].PosId); - availableConstraint = AvailableConstraint::RESET; - } - } - else if (s_pts == 3 && s_lns == 0 && s_cir == 0 && s_ell == 0) { - //Horizontal, vertical, symmetry - if (availableConstraint == AvailableConstraint::FIRST) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Horizontal' constraints")); - for (int i = 0; i < s_pts - 1; i++) { - createHorizontalConstrain(selPoints[i].GeoId, selPoints[i].PosId, selPoints[i + 1].GeoId, selPoints[i + 1].PosId); - } - selAllowed = true; - } - if (availableConstraint == AvailableConstraint::SECOND) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Vertical' constraints")); - for (int i = 0; i < s_pts - 1; i++) { - createVerticalConstrain(selPoints[i].GeoId, selPoints[i].PosId, selPoints[i + 1].GeoId, selPoints[i + 1].PosId); - } - } - if (availableConstraint == AvailableConstraint::THIRD) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add Symmetry constraints")); - createSymmetryConstrain(selPoints[0].GeoId, selPoints[0].PosId, selPoints[1].GeoId, selPoints[1].PosId, selPoints[2].GeoId, selPoints[2].PosId); - availableConstraint = AvailableConstraint::RESET; - } - } - else if (s_pts >= 4 && s_lns == 0 && s_cir == 0 && s_ell == 0) { - //Horizontal, vertical - if (availableConstraint == AvailableConstraint::FIRST) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Horizontal' constraints")); - for (int i = 0; i < s_pts - 1; i++) { - createHorizontalConstrain(selPoints[i].GeoId, selPoints[i].PosId, selPoints[i + 1].GeoId, selPoints[i + 1].PosId); - } - selAllowed = true; - } - if (availableConstraint == AvailableConstraint::SECOND) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Vertical' constraints")); - for (int i = 0; i < s_pts - 1; i++) { - createVerticalConstrain(selPoints[i].GeoId, selPoints[i].PosId, selPoints[i + 1].GeoId, selPoints[i + 1].PosId); - } - availableConstraint = AvailableConstraint::RESET; - } - } - else if (s_pts == 2 && s_lns == 1 && s_cir == 0 && s_ell == 0) { - //symmetry, distances - if (availableConstraint == AvailableConstraint::FIRST) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add Symmetry constraint")); - createSymmetryConstrain(selPoints[0].GeoId, selPoints[0].PosId, selPoints[1].GeoId, selPoints[1].PosId, selLine[0].GeoId, selLine[0].PosId); - selAllowed = true; - } - if (availableConstraint == AvailableConstraint::SECOND) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance constraints")); - for (int i = 0; i < s_pts; i++) { - createDistanceConstrain(selPoints[i].GeoId, selPoints[i].PosId, selLine[0].GeoId, selLine[0].PosId, onSketchPos); - } - availableConstraint = AvailableConstraint::RESET; - } - } - else if (s_pts >= 3 && s_lns == 1 && s_cir == 0 && s_ell == 0) { - //distances - if (availableConstraint == AvailableConstraint::FIRST) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance constraints")); - for (int i = 0; i < s_pts; i++) { - createDistanceConstrain(selPoints[i].GeoId, selPoints[i].PosId, selLine[0].GeoId, selLine[0].PosId, onSketchPos); - } - selAllowed = true; - availableConstraint = AvailableConstraint::RESET; - } - } - else if (s_pts >= 1 && s_lns == 0 && s_cir == 1 && s_ell == 0) { - //distance between 1 point and circle/arc not supported yet. - if (availableConstraint == AvailableConstraint::FIRST) { - //nothing yet - //availableConstraint = AvailableConstraint::RESET; - } - } - else if (s_pts >= 1 && s_lns == 0 && s_cir == 0 && s_ell == 1) { - //distance between 1 point and elipse/arc of... not supported yet. - if (availableConstraint == AvailableConstraint::FIRST) { - //nothing yet - //availableConstraint = AvailableConstraint::RESET; - } - } + if (s_pts == 1 && s_lns == 0 && s_cir == 0 && s_ell == 0) { makeCts_1Point(selAllowed, onSketchPos); } + else if (s_pts == 2 && s_lns == 0 && s_cir == 0 && s_ell == 0) { makeCts_2Point(selAllowed, onSketchPos); } + else if (s_pts == 1 && s_lns == 1 && s_cir == 0 && s_ell == 0) { makeCts_1Point1Line(selAllowed, onSketchPos); } + else if (s_pts == 3 && s_lns == 0 && s_cir == 0 && s_ell == 0) { makeCts_3Point(selAllowed, s_pts); } + else if (s_pts >= 4 && s_lns == 0 && s_cir == 0 && s_ell == 0) { makeCts_4MorePoint(selAllowed, s_pts); } + else if (s_pts == 2 && s_lns == 1 && s_cir == 0 && s_ell == 0) { makeCts_2Point1Line(selAllowed, onSketchPos, s_pts); } + else if (s_pts >= 3 && s_lns == 1 && s_cir == 0 && s_ell == 0) { makeCts_3MorePoint1Line(selAllowed, onSketchPos, s_pts); } + else if (s_pts >= 1 && s_lns == 0 && s_cir == 1 && s_ell == 0) { makeCts_1MorePoint1Circle(selAllowed); } + else if (s_pts >= 1 && s_lns == 0 && s_cir == 0 && s_ell == 1) { makeCts_1MorePoint1Ellipse(selAllowed); } } else if (s_lns > 0) { //s_pts is necessarily 0 - if (s_lns == 1 && s_cir == 0 && s_ell == 0) { - //axis can be selected but we don't want distance on axis! - if ((selLine[0].GeoId != Sketcher::GeoEnum::VAxis && selLine[0].GeoId != Sketcher::GeoEnum::HAxis)) { - //distance, horizontal, vertical, block - if (availableConstraint == AvailableConstraint::FIRST) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add length constraint")); - createDistanceConstrain(selLine[0].GeoId, Sketcher::PointPos::start, selLine[0].GeoId, Sketcher::PointPos::end, onSketchPos); - selAllowed = true; - } - if (availableConstraint == AvailableConstraint::SECOND) { - if (isHorizontalVerticalBlock(selLine[0].GeoId)) { - //if the line has a vertical horizontal or block constraint then we don't switch to other modes as they are horizontal, vertical and block. - availableConstraint = AvailableConstraint::RESET; - } - else { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add Horizontal constraint")); - createHorizontalConstrain(selLine[0].GeoId, Sketcher::PointPos::none, GeoEnum::GeoUndef, Sketcher::PointPos::none); - } - } - if (availableConstraint == AvailableConstraint::THIRD) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add Vertical constraint")); - createVerticalConstrain(selLine[0].GeoId, Sketcher::PointPos::none, GeoEnum::GeoUndef, Sketcher::PointPos::none); - } - if (availableConstraint == AvailableConstraint::FOURTH) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add Block constraint")); - createBlockConstrain(selLine[0].GeoId); - availableConstraint = AvailableConstraint::RESET; - } - } - else { - //But axis can still be selected - selAllowed = true; - } - } - else if (s_lns == 2 && s_cir == 0 && s_ell == 0) { - //angle (if parallel: Distance (see in createAngleConstrain)), equal. - if (availableConstraint == AvailableConstraint::FIRST) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add Angle constraint")); - createAngleConstrain(selLine[0].GeoId, selLine[1].GeoId, onSketchPos); - selAllowed = true; - } - if (availableConstraint == AvailableConstraint::SECOND) { - if (selLine[0].GeoId == Sketcher::GeoEnum::VAxis || selLine[1].GeoId == Sketcher::GeoEnum::VAxis - || selLine[0].GeoId == Sketcher::GeoEnum::HAxis || selLine[1].GeoId == Sketcher::GeoEnum::HAxis) { - //if one line is axis, then can't equal.. - } - else { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraint")); - createEqualityConstrain(selLine[0].GeoId, selLine[1].GeoId); - } - availableConstraint = AvailableConstraint::RESET; - } - } - else if (s_lns >= 3 && s_cir == 0 && s_ell == 0) { - //equality. - if (availableConstraint == AvailableConstraint::FIRST) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraints")); - for (int i = 0; i < s_lns - 1; i++) { - createEqualityConstrain(selLine[i].GeoId, selLine[i + 1].GeoId); - } - selAllowed = true; - availableConstraint = AvailableConstraint::RESET; - } - } - else if (s_lns == 1 && s_cir == 1 && s_ell == 0) { - //Distance. - if (availableConstraint == AvailableConstraint::FIRST) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add length constraint")); - createDistanceConstrain(selCircleArc[0].GeoId, selCircleArc[0].PosId, selLine[0].GeoId, selLine[0].PosId, onSketchPos); // line to be on second parameter - selAllowed = true; - availableConstraint = AvailableConstraint::RESET; - } - } - else if (s_lns == 1 && s_cir == 2 && s_ell == 0) { - //symmetry. - if (availableConstraint == AvailableConstraint::FIRST) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add Symmetry constraints")); - createSymmetryConstrain(selCircleArc[0].GeoId, Sketcher::PointPos::mid, selCircleArc[1].GeoId, Sketcher::PointPos::mid, selLine[0].GeoId, selLine[0].PosId); - selAllowed = true; - availableConstraint = AvailableConstraint::RESET; - } - } - else if (s_lns == 1 && s_cir == 0 && s_ell == 1) { - //TODO distance between line and ellipse/arc of... not supported yet. - if (availableConstraint == AvailableConstraint::FIRST) { - //selAllowed = true; - //availableConstraint = AvailableConstraint::RESET; - } - } + if (s_lns == 1 && s_cir == 0 && s_ell == 0) { makeCts_1Line(selAllowed, onSketchPos); } + else if (s_lns == 2 && s_cir == 0 && s_ell == 0) { makeCts_2Line(selAllowed, onSketchPos); } + else if (s_lns >= 3 && s_cir == 0 && s_ell == 0) { makeCts_3MoreLine(selAllowed, s_lns); } + else if (s_lns == 1 && s_cir == 1 && s_ell == 0) { makeCts_1Line1Circle(selAllowed, onSketchPos); } + else if (s_lns == 1 && s_cir == 2 && s_ell == 0) { makeCts_1Line2Circle(selAllowed); } + else if (s_lns == 1 && s_cir == 0 && s_ell == 1) { makeCts_1Line1Ellipse(selAllowed); } } else if (s_cir > 0) { //s_pts & s_lns are necessarily 0 - if (s_cir == 1 && s_ell == 0) { - //Radius/diameter. Mode changes in createRadiusDiameterConstrain. - restartCommand(QT_TRANSLATE_NOOP("Command", "Add Radius constraint")); - createRadiusDiameterConstrain(selCircleArc[0].GeoId, onSketchPos); - selAllowed = true; - } - else if (s_cir == 2 && s_ell == 0) { - //Distance, radial distance, equality - if (availableConstraint == AvailableConstraint::FIRST) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add length constraint")); - createDistanceConstrain(selCircleArc[0].GeoId, selCircleArc[0].PosId, selCircleArc[1].GeoId, selCircleArc[1].PosId, onSketchPos); - selAllowed = true; - } - if (availableConstraint == AvailableConstraint::SECOND) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add concentric and length constraint")); - createDistanceConstrain(selCircleArc[0].GeoId, selCircleArc[0].PosId, selCircleArc[1].GeoId, selCircleArc[1].PosId, onSketchPos); - bool created = createCoincidenceConstrain(selCircleArc[0].GeoId, Sketcher::PointPos::mid, selCircleArc[1].GeoId, Sketcher::PointPos::mid); - if (!created) { //Already concentric, so skip to next - availableConstraint = AvailableConstraint::THIRD; - } - } - if (availableConstraint == AvailableConstraint::THIRD) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraint")); - for (int i = 0; i < s_cir - 1; i++) { - createEqualityConstrain(selCircleArc[i].GeoId, selCircleArc[i + 1].GeoId); - } - availableConstraint = AvailableConstraint::RESET; - } - } - else if (s_cir > 2 && s_ell == 0) { - //equality. - if (availableConstraint == AvailableConstraint::FIRST) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraint")); - for (int i = 0; i < s_cir - 1; i++) { - createEqualityConstrain(selCircleArc[i].GeoId, selCircleArc[i + 1].GeoId); - } - selAllowed = true; - availableConstraint = AvailableConstraint::RESET; - } - } - else if (s_cir == 1 && s_ell == 1) { - //TODO distance between circle and ellipse/arc of... not supported yet. - if (availableConstraint == AvailableConstraint::FIRST) { - //selAllowed = true; - //availableConstraint = AvailableConstraint::RESET; - } - } + if (s_cir == 1 && s_ell == 0) { makeCts_1Circle(selAllowed, onSketchPos); } + else if (s_cir == 2 && s_ell == 0) { makeCts_2Circle(selAllowed, onSketchPos); } + else if (s_cir >= 3 && s_ell == 0) { makeCts_3MoreCircle(selAllowed, s_cir); } + else if (s_cir == 1 && s_ell == 1) { makeCts_1Circle1Ellipse(selAllowed); } } else if (s_ell > 0) { //s_pts & s_lns & s_cir are necessarily 0 - if (s_ell == 1) { - //One ellipse or arc of ellipse/hyperbola/parabola - no constrain to attribute - selAllowed = true; - } - else if (s_ell > 1) { - //only ellipse or arc of of same kind, then equality of all radius. - bool allTheSame = 1; - const Part::Geometry* geom = Obj->getGeometry(selEllipseAndCo[0].GeoId); - Base::Type typeOf = geom->getTypeId(); - for (int i = 1; i < s_ell; i++) { - const Part::Geometry* geomi = Obj->getGeometry(selEllipseAndCo[i].GeoId); - if (typeOf != geomi->getTypeId()) { - allTheSame = 0; - } - } - if (allTheSame) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraint")); - for (int i = 1; i < s_ell; i++) { - createEqualityConstrain(selEllipseAndCo[0].GeoId, selEllipseAndCo[i].GeoId); - } - selAllowed = true; - } - } + if (s_ell == 1) { makeCts_1Ellipse(selAllowed); } + else if (s_ell >= 2) { makeCts_2MoreEllipse(selAllowed, s_ell); } } return selAllowed; } + void makeCts_1Point(bool& selAllowed, Base::Vector2d onSketchPos) + { + //Lock, autodistance + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add lock constraint")); + specialConstraint = SpecialConstraint::Block; + createDistanceXYConstrain(Sketcher::DistanceX, selPoints[0].GeoId, selPoints[0].PosId, Sketcher::GeoEnum::RtPnt, Sketcher::PointPos::start, onSketchPos); + createDistanceXYConstrain(Sketcher::DistanceY, selPoints[0].GeoId, selPoints[0].PosId, Sketcher::GeoEnum::RtPnt, Sketcher::PointPos::start, onSketchPos); + selAllowed = true; + } + if (availableConstraint == AvailableConstraint::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Distance to origin' constraint")); + createDistanceConstrain(selPoints[0].GeoId, selPoints[0].PosId, Sketcher::GeoEnum::RtPnt, Sketcher::PointPos::start, onSketchPos); + availableConstraint = AvailableConstraint::RESET; + } + } + void makeCts_2Point(bool& selAllowed, Base::Vector2d onSketchPos) + { + //distance, horizontal, vertical + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance constraint")); + createDistanceConstrain(selPoints[0].GeoId, selPoints[0].PosId, selPoints[1].GeoId, selPoints[1].PosId, onSketchPos); + selAllowed = true; + } + if (availableConstraint == AvailableConstraint::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Horizontal' constraints")); + createHorizontalConstrain(selPoints[0].GeoId, selPoints[0].PosId, selPoints[1].GeoId, selPoints[1].PosId); + } + if (availableConstraint == AvailableConstraint::THIRD) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Vertical' constraints")); + createVerticalConstrain(selPoints[0].GeoId, selPoints[0].PosId, selPoints[1].GeoId, selPoints[1].PosId); + availableConstraint = AvailableConstraint::RESET; + } + } + void makeCts_1Point1Line(bool& selAllowed, Base::Vector2d onSketchPos) + { + //distance, Symmetry + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add point to line Distance constraint")); + createDistanceConstrain(selPoints[0].GeoId, selPoints[0].PosId, selLine[0].GeoId, selLine[0].PosId, onSketchPos); // line to be on second parameter + selAllowed = true; + } + if (availableConstraint == AvailableConstraint::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Symmetry constraint")); + createSymmetryConstrain(selLine[0].GeoId, Sketcher::PointPos::start, selLine[0].GeoId, Sketcher::PointPos::end, selPoints[0].GeoId, selPoints[0].PosId); + availableConstraint = AvailableConstraint::RESET; + } + } + void makeCts_3Point(bool& selAllowed, size_t s_pts) + { + //Horizontal, vertical, symmetry + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Horizontal' constraints")); + for (int i = 0; i < s_pts - 1; i++) { + createHorizontalConstrain(selPoints[i].GeoId, selPoints[i].PosId, selPoints[i + 1].GeoId, selPoints[i + 1].PosId); + } + selAllowed = true; + } + if (availableConstraint == AvailableConstraint::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Vertical' constraints")); + for (int i = 0; i < s_pts - 1; i++) { + createVerticalConstrain(selPoints[i].GeoId, selPoints[i].PosId, selPoints[i + 1].GeoId, selPoints[i + 1].PosId); + } + } + if (availableConstraint == AvailableConstraint::THIRD) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Symmetry constraints")); + createSymmetryConstrain(selPoints[0].GeoId, selPoints[0].PosId, selPoints[1].GeoId, selPoints[1].PosId, selPoints[2].GeoId, selPoints[2].PosId); + availableConstraint = AvailableConstraint::RESET; + } + } + void makeCts_4MorePoint(bool& selAllowed, size_t s_pts) + { + //Horizontal, vertical + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Horizontal' constraints")); + for (int i = 0; i < s_pts - 1; i++) { + createHorizontalConstrain(selPoints[i].GeoId, selPoints[i].PosId, selPoints[i + 1].GeoId, selPoints[i + 1].PosId); + } + selAllowed = true; + } + if (availableConstraint == AvailableConstraint::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add 'Vertical' constraints")); + for (int i = 0; i < s_pts - 1; i++) { + createVerticalConstrain(selPoints[i].GeoId, selPoints[i].PosId, selPoints[i + 1].GeoId, selPoints[i + 1].PosId); + } + availableConstraint = AvailableConstraint::RESET; + } + } + void makeCts_2Point1Line(bool& selAllowed, Base::Vector2d onSketchPos, size_t s_pts) + { + //symmetry, distances + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Symmetry constraint")); + createSymmetryConstrain(selPoints[0].GeoId, selPoints[0].PosId, selPoints[1].GeoId, selPoints[1].PosId, selLine[0].GeoId, selLine[0].PosId); + selAllowed = true; + } + if (availableConstraint == AvailableConstraint::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance constraints")); + for (int i = 0; i < s_pts; i++) { + createDistanceConstrain(selPoints[i].GeoId, selPoints[i].PosId, selLine[0].GeoId, selLine[0].PosId, onSketchPos); + } + availableConstraint = AvailableConstraint::RESET; + } + } + void makeCts_3MorePoint1Line(bool& selAllowed, Base::Vector2d onSketchPos, size_t s_pts) + { + //distances + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance constraints")); + for (int i = 0; i < s_pts; i++) { + createDistanceConstrain(selPoints[i].GeoId, selPoints[i].PosId, selLine[0].GeoId, selLine[0].PosId, onSketchPos); + } + selAllowed = true; + availableConstraint = AvailableConstraint::RESET; + } + } + void makeCts_1MorePoint1Circle(bool& selAllowed) + { + //distance between 1 point and circle/arc not supported yet. + if (availableConstraint == AvailableConstraint::FIRST) { + //nothing yet + //availableConstraint = AvailableConstraint::RESET; + } + } + void makeCts_1MorePoint1Ellipse(bool& selAllowed) + { + //distance between 1 point and elipse/arc of... not supported yet. + if (availableConstraint == AvailableConstraint::FIRST) { + //nothing yet + //availableConstraint = AvailableConstraint::RESET; + } + } + + void makeCts_1Line(bool& selAllowed, Base::Vector2d onSketchPos) + { + //axis can be selected but we don't want distance on axis! + if ((selLine[0].GeoId != Sketcher::GeoEnum::VAxis && selLine[0].GeoId != Sketcher::GeoEnum::HAxis)) { + //distance, horizontal, vertical, block + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add length constraint")); + createDistanceConstrain(selLine[0].GeoId, Sketcher::PointPos::start, selLine[0].GeoId, Sketcher::PointPos::end, onSketchPos); + selAllowed = true; + } + if (availableConstraint == AvailableConstraint::SECOND) { + if (isHorizontalVerticalBlock(selLine[0].GeoId)) { + //if the line has a vertical horizontal or block constraint then we don't switch to other modes as they are horizontal, vertical and block. + availableConstraint = AvailableConstraint::RESET; + } + else { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Horizontal constraint")); + createHorizontalConstrain(selLine[0].GeoId, Sketcher::PointPos::none, GeoEnum::GeoUndef, Sketcher::PointPos::none); + } + } + if (availableConstraint == AvailableConstraint::THIRD) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Vertical constraint")); + createVerticalConstrain(selLine[0].GeoId, Sketcher::PointPos::none, GeoEnum::GeoUndef, Sketcher::PointPos::none); + } + if (availableConstraint == AvailableConstraint::FOURTH) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Block constraint")); + createBlockConstrain(selLine[0].GeoId); + availableConstraint = AvailableConstraint::RESET; + } + } + else { + //But axis can still be selected + selAllowed = true; + } + } + void makeCts_2Line(bool& selAllowed, Base::Vector2d onSketchPos) + { + //angle (if parallel: Distance (see in createAngleConstrain)), equal. + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Angle constraint")); + createAngleConstrain(selLine[0].GeoId, selLine[1].GeoId, onSketchPos); + selAllowed = true; + } + if (availableConstraint == AvailableConstraint::SECOND) { + if (selLine[0].GeoId == Sketcher::GeoEnum::VAxis || selLine[1].GeoId == Sketcher::GeoEnum::VAxis + || selLine[0].GeoId == Sketcher::GeoEnum::HAxis || selLine[1].GeoId == Sketcher::GeoEnum::HAxis) { + //if one line is axis, then can't equal.. + } + else { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraint")); + createEqualityConstrain(selLine[0].GeoId, selLine[1].GeoId); + } + availableConstraint = AvailableConstraint::RESET; + } + + } + void makeCts_3MoreLine(bool& selAllowed, size_t s_lns) + { + //equality. + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraints")); + for (int i = 0; i < s_lns - 1; i++) { + createEqualityConstrain(selLine[i].GeoId, selLine[i + 1].GeoId); + } + selAllowed = true; + availableConstraint = AvailableConstraint::RESET; + } + } + void makeCts_1Line1Circle(bool& selAllowed, Base::Vector2d onSketchPos) + { + //Distance. + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add length constraint")); + createDistanceConstrain(selCircleArc[0].GeoId, selCircleArc[0].PosId, selLine[0].GeoId, selLine[0].PosId, onSketchPos); // line to be on second parameter + selAllowed = true; + availableConstraint = AvailableConstraint::RESET; + } + } + void makeCts_1Line2Circle(bool& selAllowed) + { + //symmetry. + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Symmetry constraints")); + createSymmetryConstrain(selCircleArc[0].GeoId, Sketcher::PointPos::mid, selCircleArc[1].GeoId, Sketcher::PointPos::mid, selLine[0].GeoId, selLine[0].PosId); + selAllowed = true; + availableConstraint = AvailableConstraint::RESET; + } + } + void makeCts_1Line1Ellipse(bool& selAllowed) + { + //TODO distance between line and ellipse/arc of... not supported yet. + if (availableConstraint == AvailableConstraint::FIRST) { + //selAllowed = true; + //availableConstraint = AvailableConstraint::RESET; + } + } + + void makeCts_1Circle(bool& selAllowed, Base::Vector2d onSketchPos) + { + //Radius/diameter. Mode changes in createRadiusDiameterConstrain. + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Radius constraint")); + createRadiusDiameterConstrain(selCircleArc[0].GeoId, onSketchPos); + selAllowed = true; + } + void makeCts_2Circle(bool& selAllowed, Base::Vector2d onSketchPos) + { + //Distance, radial distance, equality + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add length constraint")); + createDistanceConstrain(selCircleArc[0].GeoId, selCircleArc[0].PosId, selCircleArc[1].GeoId, selCircleArc[1].PosId, onSketchPos); + selAllowed = true; + } + if (availableConstraint == AvailableConstraint::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add concentric and length constraint")); + createDistanceConstrain(selCircleArc[0].GeoId, selCircleArc[0].PosId, selCircleArc[1].GeoId, selCircleArc[1].PosId, onSketchPos); + bool created = createCoincidenceConstrain(selCircleArc[0].GeoId, Sketcher::PointPos::mid, selCircleArc[1].GeoId, Sketcher::PointPos::mid); + if (!created) { //Already concentric, so skip to next + availableConstraint = AvailableConstraint::THIRD; + } + } + if (availableConstraint == AvailableConstraint::THIRD) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraint")); + createEqualityConstrain(selCircleArc[0].GeoId, selCircleArc[1].GeoId); + availableConstraint = AvailableConstraint::RESET; + } + + } + void makeCts_3MoreCircle(bool& selAllowed, size_t s_cir) + { + //equality. + if (availableConstraint == AvailableConstraint::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraint")); + for (int i = 0; i < s_cir - 1; i++) { + createEqualityConstrain(selCircleArc[i].GeoId, selCircleArc[i + 1].GeoId); + } + selAllowed = true; + availableConstraint = AvailableConstraint::RESET; + } + } + void makeCts_1Circle1Ellipse(bool& selAllowed) + { + //TODO distance between circle and ellipse/arc of... not supported yet. + if (availableConstraint == AvailableConstraint::FIRST) { + //selAllowed = true; + //availableConstraint = AvailableConstraint::RESET; + } + } + + void makeCts_1Ellipse(bool& selAllowed) + { + //One ellipse or arc of ellipse/hyperbola/parabola - no constrain to attribute + selAllowed = true; + } + void makeCts_2MoreEllipse(bool& selAllowed, size_t s_ell) + { + //only ellipse or arc of of same kind, then equality of all radius. + bool allTheSame = 1; + const Part::Geometry* geom = Obj->getGeometry(selEllipseAndCo[0].GeoId); + Base::Type typeOf = geom->getTypeId(); + for (int i = 1; i < s_ell; i++) { + const Part::Geometry* geomi = Obj->getGeometry(selEllipseAndCo[i].GeoId); + if (typeOf != geomi->getTypeId()) { + allTheSame = 0; + } + } + if (allTheSame) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraint")); + for (int i = 1; i < s_ell; i++) { + createEqualityConstrain(selEllipseAndCo[0].GeoId, selEllipseAndCo[i].GeoId); + } + selAllowed = true; + } + } + void createDistanceConstrain(int GeoId1, Sketcher::PointPos PosId1, int GeoId2, Sketcher::PointPos PosId2, Base::Vector2d onSketchPos) { //We make sure that if there's a line, it is GeoId2. if (GeoId1 == GeoId2 || (PosId1 != Sketcher::PointPos::none && PosId2 != Sketcher::PointPos::none)) { From a683f3aca4042b64d6d1d47eede5b4df6cd9a3ac Mon Sep 17 00:00:00 2001 From: Paddle Date: Sun, 27 Aug 2023 09:26:44 +0200 Subject: [PATCH 10/12] Fix crash when user click 'Close' button while Dimension is active. TaskDlgEditSketch didn't purge the handler first as is doing CmdSketcherLeaveSketch. --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 1 - src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 61452d0d4a..a9acd51be9 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -1061,7 +1061,6 @@ public: void deactivated() override { Gui::Command::abortCommand(); - //TODO: When user exit sketch edit while tool is activated solve() crashes. solve is needed to refresh the sketch after abortCommand Obj->solve(); sketchgui->draw(false, false); // Redraw } diff --git a/src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp b/src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp index 0912c4b54b..02a530d51f 100644 --- a/src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp +++ b/src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp @@ -100,6 +100,10 @@ bool TaskDlgEditSketch::reject() hGrp->SetBool("ExpandedConstraintsWidget", Constraints->isGroupVisible()); hGrp->SetBool("ExpandedElementsWidget", Elements->isGroupVisible()); + if (sketchView && sketchView->getSketchMode() != ViewProviderSketch::STATUS_NONE) { + sketchView->purgeHandler(); + } + std::string document = getDocumentName();// needed because resetEdit() deletes this instance Gui::Command::doCommand( Gui::Command::Gui, "Gui.getDocument('%s').resetEdit()", document.c_str()); From d5bdebfe1067dc19b89a244214c78d8365282a63 Mon Sep 17 00:00:00 2001 From: Paddle Date: Sun, 27 Aug 2023 18:48:00 +0200 Subject: [PATCH 11/12] Dimension: Fix 2 circles concentric and length mode. --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index a9acd51be9..d38b3f6ac4 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -1582,11 +1582,13 @@ protected: } if (availableConstraint == AvailableConstraint::SECOND) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add concentric and length constraint")); - createDistanceConstrain(selCircleArc[0].GeoId, selCircleArc[0].PosId, selCircleArc[1].GeoId, selCircleArc[1].PosId, onSketchPos); bool created = createCoincidenceConstrain(selCircleArc[0].GeoId, Sketcher::PointPos::mid, selCircleArc[1].GeoId, Sketcher::PointPos::mid); if (!created) { //Already concentric, so skip to next availableConstraint = AvailableConstraint::THIRD; } + else { + createDistanceConstrain(selCircleArc[0].GeoId, selCircleArc[0].PosId, selCircleArc[1].GeoId, selCircleArc[1].PosId, onSketchPos); + } } if (availableConstraint == AvailableConstraint::THIRD) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Equality constraint")); From e21b6cf86060500d5adbf68cfa445e30350213ca Mon Sep 17 00:00:00 2001 From: Paddle Date: Sun, 27 Aug 2023 18:48:33 +0200 Subject: [PATCH 12/12] Implement GeomSelectionSizes to further refactor Dimension::makeAppropriateConstraint --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 96 ++++++++++++++------- 1 file changed, 67 insertions(+), 29 deletions(-) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index d38b3f6ac4..fe7d5c0111 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -993,6 +993,47 @@ void CmdSketcherConstraint::activated(int /*iMsg*/) // Dimension tool ======================================================= +class GeomSelectionSizes +{ +public: + GeomSelectionSizes(size_t s_pts, size_t s_lns, size_t s_cir, size_t s_ell) : + s_pts(s_pts), s_lns(s_lns), s_cir(s_cir), s_ell(s_ell) {} + ~GeomSelectionSizes() {} + + + bool hasPoints() const { return s_pts > 0; } + bool hasLines() const { return s_lns > 0; } + bool hasCirclesOrArcs() const { return s_cir > 0; } + bool hasEllipseAndCo() const { return s_ell > 0; } + + bool has1Point() const { return s_pts == 1 && s_lns == 0 && s_cir == 0 && s_ell == 0; } + bool has2Points() const { return s_pts == 2 && s_lns == 0 && s_cir == 0 && s_ell == 0; } + bool has1Point1Line() const { return s_pts == 1 && s_lns == 1 && s_cir == 0 && s_ell == 0; } + bool has3Points() const { return s_pts == 3 && s_lns == 0 && s_cir == 0 && s_ell == 0; } + bool has4MorePoints() const { return s_pts >= 4 && s_lns == 0 && s_cir == 0 && s_ell == 0; } + bool has2Points1Line() const { return s_pts == 2 && s_lns == 1 && s_cir == 0 && s_ell == 0; } + bool has3MorePoints1Line() const { return s_pts >= 3 && s_lns == 1 && s_cir == 0 && s_ell == 0; } + bool has1MorePoint1Circle() const { return s_pts >= 1 && s_lns == 0 && s_cir == 1 && s_ell == 0; } + bool has1MorePoint1Ellipse() const { return s_pts >= 1 && s_lns == 0 && s_cir == 0 && s_ell == 1; } + + bool has1Line() const { return s_pts == 0 && s_lns == 1 && s_cir == 0 && s_ell == 0; } + bool has2Lines() const { return s_pts == 0 && s_lns == 2 && s_cir == 0 && s_ell == 0; } + bool has3MoreLines() const { return s_pts == 0 && s_lns >= 3 && s_cir == 0 && s_ell == 0; } + bool has1Line1Circle() const { return s_pts == 0 && s_lns == 1 && s_cir == 1 && s_ell == 0; } + bool has1Line2Circles() const { return s_pts == 0 && s_lns == 1 && s_cir == 2 && s_ell == 0; } + bool has1Line1Ellipse() const { return s_pts == 0 && s_lns == 1 && s_cir == 0 && s_ell == 1; } + + bool has1Circle() const { return s_pts == 0 && s_lns == 0 && s_cir == 1 && s_ell == 0; } + bool has2Circles() const { return s_pts == 0 && s_lns == 0 && s_cir == 2 && s_ell == 0; } + bool has3MoreCircles() const { return s_pts == 0 && s_lns == 0 && s_cir >= 3 && s_ell == 0; } + bool has1Circle1Ellipse() const { return s_pts == 0 && s_lns == 0 && s_cir == 1 && s_ell == 1; } + + bool has1Ellipse() const { return s_pts == 0 && s_lns == 0 && s_cir == 0 && s_ell == 1; } + bool has2MoreEllipses() const { return s_pts == 0 && s_lns == 0 && s_cir == 0 && s_ell >= 2; } + + size_t s_pts, s_lns, s_cir, s_ell; +}; + class DrawSketchHandlerDimension : public DrawSketchHandler { public: @@ -1298,39 +1339,36 @@ protected: bool makeAppropriateConstraint(Base::Vector2d onSketchPos) { bool selAllowed = false; - size_t s_pts = selPoints.size(); - size_t s_lns = selLine.size(); - size_t s_cir = selCircleArc.size(); - size_t s_ell = selEllipseAndCo.size(); + GeomSelectionSizes selection(selPoints.size(), selLine.size(), selCircleArc.size(), selEllipseAndCo.size()); - if (s_pts > 0) { - if (s_pts == 1 && s_lns == 0 && s_cir == 0 && s_ell == 0) { makeCts_1Point(selAllowed, onSketchPos); } - else if (s_pts == 2 && s_lns == 0 && s_cir == 0 && s_ell == 0) { makeCts_2Point(selAllowed, onSketchPos); } - else if (s_pts == 1 && s_lns == 1 && s_cir == 0 && s_ell == 0) { makeCts_1Point1Line(selAllowed, onSketchPos); } - else if (s_pts == 3 && s_lns == 0 && s_cir == 0 && s_ell == 0) { makeCts_3Point(selAllowed, s_pts); } - else if (s_pts >= 4 && s_lns == 0 && s_cir == 0 && s_ell == 0) { makeCts_4MorePoint(selAllowed, s_pts); } - else if (s_pts == 2 && s_lns == 1 && s_cir == 0 && s_ell == 0) { makeCts_2Point1Line(selAllowed, onSketchPos, s_pts); } - else if (s_pts >= 3 && s_lns == 1 && s_cir == 0 && s_ell == 0) { makeCts_3MorePoint1Line(selAllowed, onSketchPos, s_pts); } - else if (s_pts >= 1 && s_lns == 0 && s_cir == 1 && s_ell == 0) { makeCts_1MorePoint1Circle(selAllowed); } - else if (s_pts >= 1 && s_lns == 0 && s_cir == 0 && s_ell == 1) { makeCts_1MorePoint1Ellipse(selAllowed); } + if (selection.hasPoints()) { + if (selection.has1Point()) { makeCts_1Point(selAllowed, onSketchPos); } + else if (selection.has2Points()) { makeCts_2Point(selAllowed, onSketchPos); } + else if (selection.has1Point1Line()) { makeCts_1Point1Line(selAllowed, onSketchPos); } + else if (selection.has3Points()) { makeCts_3Point(selAllowed, selection.s_pts); } + else if (selection.has4MorePoints()) { makeCts_4MorePoint(selAllowed, selection.s_pts); } + else if (selection.has2Points1Line()) { makeCts_2Point1Line(selAllowed, onSketchPos, selection.s_pts); } + else if (selection.has3MorePoints1Line()) { makeCts_3MorePoint1Line(selAllowed, onSketchPos, selection.s_pts); } + else if (selection.has1MorePoint1Circle()) { makeCts_1MorePoint1Circle(selAllowed); } + else if (selection.has1MorePoint1Ellipse()) { makeCts_1MorePoint1Ellipse(selAllowed); } } - else if (s_lns > 0) { //s_pts is necessarily 0 - if (s_lns == 1 && s_cir == 0 && s_ell == 0) { makeCts_1Line(selAllowed, onSketchPos); } - else if (s_lns == 2 && s_cir == 0 && s_ell == 0) { makeCts_2Line(selAllowed, onSketchPos); } - else if (s_lns >= 3 && s_cir == 0 && s_ell == 0) { makeCts_3MoreLine(selAllowed, s_lns); } - else if (s_lns == 1 && s_cir == 1 && s_ell == 0) { makeCts_1Line1Circle(selAllowed, onSketchPos); } - else if (s_lns == 1 && s_cir == 2 && s_ell == 0) { makeCts_1Line2Circle(selAllowed); } - else if (s_lns == 1 && s_cir == 0 && s_ell == 1) { makeCts_1Line1Ellipse(selAllowed); } + else if (selection.hasLines()) { + if (selection.has1Line()) { makeCts_1Line(selAllowed, onSketchPos); } + else if (selection.has2Lines()) { makeCts_2Line(selAllowed, onSketchPos); } + else if (selection.has3MoreLines()) { makeCts_3MoreLine(selAllowed, selection.s_lns); } + else if (selection.has1Line1Circle()) { makeCts_1Line1Circle(selAllowed, onSketchPos); } + else if (selection.has1Line2Circles()) { makeCts_1Line2Circle(selAllowed); } + else if (selection.has1Line1Ellipse()) { makeCts_1Line1Ellipse(selAllowed); } } - else if (s_cir > 0) { //s_pts & s_lns are necessarily 0 - if (s_cir == 1 && s_ell == 0) { makeCts_1Circle(selAllowed, onSketchPos); } - else if (s_cir == 2 && s_ell == 0) { makeCts_2Circle(selAllowed, onSketchPos); } - else if (s_cir >= 3 && s_ell == 0) { makeCts_3MoreCircle(selAllowed, s_cir); } - else if (s_cir == 1 && s_ell == 1) { makeCts_1Circle1Ellipse(selAllowed); } + else if (selection.hasCirclesOrArcs()) { + if (selection.has1Circle()) { makeCts_1Circle(selAllowed, onSketchPos); } + else if (selection.has2Circles()) { makeCts_2Circle(selAllowed, onSketchPos); } + else if (selection.has3MoreCircles()) { makeCts_3MoreCircle(selAllowed, selection.s_cir); } + else if (selection.has1Circle1Ellipse()) { makeCts_1Circle1Ellipse(selAllowed); } } - else if (s_ell > 0) { //s_pts & s_lns & s_cir are necessarily 0 - if (s_ell == 1) { makeCts_1Ellipse(selAllowed); } - else if (s_ell >= 2) { makeCts_2MoreEllipse(selAllowed, s_ell); } + else if (selection.hasEllipseAndCo()) { + if (selection.has1Ellipse()) { makeCts_1Ellipse(selAllowed); } + else if (selection.has2MoreEllipses()) { makeCts_2MoreEllipse(selAllowed, selection.s_ell); } } return selAllowed; }