From 74e8990044b3464a61a4be89b82c53d0cf2bf80f Mon Sep 17 00:00:00 2001 From: Paddle Date: Tue, 17 Oct 2023 19:02:15 +0200 Subject: [PATCH] Sketcher: Rectangle DSH --- src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 24 +- .../Sketcher/Gui/DrawSketchHandlerRectangle.h | 3116 +++++++++++++---- src/Mod/Sketcher/Gui/Resources/Sketcher.qrc | 12 + .../icons/geometry/Sketcher_CreateFrame.svg | 233 ++ .../geometry/Sketcher_CreateFrame_Constr.svg | 223 ++ .../Sketcher_CreateRectangle3Points.svg | 221 ++ ...Sketcher_CreateRectangle3Points_Center.svg | 221 ++ ...r_CreateRectangle3Points_Center_Constr.svg | 215 ++ ...Sketcher_CreateRectangle3Points_Constr.svg | 215 ++ .../Sketcher_Pointer_Create_Box_Center.svg | 52 + .../Sketcher_Pointer_Create_Frame.svg | 63 + .../Sketcher_Pointer_Create_Frame_Center.svg | 60 + .../Sketcher_Pointer_Oblong_Center.svg | 48 + .../Sketcher_Pointer_Oblong_Frame.svg | 51 + .../Sketcher_Pointer_Oblong_Frame_Center.svg | 58 + 15 files changed, 4129 insertions(+), 683 deletions(-) create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateFrame.svg create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateFrame_Constr.svg create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateRectangle3Points.svg create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateRectangle3Points_Center.svg create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateRectangle3Points_Center_Constr.svg create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateRectangle3Points_Constr.svg create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Create_Box_Center.svg create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Create_Frame.svg create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Create_Frame_Center.svg create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Oblong_Center.svg create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Oblong_Frame.svg create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Oblong_Frame_Center.svg diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index 2f5643f144..13451ded84 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -153,8 +153,9 @@ CONSTRUCTION_UPDATE_ACTION(CmdSketcherCreateRectangle, "Sketcher_CreateRectangle void CmdSketcherCreateRectangle::activated(int iMsg) { Q_UNUSED(iMsg); - ActivateHandler(getActiveGuiDocument(), - new DrawSketchHandlerBox(DrawSketchHandlerBox::Diagonal)); + ActivateHandler( + getActiveGuiDocument(), + new DrawSketchHandlerRectangle(ConstructionMethods::RectangleConstructionMethod::Diagonal)); } bool CmdSketcherCreateRectangle::isActive() @@ -184,7 +185,8 @@ void CmdSketcherCreateRectangleCenter::activated(int iMsg) { Q_UNUSED(iMsg); ActivateHandler(getActiveGuiDocument(), - new DrawSketchHandlerBox(DrawSketchHandlerBox::CenterAndCorner)); + new DrawSketchHandlerRectangle( + ConstructionMethods::RectangleConstructionMethod::CenterAndCorner)); } bool CmdSketcherCreateRectangleCenter::isActive() @@ -216,7 +218,10 @@ CONSTRUCTION_UPDATE_ACTION(CmdSketcherCreateOblong, "Sketcher_CreateOblong") void CmdSketcherCreateOblong::activated(int iMsg) { Q_UNUSED(iMsg); - ActivateHandler(getActiveGuiDocument(), new DrawSketchHandlerOblong()); + ActivateHandler( + getActiveGuiDocument(), + new DrawSketchHandlerRectangle(ConstructionMethods::RectangleConstructionMethod::Diagonal, + true)); } bool CmdSketcherCreateOblong::isActive() @@ -244,14 +249,19 @@ void CmdSketcherCompCreateRectangles::activated(int iMsg) { if (iMsg == 0) { ActivateHandler(getActiveGuiDocument(), - new DrawSketchHandlerBox(DrawSketchHandlerBox::Diagonal)); + new DrawSketchHandlerRectangle( + ConstructionMethods::RectangleConstructionMethod::Diagonal)); } else if (iMsg == 1) { ActivateHandler(getActiveGuiDocument(), - new DrawSketchHandlerBox(DrawSketchHandlerBox::CenterAndCorner)); + new DrawSketchHandlerRectangle( + ConstructionMethods::RectangleConstructionMethod::CenterAndCorner)); } else if (iMsg == 2) { - ActivateHandler(getActiveGuiDocument(), new DrawSketchHandlerOblong()); + ActivateHandler(getActiveGuiDocument(), + new DrawSketchHandlerRectangle( + ConstructionMethods::RectangleConstructionMethod::Diagonal, + true)); } else { return; diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerRectangle.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerRectangle.h index a335f2fcfc..b793ec6a37 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerRectangle.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerRectangle.h @@ -20,737 +20,2501 @@ * * ***************************************************************************/ + #ifndef SKETCHERGUI_DrawSketchHandlerRectangle_H #define SKETCHERGUI_DrawSketchHandlerRectangle_H -#include + +#include "DrawSketchDefaultWidgetController.h" +#include "DrawSketchControllableHandler.h" #include "GeometryCreationMode.h" - +#include "Utils.h" namespace SketcherGui { extern GeometryCreationMode geometryCreationMode; // defined in CommandCreateGeo.cpp -class DrawSketchHandlerBox: public DrawSketchHandler +class DrawSketchHandlerRectangle; + +namespace ConstructionMethods { -public: - enum ConstructionMethod - { - Diagonal, - CenterAndCorner - }; - explicit DrawSketchHandlerBox(ConstructionMethod constrMethod = Diagonal) - : Mode(STATUS_SEEK_First) - , EditCurve(5) - , constructionMethod(constrMethod) - {} - ~DrawSketchHandlerBox() override - {} - - /// mode table - enum BoxMode - { - STATUS_SEEK_First, /**< enum value ----. */ - STATUS_SEEK_Second, /**< enum value ----. */ - STATUS_End - }; - -public: - void mouseMove(Base::Vector2d onSketchPos) override - { - - if (Mode == STATUS_SEEK_First) { - setPositionText(onSketchPos); - if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2d(0.f, 0.f))) { - renderSuggestConstraintsCursor(sugConstr1); - return; - } - } - else if (Mode == STATUS_SEEK_Second) { - if (constructionMethod == Diagonal) { - float dx = onSketchPos.x - EditCurve[0].x; - float dy = onSketchPos.y - EditCurve[0].y; - if (showCursorCoords()) { - SbString text; - std::string dxString = lengthToDisplayFormat(dx, 1); - std::string dyString = lengthToDisplayFormat(dy, 1); - text.sprintf(" (%s x %s)", dxString.c_str(), dyString.c_str()); - setPositionText(onSketchPos, text); - } - - EditCurve[2] = onSketchPos; - EditCurve[1] = Base::Vector2d(onSketchPos.x, EditCurve[0].y); - EditCurve[3] = Base::Vector2d(EditCurve[0].x, onSketchPos.y); - } - else if (constructionMethod == CenterAndCorner) { - float dx = onSketchPos.x - center.x; - float dy = onSketchPos.y - center.y; - if (showCursorCoords()) { - SbString text; - std::string dxString = lengthToDisplayFormat(dx, 1); - std::string dyString = lengthToDisplayFormat(dy, 1); - text.sprintf(" (%s x %s)", dxString.c_str(), dyString.c_str()); - setPositionText(onSketchPos, text); - } - - EditCurve[0] = center - (onSketchPos - center); - EditCurve[1] = Base::Vector2d(EditCurve[0].x, onSketchPos.y); - EditCurve[2] = onSketchPos; - EditCurve[3] = Base::Vector2d(onSketchPos.x, EditCurve[0].y); - EditCurve[4] = EditCurve[0]; - } - - drawEdit(EditCurve); - if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2d(0.0, 0.0))) { - renderSuggestConstraintsCursor(sugConstr2); - return; - } - } - applyCursor(); - } - - bool pressButton(Base::Vector2d onSketchPos) override - { - if (Mode == STATUS_SEEK_First) { - if (constructionMethod == Diagonal) { - EditCurve[0] = onSketchPos; - EditCurve[4] = onSketchPos; - } - else if (constructionMethod == CenterAndCorner) { - center = onSketchPos; - } - - Mode = STATUS_SEEK_Second; - } - else { - if (constructionMethod == Diagonal) { - EditCurve[2] = onSketchPos; - EditCurve[1] = Base::Vector2d(onSketchPos.x, EditCurve[0].y); - EditCurve[3] = Base::Vector2d(EditCurve[0].x, onSketchPos.y); - drawEdit(EditCurve); - Mode = STATUS_End; - } - else if (constructionMethod == CenterAndCorner) { - EditCurve[0] = center - (onSketchPos - center); - EditCurve[1] = Base::Vector2d(EditCurve[0].x, onSketchPos.y); - EditCurve[2] = onSketchPos; - EditCurve[3] = Base::Vector2d(onSketchPos.x, EditCurve[0].y); - EditCurve[4] = EditCurve[0]; - drawEdit(EditCurve); - Mode = STATUS_End; - } - } - return true; - } - - bool releaseButton(Base::Vector2d onSketchPos) override - { - Q_UNUSED(onSketchPos); - if (Mode == STATUS_End) { - unsetCursor(); - resetPositionText(); - int firstCurve = getHighestCurveIndex() + 1; - - try { - if (constructionMethod == Diagonal) { - Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add sketch box")); - Gui::Command::doCommand( - Gui::Command::Doc, - "geoList = []\n" - "geoList.append(Part.LineSegment(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))" - "\n" - "geoList.append(Part.LineSegment(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))" - "\n" - "geoList.append(Part.LineSegment(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))" - "\n" - "geoList.append(Part.LineSegment(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))" - "\n" - "%s.addGeometry(geoList,%s)\n" - "conList = []\n" - "conList.append(Sketcher.Constraint('Coincident',%i,2,%i,1))\n" - "conList.append(Sketcher.Constraint('Coincident',%i,2,%i,1))\n" - "conList.append(Sketcher.Constraint('Coincident',%i,2,%i,1))\n" - "conList.append(Sketcher.Constraint('Coincident',%i,2,%i,1))\n" - "conList.append(Sketcher.Constraint('Horizontal',%i))\n" - "conList.append(Sketcher.Constraint('Horizontal',%i))\n" - "conList.append(Sketcher.Constraint('Vertical',%i))\n" - "conList.append(Sketcher.Constraint('Vertical',%i))\n" - "%s.addConstraint(conList)\n" - "del geoList, conList\n", - EditCurve[0].x, - EditCurve[0].y, - EditCurve[1].x, - EditCurve[1].y, // line 1 - EditCurve[1].x, - EditCurve[1].y, - EditCurve[2].x, - EditCurve[2].y, // line 2 - EditCurve[2].x, - EditCurve[2].y, - EditCurve[3].x, - EditCurve[3].y, // line 3 - EditCurve[3].x, - EditCurve[3].y, - EditCurve[0].x, - EditCurve[0].y, // line 4 - Gui::Command::getObjectCmd(sketchgui->getObject()).c_str(), // the sketch - geometryCreationMode == Construction - ? "True" - : "False", // geometry as construction or not - firstCurve, - firstCurve + 1, // coincident1 - firstCurve + 1, - firstCurve + 2, // coincident2 - firstCurve + 2, - firstCurve + 3, // coincident3 - firstCurve + 3, - firstCurve, // coincident4 - firstCurve, // horizontal1 - firstCurve + 2, // horizontal2 - firstCurve + 1, // vertical1 - firstCurve + 3, // vertical2 - Gui::Command::getObjectCmd(sketchgui->getObject()).c_str()); // the sketch - - Gui::Command::commitCommand(); - } - else if (constructionMethod == CenterAndCorner) { - Gui::Command::openCommand( - QT_TRANSLATE_NOOP("Command", "Add centered sketch box")); - Gui::Command::doCommand( - Gui::Command::Doc, - "geoList = []\n" - "geoList.append(Part.LineSegment(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))" - "\n" - "geoList.append(Part.LineSegment(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))" - "\n" - "geoList.append(Part.LineSegment(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))" - "\n" - "geoList.append(Part.LineSegment(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))" - "\n" - "geoList.append(Part.Point(App.Vector(%f,%f,0)))\n" - "%s.addGeometry(geoList,%s)\n" - "conList = []\n" - "conList.append(Sketcher.Constraint('Coincident',%i,2,%i,1))\n" - "conList.append(Sketcher.Constraint('Coincident',%i,2,%i,1))\n" - "conList.append(Sketcher.Constraint('Coincident',%i,2,%i,1))\n" - "conList.append(Sketcher.Constraint('Coincident',%i,2,%i,1))\n" - "conList.append(Sketcher.Constraint('Horizontal',%i))\n" - "conList.append(Sketcher.Constraint('Horizontal',%i))\n" - "conList.append(Sketcher.Constraint('Vertical',%i))\n" - "conList.append(Sketcher.Constraint('Vertical',%i))\n" - "conList.append(Sketcher.Constraint('Symmetric',%i,2,%i,1,%i,1))\n" - "%s.addConstraint(conList)\n" - "del geoList, conList\n", - EditCurve[0].x, - EditCurve[0].y, - EditCurve[1].x, - EditCurve[1].y, // line 1 - EditCurve[1].x, - EditCurve[1].y, - EditCurve[2].x, - EditCurve[2].y, // line 2 - EditCurve[2].x, - EditCurve[2].y, - EditCurve[3].x, - EditCurve[3].y, // line 3 - EditCurve[3].x, - EditCurve[3].y, - EditCurve[0].x, - EditCurve[0].y, // line 4 - center.x, - center.y, // center point - Gui::Command::getObjectCmd(sketchgui->getObject()).c_str(), // the sketch - geometryCreationMode == Construction - ? "True" - : "False", // geometry as construction or not - firstCurve, - firstCurve + 1, // coincident1 - firstCurve + 1, - firstCurve + 2, // coincident2 - firstCurve + 2, - firstCurve + 3, // coincident3 - firstCurve + 3, - firstCurve, // coincident4 - firstCurve + 1, // horizontal1 - firstCurve + 3, // horizontal2 - firstCurve, // vertical1 - firstCurve + 2, // vertical2 - firstCurve + 1, - firstCurve, - firstCurve + 4, // Symmetric - Gui::Command::getObjectCmd(sketchgui->getObject()).c_str()); // the sketch - - Gui::Command::commitCommand(); - } - } - catch (const Base::Exception&) { - Gui::NotifyError(sketchgui, - QT_TRANSLATE_NOOP("Notifications", "Error"), - QT_TRANSLATE_NOOP("Notifications", "Failed to add box")); - - Gui::Command::abortCommand(); - } - - if (constructionMethod == Diagonal) { - // add auto constraints at the start of the first side - if (!sugConstr1.empty()) { - createAutoConstraints(sugConstr1, - getHighestCurveIndex() - 3, - Sketcher::PointPos::start); - sugConstr1.clear(); - } - - // add auto constraints at the end of the second side - if (!sugConstr2.empty()) { - createAutoConstraints(sugConstr2, - getHighestCurveIndex() - 2, - Sketcher::PointPos::end); - sugConstr2.clear(); - } - } - else if (constructionMethod == CenterAndCorner) { - // add auto constraints at the start of the first side - if (!sugConstr1.empty()) { - createAutoConstraints(sugConstr1, - getHighestCurveIndex(), - Sketcher::PointPos::start); - sugConstr1.clear(); - } - - // add auto constraints at the end of the second side - if (!sugConstr2.empty()) { - createAutoConstraints(sugConstr2, - getHighestCurveIndex() - 3, - Sketcher::PointPos::end); - sugConstr2.clear(); - } - } - - tryAutoRecomputeIfNotSolve( - static_cast(sketchgui->getObject())); - - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( - "User parameter:BaseApp/Preferences/Mod/Sketcher"); - bool continuousMode = hGrp->GetBool("ContinuousCreationMode", true); - if (continuousMode) { - // This code enables the continuous creation mode. - Mode = STATUS_SEEK_First; - EditCurve.clear(); - drawEdit(EditCurve); - EditCurve.resize(5); - applyCursor(); - /* this is ok not to call to purgeHandler - * in continuous creation mode because the - * handler is destroyed by the quit() method on pressing the - * right button of the mouse */ - } - else { - sketchgui->purgeHandler(); // no code after this line, Handler get deleted in - // ViewProvider - } - } - return true; - } - -private: - QString getCrosshairCursorSVGName() const override - { - return QString::fromLatin1("Sketcher_Pointer_Create_Box"); - } - -protected: - BoxMode Mode; - std::vector EditCurve; - std::vector sugConstr1, sugConstr2; - ConstructionMethod constructionMethod; - Base::Vector2d center; +enum class RectangleConstructionMethod +{ + Diagonal, + CenterAndCorner, + ThreePoints, + CenterAnd3Points, + End // Must be the last one }; -class DrawSketchHandlerOblong: public DrawSketchHandler +} + +using DSHRectangleController = + DrawSketchDefaultWidgetController, + /*WidgetParametersT =*/WidgetParameters<0, 0, 0, 0>, + /*WidgetCheckboxesT =*/WidgetCheckboxes<2, 2, 2, 2>, + /*WidgetComboboxesT =*/WidgetComboboxes<1, 1, 1, 1>, + ConstructionMethods::RectangleConstructionMethod, + /*bool PFirstComboboxIsConstructionMethod =*/true>; + +using DSHRectangleControllerBase = DSHRectangleController::ControllerBase; + +using DrawSketchHandlerRectangleBase = DrawSketchControllableHandler; + + +class DrawSketchHandlerRectangle: public DrawSketchHandlerRectangleBase { + // Allow specialisations of controllers access to private members + friend DSHRectangleController; + friend DSHRectangleControllerBase; + public: - DrawSketchHandlerOblong() - : Mode(STATUS_SEEK_First) - , lengthX(0) - , lengthY(0) - , radius(0) - , signX(1) - , signY(1) - , EditCurve(37) + DrawSketchHandlerRectangle(ConstructionMethod constrMethod = ConstructionMethod::Diagonal, + bool roundcorners = false, + bool frame = false) + : DrawSketchHandlerRectangleBase(constrMethod) + , roundCorners(roundcorners) + , makeFrame(frame) + , cornersReversed(false) + , thickness(0.) {} - ~DrawSketchHandlerOblong() override - {} - /// mode table - enum BoxMode + + ~DrawSketchHandlerRectangle() override = default; + +private: + void updateDataAndDrawToPosition(Base::Vector2d onSketchPos) override { - STATUS_SEEK_First, /**< enum value ----. */ - STATUS_SEEK_Second, /**< enum value ----. */ - STATUS_End - }; + switch (state()) { + case SelectMode::SeekFirst: { + drawPositionAtCursor(onSketchPos); - void mouseMove(Base::Vector2d onSketchPos) override - { + if (constructionMethod() == ConstructionMethod::Diagonal + || constructionMethod() == ConstructionMethod::ThreePoints) { + corner1 = onSketchPos; + } + else { //(constructionMethod == ConstructionMethod::CenterAndCorner) + center = onSketchPos; + } - if (Mode == STATUS_SEEK_First) { - setPositionText(onSketchPos); - if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2d(0.f, 0.f))) { - renderSuggestConstraintsCursor(sugConstr1); - return; - } - } - else if (Mode == STATUS_SEEK_Second) { - float distanceX = onSketchPos.x - StartPos.x; - float distanceY = onSketchPos.y - StartPos.y; + if (seekAutoConstraint(sugConstraints[0], onSketchPos, Base::Vector2d(0.f, 0.f))) { + renderSuggestConstraintsCursor(sugConstraints[0]); + return; + } + } break; + case SelectMode::SeekSecond: { + if (constructionMethod() == ConstructionMethod::Diagonal) { + drawDirectionAtCursor(onSketchPos, corner1); - lengthX = distanceX; - lengthY = distanceY; - signX = Base::sgn(distanceX); - signY = Base::sgn(distanceY); - if (fabs(distanceX) > fabs(distanceY)) { - radius = fabs(distanceY) - / 4; // we use a fourth of the smaller distance as default radius - } - else { - radius = fabs(distanceX) / 4; - } + // Note : we swap corner2 and 4 to make sure the corners are CCW. + // making things easier down the line. + corner3 = onSketchPos; + if ((corner3.x - corner1.x) * (corner3.y - corner1.y) > 0) { + corner2 = Base::Vector2d(onSketchPos.x, corner1.y); + corner4 = Base::Vector2d(corner1.x, onSketchPos.y); + cornersReversed = false; + } + else { + corner4 = Base::Vector2d(onSketchPos.x, corner1.y); + corner2 = Base::Vector2d(corner1.x, onSketchPos.y); + cornersReversed = true; + } + angle123 = M_PI / 2; + angle412 = M_PI / 2; + } + else if (constructionMethod() == ConstructionMethod::CenterAndCorner) { + drawDirectionAtCursor(onSketchPos, center); - // we draw the lines with 36 segments, 8 for each arc and 4 lines - // draw the arcs - for (int i = 0; i < 8; i++) { - // calculate the x,y positions forming the arc - double angle = i * M_PI / 16.0; - double x_i = -radius * sin(angle); - double y_i = -radius * cos(angle); - // we are drawing clockwise starting with the arc that is besides StartPos - if (signX == signY) { - EditCurve[i] = Base::Vector2d(StartPos.x + signX * (radius + x_i), - StartPos.y + signY * (radius + y_i)); - EditCurve[9 + i] = - Base::Vector2d(StartPos.x + signY * (radius + y_i), - StartPos.y + lengthY - signX * (radius + x_i)); - EditCurve[18 + i] = - Base::Vector2d(StartPos.x + lengthX - signX * (radius + x_i), - StartPos.y + lengthY - signY * (radius + y_i)); - EditCurve[27 + i] = - Base::Vector2d(StartPos.x + lengthX - signY * (radius + y_i), - StartPos.y + signX * (radius + x_i)); + corner1 = center - (onSketchPos - center); + corner3 = onSketchPos; + if (Base::sgn(corner3.x - corner1.x) * Base::sgn(corner3.y - corner1.y) > 0) { + corner2 = Base::Vector2d(onSketchPos.x, corner1.y); + corner4 = Base::Vector2d(corner1.x, onSketchPos.y); + cornersReversed = false; + } + else { + corner4 = Base::Vector2d(onSketchPos.x, corner1.y); + corner2 = Base::Vector2d(corner1.x, onSketchPos.y); + cornersReversed = true; + } + angle123 = M_PI / 2; + angle412 = M_PI / 2; + } + else if (constructionMethod() == ConstructionMethod::ThreePoints) { + drawDirectionAtCursor(onSketchPos, corner1); + + corner2 = onSketchPos; + Base::Vector2d perpendicular; + perpendicular.x = -(corner2 - corner1).y; + perpendicular.y = (corner2 - corner1).x; + corner3 = corner2 + perpendicular; + corner4 = corner1 + perpendicular; + angle123 = M_PI / 2; + angle412 = M_PI / 2; + corner2Initial = corner2; + side = getPointSideOfVector(corner3, corner2 - corner1, corner1); } else { - EditCurve[i] = Base::Vector2d(StartPos.x - signY * (radius + y_i), - StartPos.y - signX * (radius + x_i)); - EditCurve[9 + i] = Base::Vector2d(StartPos.x + lengthX - signX * (radius + x_i), - StartPos.y + signY * (radius + y_i)); - EditCurve[18 + i] = - Base::Vector2d(StartPos.x + lengthX + signY * (radius + y_i), - StartPos.y + lengthY + signX * (radius + x_i)); - EditCurve[27 + i] = - Base::Vector2d(StartPos.x + signX * (radius + x_i), - StartPos.y + lengthY - signY * (radius + y_i)); + drawDirectionAtCursor(onSketchPos, center); + + corner1 = onSketchPos; + corner3 = center - (onSketchPos - center); + Base::Vector2d perpendicular; + perpendicular.x = -(onSketchPos - center).y; + perpendicular.y = (onSketchPos - center).x; + corner2 = center + perpendicular; + corner4 = center - perpendicular; + angle123 = M_PI / 2; + angle412 = M_PI / 2; + side = getPointSideOfVector(corner2, corner3 - corner1, corner1); } - } - // draw the lines - if (signX == signY) { - EditCurve[8] = Base::Vector2d(StartPos.x, StartPos.y + (signY * radius)); - EditCurve[17] = Base::Vector2d(StartPos.x + (signX * radius), StartPos.y + lengthY); - EditCurve[26] = - Base::Vector2d(StartPos.x + lengthX, StartPos.y + lengthY - (signY * radius)); - EditCurve[35] = Base::Vector2d(StartPos.x + lengthX - (signX * radius), StartPos.y); - } - else { - EditCurve[8] = Base::Vector2d(StartPos.x + (signX * radius), StartPos.y); - EditCurve[17] = Base::Vector2d(StartPos.x + lengthX, StartPos.y + (signY * radius)); - EditCurve[26] = - Base::Vector2d(StartPos.x + lengthX - (signX * radius), StartPos.y + lengthY); - EditCurve[35] = Base::Vector2d(StartPos.x, StartPos.y + lengthY - (signY * radius)); - } - // close the curve - EditCurve[36] = EditCurve[0]; - if (showCursorCoords()) { - SbString text; - std::string radiusString = lengthToDisplayFormat(radius, 1); - std::string xString = lengthToDisplayFormat(lengthX, 1); - std::string yString = lengthToDisplayFormat(lengthY, 1); - text.sprintf(" (R%s X%s Y%s)", - radiusString.c_str(), - xString.c_str(), - yString.c_str()); - setPositionText(onSketchPos, text); - } + if (roundCorners) { + length = (corner2 - corner1).Length(); + width = (corner4 - corner1).Length(); + radius = std::min(length, width) / 6; + } + else { + radius = 0.; + } - drawEdit(EditCurve); - if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2d(0.f, 0.f))) { - renderSuggestConstraintsCursor(sugConstr2); - return; - } + try { + CreateAndDrawShapeGeometry(); + } + catch (const Base::ValueError&) { + } // equal points while hovering raise an objection that can be safely ignored + + if (seekAutoConstraint(sugConstraints[1], onSketchPos, Base::Vector2d(0.0, 0.0))) { + renderSuggestConstraintsCursor(sugConstraints[1]); + return; + } + } break; + case SelectMode::SeekThird: { + if (constructionMethod() == ConstructionMethod::Diagonal + || constructionMethod() == ConstructionMethod::CenterAndCorner) { + if (roundCorners) { + calculateRadius(onSketchPos); + } + else { + calculateThickness( + onSketchPos); // This is the case of frame of normal rectangle. + } + } + else if (constructionMethod() == ConstructionMethod::ThreePoints) { + corner2 = corner2Initial; + corner3 = onSketchPos; + if (side == getPointSideOfVector(corner3, corner2 - corner1, corner1)) { + corner4 = corner1 + (corner3 - corner2); + cornersReversed = false; + } + else { + corner4 = corner2; + corner2 = corner1 + (corner3 - corner4); + cornersReversed = true; + } + Base::Vector2d a = corner1 - corner2; + Base::Vector2d b = corner3 - corner2; + if (fabs((sqrt(a.x * a.x + a.y * a.y) * sqrt(b.x * b.x + b.y * b.y))) + > Precision::Confusion()) { + angle123 = + acos((a.x * b.x + a.y * b.y) + / (sqrt(a.x * a.x + a.y * a.y) * sqrt(b.x * b.x + b.y * b.y))); + } + angle412 = M_PI - angle123; + if (roundCorners) { + radius = std::min(length, width) / 6 + * std::min(sqrt(1 - cos(angle412) * cos(angle412)), + sqrt(1 - cos(angle123) * cos(angle123))); + } + else { + radius = 0.; + } + + SbString text; + text.sprintf(" (%.1f Angle)", angle123 / M_PI * 180); + setPositionText(onSketchPos, text); + } + else { + corner2 = onSketchPos; + corner4 = center - (onSketchPos - center); + cornersReversed = false; + if (side != getPointSideOfVector(corner2, corner3 - corner1, corner1)) { + corner4 = onSketchPos; + corner2 = center - (onSketchPos - center); + cornersReversed = true; + } + Base::Vector2d a = corner4 - corner1; + Base::Vector2d b = corner2 - corner1; + if (fabs((sqrt(a.x * a.x + a.y * a.y) * sqrt(b.x * b.x + b.y * b.y))) + > Precision::Confusion()) { + angle412 = + acos((a.x * b.x + a.y * b.y) + / (sqrt(a.x * a.x + a.y * a.y) * sqrt(b.x * b.x + b.y * b.y))); + } + angle123 = M_PI - angle412; + if (roundCorners) { + radius = std::min(length, width) / 6 + * std::min(sqrt(1 - cos(angle412) * cos(angle412)), + sqrt(1 - cos(angle123) * cos(angle123))); + } + else { + radius = 0.; + } + + SbString text; + text.sprintf(" (%.1f Angle)", angle412 / M_PI * 180); + setPositionText(onSketchPos, text); + } + + try { + CreateAndDrawShapeGeometry(); + } + catch (const Base::ValueError&) { + } // equal points while hovering raise an objection that can be safely ignored + + if ((constructionMethod() == ConstructionMethod::ThreePoints + || constructionMethod() == ConstructionMethod::CenterAnd3Points) + && seekAutoConstraint(sugConstraints[2], + onSketchPos, + Base::Vector2d(0.0, 0.0))) { + renderSuggestConstraintsCursor(sugConstraints[2]); + return; + } + } break; + case SelectMode::SeekFourth: { + if (constructionMethod() == ConstructionMethod::Diagonal + || constructionMethod() == ConstructionMethod::CenterAndCorner) { + calculateThickness( + onSketchPos); // This is the case of frame of round corner rectangle. + } + else { + if (roundCorners) { + calculateRadius(onSketchPos); + } + else { + calculateThickness(onSketchPos); + } + } + + CreateAndDrawShapeGeometry(); + } break; + case SelectMode::SeekFifth: { + calculateThickness(onSketchPos); + + CreateAndDrawShapeGeometry(); + } break; + default: + break; } - applyCursor(); } - bool pressButton(Base::Vector2d onSketchPos) override + void executeCommands() override { - if (Mode == STATUS_SEEK_First) { - StartPos = onSketchPos; - Mode = STATUS_SEEK_Second; + try { + firstCurve = getHighestCurveIndex() + 1; + + createShape(false); + + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add sketch box")); + + commandAddShapeGeometryAndConstraints(); + + Gui::Command::commitCommand(); } + catch (const Base::Exception& e) { + Gui::NotifyError(sketchgui, + QT_TRANSLATE_NOOP("Notifications", "Error"), + QT_TRANSLATE_NOOP("Notifications", "Failed to add box")); + + Gui::Command::abortCommand(); + THROWM(Base::RuntimeError, + QT_TRANSLATE_NOOP( + "Notifications", + "Tool execution aborted") "\n") // This prevents constraints from being + // applied on non existing geometry + } + + thickness = 0.; + } + + void generateAutoConstraints() override + { + + if (constructionMethod() == ConstructionMethod::Diagonal) { + // add auto constraints at the start of the first side + if (radius > Precision::Confusion()) { + if (!sugConstraints[0].empty()) { + generateAutoConstraintsOnElement(sugConstraints[0], + constructionPointOneId, + Sketcher::PointPos::start); + } + + if (!sugConstraints[1].empty()) { + generateAutoConstraintsOnElement(sugConstraints[1], + constructionPointTwoId, + Sketcher::PointPos::start); + } + } + else { + if (!sugConstraints[0].empty()) { + generateAutoConstraintsOnElement(sugConstraints[0], + firstCurve, + Sketcher::PointPos::start); + } + + if (!sugConstraints[1].empty()) { + generateAutoConstraintsOnElement(sugConstraints[1], + firstCurve + 1, + Sketcher::PointPos::end); + } + } + } + else if (constructionMethod() == ConstructionMethod::CenterAndCorner) { + // add auto constraints at center + if (!sugConstraints[0].empty()) { + generateAutoConstraintsOnElement(sugConstraints[0], + centerPointId, + Sketcher::PointPos::start); + } + + // add auto constraints for the line segment end + if (!sugConstraints[1].empty()) { + if (radius > Precision::Confusion()) { + generateAutoConstraintsOnElement(sugConstraints[1], + constructionPointOneId, + Sketcher::PointPos::start); + } + else { + generateAutoConstraintsOnElement(sugConstraints[1], + firstCurve + 1, + Sketcher::PointPos::end); + } + } + } + else if (constructionMethod() == ConstructionMethod::ThreePoints) { + if (radius > Precision::Confusion()) { + if (!sugConstraints[0].empty()) { + generateAutoConstraintsOnElement(sugConstraints[0], + constructionPointOneId, + Sketcher::PointPos::start); + } + + if (!sugConstraints[1].empty()) { + generateAutoConstraintsOnElement(sugConstraints[1], + constructionPointTwoId, + Sketcher::PointPos::start); + } + + if (!sugConstraints[2].empty()) { + generateAutoConstraintsOnElement(sugConstraints[2], + constructionPointThreeId, + Sketcher::PointPos::start); + } + } + else { + if (!sugConstraints[0].empty()) { + generateAutoConstraintsOnElement(sugConstraints[0], + firstCurve, + Sketcher::PointPos::start); + } + + if (!sugConstraints[1].empty()) { + if (!cornersReversed) { + generateAutoConstraintsOnElement(sugConstraints[1], + firstCurve + 1, + Sketcher::PointPos::start); + } + else { + generateAutoConstraintsOnElement(sugConstraints[1], + firstCurve + 3, + Sketcher::PointPos::start); + } + } + + if (!sugConstraints[2].empty()) { + generateAutoConstraintsOnElement(sugConstraints[2], + firstCurve + 2, + Sketcher::PointPos::start); + } + } + } + else if (constructionMethod() == ConstructionMethod::CenterAnd3Points) { + // add auto constraints at center + if (!sugConstraints[0].empty()) { + generateAutoConstraintsOnElement(sugConstraints[0], + centerPointId, + Sketcher::PointPos::start); + } + + // add auto constraints for the line segment end + if (radius > Precision::Confusion()) { + if (!sugConstraints[1].empty()) { + generateAutoConstraintsOnElement(sugConstraints[1], + constructionPointOneId, + Sketcher::PointPos::start); + } + + if (!sugConstraints[2].empty()) { + generateAutoConstraintsOnElement(sugConstraints[2], + constructionPointTwoId, + Sketcher::PointPos::start); + } + } + else { + if (!sugConstraints[1].empty()) { + generateAutoConstraintsOnElement(sugConstraints[1], + firstCurve, + Sketcher::PointPos::start); + } + + if (!sugConstraints[2].empty()) { + if (!cornersReversed) { + generateAutoConstraintsOnElement(sugConstraints[2], + firstCurve + 1, + Sketcher::PointPos::start); + } + else { + generateAutoConstraintsOnElement(sugConstraints[2], + firstCurve + 3, + Sketcher::PointPos::start); + } + } + } + } + + // Ensure temporary autoconstraints do not generate a redundancy and that the geometry + // parameters are accurate This is particularly important for adding widget mandated + // constraints. + removeRedundantAutoConstraints(); + } + + void createAutoConstraints() override + { + createGeneratedAutoConstraints(true); + + sugConstraints[0].clear(); + sugConstraints[1].clear(); + } + + std::string getToolName() const override + { + return "DSH_Rectangle"; + } + + QString getCrosshairCursorSVGName() const override + { + if (!roundCorners && !makeFrame) { + if (constructionMethod() == ConstructionMethod::CenterAndCorner) { + return QString::fromLatin1("Sketcher_Pointer_Create_Box_Center"); + } + else { + return QString::fromLatin1("Sketcher_Pointer_Create_Box"); + } + } + else if (roundCorners && !makeFrame) { + if (constructionMethod() == ConstructionMethod::CenterAndCorner) { + return QString::fromLatin1("Sketcher_Pointer_Oblong_Center"); + } + else { + return QString::fromLatin1("Sketcher_Pointer_Oblong"); + } + } + else if (!roundCorners && makeFrame) { + if (constructionMethod() == ConstructionMethod::CenterAndCorner) { + return QString::fromLatin1("Sketcher_Pointer_Create_Frame_Center"); + } + else { + return QString::fromLatin1("Sketcher_Pointer_Create_Frame"); + } + } + else { // both roundCorners and makeFrame + if (constructionMethod() == ConstructionMethod::CenterAndCorner) { + return QString::fromLatin1("Sketcher_Pointer_Oblong_Frame_Center"); + } + else { + return QString::fromLatin1("Sketcher_Pointer_Oblong_Frame"); + } + } + } + + std::unique_ptr createWidget() const override + { + return std::make_unique(); + } + + bool isWidgetVisible() const override + { + return true; + }; + + QPixmap getToolIcon() const override + { + return Gui::BitmapFactory().pixmap("Sketcher_CreateRectangle"); + } + + QString getToolWidgetText() const override + { + return QString(QObject::tr("Rectangle parameters")); + } + + void angleSnappingControl() override + { + if ((constructionMethod() == ConstructionMethod::ThreePoints) + && state() == SelectMode::SeekSecond) { + setAngleSnapping(true, corner1); + } + else if ((constructionMethod() == ConstructionMethod::CenterAnd3Points) + && state() == SelectMode::SeekSecond) { + setAngleSnapping(true, center); + } + else if ((constructionMethod() == ConstructionMethod::ThreePoints) + && state() == SelectMode::SeekThird) { + setAngleSnapping(true, cornersReversed ? corner4 : corner2); + } + else if ((constructionMethod() == ConstructionMethod::CenterAnd3Points) + && state() == SelectMode::SeekThird) { + setAngleSnapping(true, corner1); + } + else { - EndPos = onSketchPos; - Mode = STATUS_End; + setAngleSnapping(false); } + } + + bool canGoToNextMode() override + { + if (state() == SelectMode::SeekSecond + && (length < Precision::Confusion() || width < Precision::Confusion())) { + return false; + } + return true; } - bool releaseButton(Base::Vector2d onSketchPos) override + // reimplement because if not radius then it's 2 steps + void onButtonPressed(Base::Vector2d onSketchPos) override { - Q_UNUSED(onSketchPos); - if (Mode == STATUS_End) { - unsetCursor(); - resetPositionText(); + this->updateDataAndDrawToPosition(onSketchPos); - int firstCurve = getHighestCurveIndex() + 1; - // add the geometry to the sketch - // first determine the angles for the first arc - double start = 0; - double end = M_PI / 2; - if (signX > 0 && signY > 0) { - start = -2 * end; - end = -1 * end; - } - else if (signX > 0 && signY < 0) { - start = end; - end = 2 * end; - } - else if (signX < 0 && signY > 0) { - start = -1 * end; - end = 0; - } - - try { - Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add rounded rectangle")); - Gui::Command::doCommand( - Gui::Command::Doc, - // syntax for arcs: Part.ArcOfCircle(Part.Circle(center, axis, radius), - // startangle, endangle) - "geoList = []\n" - "geoList.append(Part.ArcOfCircle(Part.Circle(App.Vector(%f, %f, 0), " - "App.Vector(0, 0, 1), %f), %f, %f))\n" - "geoList.append(Part.LineSegment(App.Vector(%f, %f, 0), App.Vector(%f, %f, " - "0)))\n" - "geoList.append(Part.ArcOfCircle(Part.Circle(App.Vector(%f, %f, 0), " - "App.Vector(0, 0, 1), %f), %f, %f))\n" - "geoList.append(Part.LineSegment(App.Vector(%f, %f, 0), App.Vector(%f, %f, " - "0)))\n" - "geoList.append(Part.ArcOfCircle(Part.Circle(App.Vector(%f, %f, 0), " - "App.Vector(0, 0, 1), %f), %f, %f))\n" - "geoList.append(Part.LineSegment(App.Vector(%f, %f, 0), App.Vector(%f, %f, " - "0)))\n" - "geoList.append(Part.ArcOfCircle(Part.Circle(App.Vector(%f, %f, 0), " - "App.Vector(0, 0, 1), %f), %f, %f))\n" - "geoList.append(Part.LineSegment(App.Vector(%f, %f, 0), App.Vector(%f, %f, " - "0)))\n" - "%s.addGeometry(geoList, %s)\n" - "conList = []\n" - "conList.append(Sketcher.Constraint('Tangent', %i, 1, %i, 1))\n" - "conList.append(Sketcher.Constraint('Tangent', %i, 2, %i, 2))\n" - "conList.append(Sketcher.Constraint('Tangent', %i, 1, %i, 1))\n" - "conList.append(Sketcher.Constraint('Tangent', %i, 2, %i, 2))\n" - "conList.append(Sketcher.Constraint('Tangent', %i, 1, %i, 1))\n" - "conList.append(Sketcher.Constraint('Tangent', %i, 2, %i, 2))\n" - "conList.append(Sketcher.Constraint('Tangent', %i, 1, %i, 1))\n" - "conList.append(Sketcher.Constraint('Tangent', %i, 2, %i, 2))\n" - "conList.append(Sketcher.Constraint('Horizontal', %i))\n" - "conList.append(Sketcher.Constraint('Horizontal', %i))\n" - "conList.append(Sketcher.Constraint('Vertical', %i))\n" - "conList.append(Sketcher.Constraint('Vertical', %i))\n" - "conList.append(Sketcher.Constraint('Equal', %i, %i))\n" - "conList.append(Sketcher.Constraint('Equal', %i, %i))\n" - "conList.append(Sketcher.Constraint('Equal', %i, %i))\n" - "%s.addConstraint(conList)\n" - "del geoList, conList\n", - StartPos.x + (signX * radius), - StartPos.y + (signY * radius), // center of the arc 1 - radius, - start, - end, // start and end angle of arc1 - EditCurve[8].x, - EditCurve[8].y, - EditCurve[9].x, - EditCurve[9].y, // line 1 - signX == signY - ? StartPos.x + (signX * radius) - : StartPos.x + lengthX - (signX * radius), // center of the arc 2 - signX == signY ? StartPos.y + lengthY - (signY * radius) - : StartPos.y + (signY * radius), - radius, - // start and end angle of arc 2 - // the logic is that end is start + M_PI / 2 and start is the previous end - - // M_PI - end - M_PI, - end - 0.5 * M_PI, - EditCurve[17].x, - EditCurve[17].y, - EditCurve[18].x, - EditCurve[18].y, // line 2 - StartPos.x + lengthX - (signX * radius), - StartPos.y + lengthY - (signY * radius), // center of the arc 3 - radius, - end - 1.5 * M_PI, - end - M_PI, - EditCurve[26].x, - EditCurve[26].y, - EditCurve[27].x, - EditCurve[27].y, // line 3 - signX == signY ? StartPos.x + lengthX - (signX * radius) - : StartPos.x + (signX * radius), // center of the arc 4 - signX == signY ? StartPos.y + (signY * radius) - : StartPos.y + lengthY - (signY * radius), - radius, - end - 2 * M_PI, - end - 1.5 * M_PI, - EditCurve[35].x, - EditCurve[35].y, - EditCurve[36].x, - EditCurve[36].y, // line 4 - Gui::Command::getObjectCmd(sketchgui->getObject()).c_str(), // the sketch - geometryCreationMode == Construction - ? "True" - : "False", // geometry as construction or not - firstCurve, - firstCurve + 1, // tangent 1 - firstCurve + 1, - firstCurve + 2, // tangent 2 - firstCurve + 2, - firstCurve + 3, // tangent 3 - firstCurve + 3, - firstCurve + 4, // tangent 4 - firstCurve + 4, - firstCurve + 5, // tangent 5 - firstCurve + 5, - firstCurve + 6, // tangent 6 - firstCurve + 6, - firstCurve + 7, // tangent 7 - firstCurve + 7, - firstCurve, // tangent 8 - signX == signY ? firstCurve + 3 : firstCurve + 1, // horizontal constraint - signX == signY ? firstCurve + 7 : firstCurve + 5, // horizontal constraint - signX == signY ? firstCurve + 1 : firstCurve + 3, // vertical constraint - signX == signY ? firstCurve + 5 : firstCurve + 7, // vertical constraint - firstCurve, - firstCurve + 2, // equal 1 - firstCurve + 2, - firstCurve + 4, // equal 2 - firstCurve + 4, - firstCurve + 6, // equal 3 - Gui::Command::getObjectCmd(sketchgui->getObject()).c_str()); // the sketch - - // not all users want these extra points, some power users find them unnecessary - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( - "User parameter:BaseApp/Preferences/Mod/Sketcher"); - auto showExtraPoints = hGrp->GetBool("RoundRectangleSuggConstraints", true); - if (showExtraPoints) { - // now add construction geometry - two points used to take suggested constraints - Gui::Command::doCommand( - Gui::Command::Doc, - "geoList = []\n" - "geoList.append(Part.Point(App.Vector(%f, %f, 0)))\n" - "geoList.append(Part.Point(App.Vector(%f, %f, 0)))\n" - "%s.addGeometry(geoList, True)\n" // geometry as construction - "conList = []\n" - "conList.append(Sketcher.Constraint('PointOnObject', %i, 1, %i, ))\n" - "conList.append(Sketcher.Constraint('PointOnObject', %i, 1, %i, ))\n" - "conList.append(Sketcher.Constraint('PointOnObject', %i, 1, %i, ))\n" - "conList.append(Sketcher.Constraint('PointOnObject', %i, 1, %i, ))\n" - "%s.addConstraint(conList)\n" - "del geoList, conList\n", - StartPos.x, - StartPos.y, // point at StartPos - EndPos.x, - EndPos.y, // point at EndPos - Gui::Command::getObjectCmd(sketchgui->getObject()).c_str(), // the sketch - firstCurve + 8, - firstCurve + 1, // point on object constraint - firstCurve + 8, - firstCurve + 7, // point on object constraint - firstCurve + 9, - firstCurve + 3, // point on object constraint - firstCurve + 9, - firstCurve + 5, // point on object constraint - Gui::Command::getObjectCmd(sketchgui->getObject()).c_str()); // the sketch + if (canGoToNextMode()) { + if (constructionMethod() == ConstructionMethod::Diagonal + || constructionMethod() == ConstructionMethod::CenterAndCorner) { + if (state() == SelectMode::SeekSecond && !roundCorners && !makeFrame) { + setState(SelectMode::End); } - - Gui::Command::commitCommand(); - - // add auto constraints at the StartPos auxiliary point - if (!sugConstr1.empty()) { - createAutoConstraints(sugConstr1, - getHighestCurveIndex() - 1, - Sketcher::PointPos::start); - sugConstr1.clear(); + else if ((state() == SelectMode::SeekThird && roundCorners && !makeFrame) + || (state() == SelectMode::SeekThird && !roundCorners && makeFrame)) { + setState(SelectMode::End); } - - // add auto constraints at the EndPos auxiliary point - if (!sugConstr2.empty()) { - createAutoConstraints(sugConstr2, - getHighestCurveIndex(), - Sketcher::PointPos::start); - sugConstr2.clear(); + else if (state() == SelectMode::SeekFourth) { + setState(SelectMode::End); + } + else { + this->moveToNextMode(); } - - tryAutoRecomputeIfNotSolve( - static_cast(sketchgui->getObject())); - } - catch (const Base::Exception&) { - Gui::NotifyError( - sketchgui, - QT_TRANSLATE_NOOP("Notifications", "Error"), - QT_TRANSLATE_NOOP("Notifications", "Failed to add rounded rectangle")); - - Gui::Command::abortCommand(); - - tryAutoRecompute(static_cast(sketchgui->getObject())); - } - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( - "User parameter:BaseApp/Preferences/Mod/Sketcher"); - bool continuousMode = hGrp->GetBool("ContinuousCreationMode", true); - - if (continuousMode) { - // This code enables the continuous creation mode. - Mode = STATUS_SEEK_First; - EditCurve.clear(); - drawEdit(EditCurve); - EditCurve.resize(37); - applyCursor(); - /* this is ok not to call to purgeHandler - * in continuous creation mode because the - * handler is destroyed by the quit() method on pressing the - * right button of the mouse */ } else { - sketchgui->purgeHandler(); // no code after this line, Handler get deleted in - // ViewProvider + if (state() == SelectMode::SeekThird && !roundCorners && !makeFrame) { + setState(SelectMode::End); + } + else if ((state() == SelectMode::SeekFourth && roundCorners && !makeFrame) + || (state() == SelectMode::SeekFourth && !roundCorners && makeFrame)) { + setState(SelectMode::End); + } + else { + this->moveToNextMode(); + } } } - return true; } private: - QString getCrosshairCursorSVGName() const override + Base::Vector2d center, corner1, corner2, corner3, corner4, frameCorner1, frameCorner2, + frameCorner3, frameCorner4, corner2Initial; + Base::Vector3d center1, center2, center3, center4; + bool roundCorners, makeFrame, cornersReversed; + double radius, length, width, thickness, radiusFrame, angle, angle123, angle412; + int firstCurve, constructionPointOneId, constructionPointTwoId, constructionPointThreeId, + centerPointId, side; + + void createShape(bool onlyeditoutline) override { - return QString::fromLatin1("Sketcher_Pointer_Oblong"); + + ShapeGeometry.clear(); + + Base::Vector2d vecL = corner2 - corner1; + Base::Vector2d vecW = corner4 - corner1; + length = vecL.Length(); + width = vecW.Length(); + angle = vecL.Angle(); + if (length > Precision::Confusion() && width > Precision::Confusion() + && fmod(fabs(angle123), M_PI) > Precision::Confusion()) { + vecL = vecL / length; + vecW = vecW / width; + double end = angle - M_PI / 2; + double L1 = radius; + double L2 = radius; + if (cos(angle123 / 2) != 1 && cos(angle412 / 2) != 1) { + L1 = radius / sqrt(1 - cos(angle123 / 2) * cos(angle123 / 2)); + L2 = radius / sqrt(1 - cos(angle412 / 2) * cos(angle412 / 2)); + } + + addLineToShapeGeometry(toVector3d(corner1 + vecL * L2 * cos(angle412 / 2)), + toVector3d(corner2 - vecL * L1 * cos(angle123 / 2)), + isConstructionMode()); + addLineToShapeGeometry(toVector3d(corner2 + vecW * L1 * cos(angle123 / 2)), + toVector3d(corner3 - vecW * L2 * cos(angle412 / 2)), + isConstructionMode()); + addLineToShapeGeometry(toVector3d(corner3 - vecL * L2 * cos(angle412 / 2)), + toVector3d(corner4 + vecL * L1 * cos(angle123 / 2)), + isConstructionMode()); + addLineToShapeGeometry(toVector3d(corner4 - vecW * L1 * cos(angle123 / 2)), + toVector3d(corner1 + vecW * L2 * cos(angle412 / 2)), + isConstructionMode()); + + if (roundCorners && radius > Precision::Confusion()) { + // center points required later for special case of round corner frame with + // radiusFrame = 0. + Base::Vector2d b1 = (vecL + vecW) / (vecL + vecW).Length(); + Base::Vector2d b2 = (vecL - vecW) / (vecL - vecW).Length(); + center1 = toVector3d(corner1 + b1 * L2); + center2 = toVector3d(corner2 - b2 * L1); + center3 = toVector3d(corner3 - b1 * L2); + center4 = toVector3d(corner4 + b2 * L1); + + addArcToShapeGeometry(center1, + end - M_PI + angle412, + end, + radius, + isConstructionMode()); + addArcToShapeGeometry(center2, + end, + end - M_PI - angle123, + radius, + isConstructionMode()); + addArcToShapeGeometry(center3, + end + angle412, + end - M_PI, + radius, + isConstructionMode()); + addArcToShapeGeometry(center4, + end - M_PI, + end - angle123, + radius, + isConstructionMode()); + } + + if (makeFrame && state() != SelectMode::SeekSecond + && fabs(thickness) > Precision::Confusion()) { + if (radius < Precision::Confusion()) { + radiusFrame = 0.; + } + else { + radiusFrame = radius + thickness; + if (radiusFrame < 0.) { + radiusFrame = 0.; + } + } + + Base::Vector2d vecLF = frameCorner2 - frameCorner1; + Base::Vector2d vecWF = frameCorner4 - frameCorner1; + double lengthF = vecLF.Length(); + double widthF = vecWF.Length(); + + double L1F = 0.; + double L2F = 0.; + if (radius > Precision::Confusion()) { + L1F = L1 * radiusFrame / radius; + L2F = L2 * radiusFrame / radius; + } + + addLineToShapeGeometry( + toVector3d(frameCorner1 + vecLF / lengthF * L2F * cos(angle412 / 2)), + toVector3d(frameCorner2 - vecLF / lengthF * L1F * cos(angle123 / 2)), + isConstructionMode()); + addLineToShapeGeometry( + toVector3d(frameCorner2 + vecWF / widthF * L1F * cos(angle123 / 2)), + toVector3d(frameCorner3 - vecWF / widthF * L2F * cos(angle412 / 2)), + isConstructionMode()); + addLineToShapeGeometry( + toVector3d(frameCorner3 - vecLF / lengthF * L2F * cos(angle412 / 2)), + toVector3d(frameCorner4 + vecLF / lengthF * L1F * cos(angle123 / 2)), + isConstructionMode()); + addLineToShapeGeometry( + toVector3d(frameCorner4 - vecWF / widthF * L1F * cos(angle123 / 2)), + toVector3d(frameCorner1 + vecWF / widthF * L2F * cos(angle412 / 2)), + isConstructionMode()); + + if (roundCorners && radiusFrame > Precision::Confusion()) { + Base::Vector2d b1 = (vecL + vecW) / (vecL + vecW).Length(); + Base::Vector2d b2 = (vecL - vecW) / (vecL - vecW).Length(); + + addArcToShapeGeometry(toVector3d(frameCorner1 + b1 * L2F), + end - M_PI + angle412, + end, + radiusFrame, + isConstructionMode()); + addArcToShapeGeometry(toVector3d(frameCorner2 - b2 * L1F), + end, + end - M_PI - angle123, + radiusFrame, + isConstructionMode()); + addArcToShapeGeometry(toVector3d(frameCorner3 - b1 * L2F), + end + angle412, + end - M_PI, + radiusFrame, + isConstructionMode()); + addArcToShapeGeometry(toVector3d(frameCorner4 + b2 * L1F), + end - M_PI, + end - angle123, + radiusFrame, + isConstructionMode()); + } + } + + if (!onlyeditoutline) { + ShapeConstraints.clear(); + Sketcher::ConstraintType typeA = Sketcher::Horizontal; + Sketcher::ConstraintType typeB = Sketcher::Vertical; + if (Base::sgn(corner3.x - corner1.x) * Base::sgn(corner3.y - corner1.y) < 0) { + typeA = Sketcher::Vertical; + typeB = Sketcher::Horizontal; + } + + if (radius > Precision::Confusion()) { + + addToShapeConstraints(Sketcher::Tangent, + firstCurve, + Sketcher::PointPos::start, + firstCurve + 4, + Sketcher::PointPos::end); + addToShapeConstraints(Sketcher::Tangent, + firstCurve, + Sketcher::PointPos::end, + firstCurve + 5, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Tangent, + firstCurve + 1, + Sketcher::PointPos::start, + firstCurve + 5, + Sketcher::PointPos::end); + addToShapeConstraints(Sketcher::Tangent, + firstCurve + 1, + Sketcher::PointPos::end, + firstCurve + 6, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Tangent, + firstCurve + 2, + Sketcher::PointPos::start, + firstCurve + 6, + Sketcher::PointPos::end); + addToShapeConstraints(Sketcher::Tangent, + firstCurve + 2, + Sketcher::PointPos::end, + firstCurve + 7, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Tangent, + firstCurve + 3, + Sketcher::PointPos::start, + firstCurve + 7, + Sketcher::PointPos::end); + addToShapeConstraints(Sketcher::Tangent, + firstCurve + 3, + Sketcher::PointPos::end, + firstCurve + 4, + Sketcher::PointPos::start); + + if (fabs(angle) < Precision::Confusion() + || constructionMethod() == ConstructionMethod::Diagonal + || constructionMethod() == ConstructionMethod::CenterAndCorner) { + addToShapeConstraints(typeA, firstCurve); + addToShapeConstraints(typeA, firstCurve + 2); + addToShapeConstraints(typeB, firstCurve + 1); + addToShapeConstraints(typeB, firstCurve + 3); + } + else { + addToShapeConstraints(Sketcher::Parallel, + firstCurve, + Sketcher::PointPos::none, + firstCurve + 2); + addToShapeConstraints(Sketcher::Parallel, + firstCurve + 1, + Sketcher::PointPos::none, + firstCurve + 3); + if (fabs(angle123 - M_PI / 2) < Precision::Confusion()) { + addToShapeConstraints(Sketcher::Perpendicular, + firstCurve, + Sketcher::PointPos::none, + firstCurve + 1); + } + } + addToShapeConstraints(Sketcher::Equal, + firstCurve + 4, + Sketcher::PointPos::none, + firstCurve + 5); + addToShapeConstraints(Sketcher::Equal, + firstCurve + 5, + Sketcher::PointPos::none, + firstCurve + 6); + addToShapeConstraints(Sketcher::Equal, + firstCurve + 6, + Sketcher::PointPos::none, + firstCurve + 7); + + if (fabs(thickness) > Precision::Confusion()) { + if (radiusFrame + < Precision::Confusion()) { // case inner rectangle is normal rectangle + + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 8, + Sketcher::PointPos::end, + firstCurve + 9, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 9, + Sketcher::PointPos::end, + firstCurve + 10, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 10, + Sketcher::PointPos::end, + firstCurve + 11, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 11, + Sketcher::PointPos::end, + firstCurve + 8, + Sketcher::PointPos::start); + + if (fabs(angle) < Precision::Confusion() + || constructionMethod() == ConstructionMethod::Diagonal + || constructionMethod() == ConstructionMethod::CenterAndCorner) { + addToShapeConstraints(typeA, firstCurve + 8); + addToShapeConstraints(typeA, firstCurve + 10); + addToShapeConstraints(typeB, firstCurve + 9); + addToShapeConstraints(typeB, firstCurve + 11); + } + else { + addToShapeConstraints(Sketcher::Parallel, + firstCurve + 8, + Sketcher::PointPos::none, + firstCurve + 10); + addToShapeConstraints(Sketcher::Parallel, + firstCurve + 9, + Sketcher::PointPos::none, + firstCurve + 11); + addToShapeConstraints(Sketcher::Parallel, + firstCurve + 8, + Sketcher::PointPos::none, + firstCurve); + addToShapeConstraints(Sketcher::Parallel, + firstCurve + 9, + Sketcher::PointPos::none, + firstCurve + 1); + } + + // add construction lines +12, +13, +14, +15 + addLineToShapeGeometry( + center1, + Base::Vector3d(frameCorner1.x, frameCorner1.y, 0.), + true); + addLineToShapeGeometry( + center2, + Base::Vector3d(frameCorner2.x, frameCorner2.y, 0.), + true); + addLineToShapeGeometry( + center3, + Base::Vector3d(frameCorner3.x, frameCorner3.y, 0.), + true); + addLineToShapeGeometry( + center4, + Base::Vector3d(frameCorner4.x, frameCorner4.y, 0.), + true); + + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 12, + Sketcher::PointPos::start, + firstCurve + 4, + Sketcher::PointPos::mid); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 12, + Sketcher::PointPos::end, + firstCurve + 8, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 13, + Sketcher::PointPos::start, + firstCurve + 5, + Sketcher::PointPos::mid); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 13, + Sketcher::PointPos::end, + firstCurve + 9, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 14, + Sketcher::PointPos::start, + firstCurve + 6, + Sketcher::PointPos::mid); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 14, + Sketcher::PointPos::end, + firstCurve + 10, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 15, + Sketcher::PointPos::start, + firstCurve + 7, + Sketcher::PointPos::mid); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 15, + Sketcher::PointPos::end, + firstCurve + 11, + Sketcher::PointPos::start); + + addToShapeConstraints(Sketcher::Perpendicular, + firstCurve + 12, + Sketcher::PointPos::none, + firstCurve + 13); + addToShapeConstraints(Sketcher::Perpendicular, + firstCurve + 13, + Sketcher::PointPos::none, + firstCurve + 14); + addToShapeConstraints(Sketcher::Perpendicular, + firstCurve + 14, + Sketcher::PointPos::none, + firstCurve + 15); + } + else { // case inner rectangle is rounded rectangle + addToShapeConstraints(Sketcher::Tangent, + firstCurve + 8, + Sketcher::PointPos::start, + firstCurve + 12, + Sketcher::PointPos::end); + addToShapeConstraints(Sketcher::Tangent, + firstCurve + 8, + Sketcher::PointPos::end, + firstCurve + 13, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Tangent, + firstCurve + 9, + Sketcher::PointPos::start, + firstCurve + 13, + Sketcher::PointPos::end); + addToShapeConstraints(Sketcher::Tangent, + firstCurve + 9, + Sketcher::PointPos::end, + firstCurve + 14, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Tangent, + firstCurve + 10, + Sketcher::PointPos::start, + firstCurve + 14, + Sketcher::PointPos::end); + addToShapeConstraints(Sketcher::Tangent, + firstCurve + 10, + Sketcher::PointPos::end, + firstCurve + 15, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Tangent, + firstCurve + 11, + Sketcher::PointPos::start, + firstCurve + 15, + Sketcher::PointPos::end); + addToShapeConstraints(Sketcher::Tangent, + firstCurve + 11, + Sketcher::PointPos::end, + firstCurve + 12, + Sketcher::PointPos::start); + + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 4, + Sketcher::PointPos::mid, + firstCurve + 12, + Sketcher::PointPos::mid); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 5, + Sketcher::PointPos::mid, + firstCurve + 13, + Sketcher::PointPos::mid); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 6, + Sketcher::PointPos::mid, + firstCurve + 14, + Sketcher::PointPos::mid); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 7, + Sketcher::PointPos::mid, + firstCurve + 15, + Sketcher::PointPos::mid); + + if (fabs(angle) < Precision::Confusion() + || constructionMethod() == ConstructionMethod::Diagonal + || constructionMethod() == ConstructionMethod::CenterAndCorner) { + addToShapeConstraints(typeA, firstCurve + 8); + addToShapeConstraints(typeA, firstCurve + 10); + addToShapeConstraints(typeB, firstCurve + 9); + } + else { + addToShapeConstraints(Sketcher::Parallel, + firstCurve + 8, + Sketcher::PointPos::none, + firstCurve + 10); + addToShapeConstraints(Sketcher::Parallel, + firstCurve + 9, + Sketcher::PointPos::none, + firstCurve + 11); + addToShapeConstraints(Sketcher::Parallel, + firstCurve + 8, + Sketcher::PointPos::none, + firstCurve); + } + } + } + + if (constructionMethod() == ConstructionMethod::ThreePoints) { + if (fabs(thickness) > Precision::Confusion()) { + constructionPointOneId = firstCurve + 16; + constructionPointTwoId = firstCurve + 17; + constructionPointThreeId = firstCurve + 18; + } + else { + constructionPointOneId = firstCurve + 8; + constructionPointTwoId = firstCurve + 9; + constructionPointThreeId = firstCurve + 10; + } + + addPointToShapeGeometry(Base::Vector3d(corner1.x, corner1.y, 0.), true); + if (!cornersReversed) { + addPointToShapeGeometry(Base::Vector3d(corner2.x, corner2.y, 0.), true); + addToShapeConstraints(Sketcher::PointOnObject, + constructionPointTwoId, + Sketcher::PointPos::start, + firstCurve); + addToShapeConstraints(Sketcher::PointOnObject, + constructionPointTwoId, + Sketcher::PointPos::start, + firstCurve + 1); + } + else { + addPointToShapeGeometry(Base::Vector3d(corner4.x, corner4.y, 0.), true); + addToShapeConstraints(Sketcher::PointOnObject, + constructionPointTwoId, + Sketcher::PointPos::start, + firstCurve + 2); + addToShapeConstraints(Sketcher::PointOnObject, + constructionPointTwoId, + Sketcher::PointPos::start, + firstCurve + 3); + } + addPointToShapeGeometry(Base::Vector3d(corner3.x, corner3.y, 0.), true); + addToShapeConstraints(Sketcher::PointOnObject, + constructionPointOneId, + Sketcher::PointPos::start, + firstCurve); + addToShapeConstraints(Sketcher::PointOnObject, + constructionPointOneId, + Sketcher::PointPos::start, + firstCurve + 3); + addToShapeConstraints(Sketcher::PointOnObject, + constructionPointThreeId, + Sketcher::PointPos::start, + firstCurve + 1); + addToShapeConstraints(Sketcher::PointOnObject, + constructionPointThreeId, + Sketcher::PointPos::start, + firstCurve + 2); + } + else if (constructionMethod() == ConstructionMethod::CenterAnd3Points) { + if (fabs(thickness) > Precision::Confusion()) { + constructionPointOneId = firstCurve + 16; + constructionPointTwoId = firstCurve + 17; + centerPointId = firstCurve + 18; + } + else { + constructionPointOneId = firstCurve + 8; + constructionPointTwoId = firstCurve + 9; + centerPointId = firstCurve + 10; + } + + addPointToShapeGeometry(Base::Vector3d(corner1.x, corner1.y, 0.), true); + if (!cornersReversed) { + addPointToShapeGeometry(Base::Vector3d(corner2.x, corner2.y, 0.), true); + addToShapeConstraints(Sketcher::PointOnObject, + constructionPointTwoId, + Sketcher::PointPos::start, + firstCurve); + addToShapeConstraints(Sketcher::PointOnObject, + constructionPointTwoId, + Sketcher::PointPos::start, + firstCurve + 1); + } + else { + addPointToShapeGeometry(Base::Vector3d(corner4.x, corner4.y, 0.), true); + addToShapeConstraints(Sketcher::PointOnObject, + constructionPointTwoId, + Sketcher::PointPos::start, + firstCurve + 2); + addToShapeConstraints(Sketcher::PointOnObject, + constructionPointTwoId, + Sketcher::PointPos::start, + firstCurve + 3); + } + addPointToShapeGeometry(Base::Vector3d(center.x, center.y, 0.), true); + addToShapeConstraints(Sketcher::Symmetric, + firstCurve + 2, + Sketcher::PointPos::start, + firstCurve, + Sketcher::PointPos::start, + centerPointId, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::PointOnObject, + constructionPointOneId, + Sketcher::PointPos::start, + firstCurve); + addToShapeConstraints(Sketcher::PointOnObject, + constructionPointOneId, + Sketcher::PointPos::start, + firstCurve + 3); + } + else if (constructionMethod() == ConstructionMethod::CenterAndCorner) { + if (fabs(thickness) > Precision::Confusion()) { + constructionPointOneId = firstCurve + 16; + centerPointId = firstCurve + 17; + } + else { + constructionPointOneId = firstCurve + 8; + centerPointId = firstCurve + 9; + } + + addPointToShapeGeometry(Base::Vector3d(corner3.x, corner3.y, 0.), true); + addPointToShapeGeometry(Base::Vector3d(center.x, center.y, 0.), true); + addToShapeConstraints(Sketcher::Symmetric, + firstCurve + 2, + Sketcher::PointPos::start, + firstCurve, + Sketcher::PointPos::start, + centerPointId, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::PointOnObject, + constructionPointOneId, + Sketcher::PointPos::start, + firstCurve + 1); + addToShapeConstraints(Sketcher::PointOnObject, + constructionPointOneId, + Sketcher::PointPos::start, + firstCurve + 2); + } + else { + if (fabs(thickness) > Precision::Confusion()) { + constructionPointOneId = firstCurve + 16; + constructionPointTwoId = firstCurve + 17; + } + else { + constructionPointOneId = firstCurve + 8; + constructionPointTwoId = firstCurve + 9; + } + + addPointToShapeGeometry(Base::Vector3d(corner1.x, corner1.y, 0.), true); + addPointToShapeGeometry(Base::Vector3d(corner3.x, corner3.y, 0.), true); + addToShapeConstraints(Sketcher::PointOnObject, + constructionPointOneId, + Sketcher::PointPos::start, + firstCurve); + addToShapeConstraints(Sketcher::PointOnObject, + constructionPointOneId, + Sketcher::PointPos::start, + firstCurve + 3); + addToShapeConstraints(Sketcher::PointOnObject, + constructionPointTwoId, + Sketcher::PointPos::start, + firstCurve + 1); + addToShapeConstraints(Sketcher::PointOnObject, + constructionPointTwoId, + Sketcher::PointPos::start, + firstCurve + 2); + } + } + else { // cases of normal rectangles and normal frames + addToShapeConstraints(Sketcher::Coincident, + firstCurve, + Sketcher::PointPos::end, + firstCurve + 1, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 1, + Sketcher::PointPos::end, + firstCurve + 2, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 2, + Sketcher::PointPos::end, + firstCurve + 3, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 3, + Sketcher::PointPos::end, + firstCurve, + Sketcher::PointPos::start); + if (fabs(angle) < Precision::Confusion() + || constructionMethod() == ConstructionMethod::Diagonal + || constructionMethod() == ConstructionMethod::CenterAndCorner) { + addToShapeConstraints(typeA, firstCurve); + addToShapeConstraints(typeA, firstCurve + 2); + addToShapeConstraints(typeB, firstCurve + 1); + addToShapeConstraints(typeB, firstCurve + 3); + } + else { + addToShapeConstraints(Sketcher::Parallel, + firstCurve, + Sketcher::PointPos::none, + firstCurve + 2); + addToShapeConstraints(Sketcher::Parallel, + firstCurve + 1, + Sketcher::PointPos::none, + firstCurve + 3); + if (fabs(angle123 - M_PI / 2) < Precision::Confusion()) { + addToShapeConstraints(Sketcher::Perpendicular, + firstCurve, + Sketcher::PointPos::none, + firstCurve + 1); + } + } + + if (fabs(thickness) > Precision::Confusion()) { + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 4, + Sketcher::PointPos::end, + firstCurve + 5, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 5, + Sketcher::PointPos::end, + firstCurve + 6, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 6, + Sketcher::PointPos::end, + firstCurve + 7, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 7, + Sketcher::PointPos::end, + firstCurve + 4, + Sketcher::PointPos::start); + + if (fabs(angle) < Precision::Confusion() + || constructionMethod() == ConstructionMethod::Diagonal + || constructionMethod() == ConstructionMethod::CenterAndCorner) { + addToShapeConstraints(typeA, firstCurve + 4); + addToShapeConstraints(typeA, firstCurve + 6); + addToShapeConstraints(typeB, firstCurve + 5); + addToShapeConstraints(typeB, firstCurve + 7); + } + else { + addToShapeConstraints(Sketcher::Parallel, + firstCurve + 4, + Sketcher::PointPos::none, + firstCurve + 6); + addToShapeConstraints(Sketcher::Parallel, + firstCurve + 5, + Sketcher::PointPos::none, + firstCurve + 7); + if (fabs(angle123 - M_PI / 2) < Precision::Confusion()) { + addToShapeConstraints(Sketcher::Perpendicular, + firstCurve + 4, + Sketcher::PointPos::none, + firstCurve + 5); + } + } + + // add construction lines + addLineToShapeGeometry(Base::Vector3d(corner1.x, corner1.y, 0.), + Base::Vector3d(frameCorner1.x, frameCorner1.y, 0.), + true); + addLineToShapeGeometry(Base::Vector3d(corner2.x, corner2.y, 0.), + Base::Vector3d(frameCorner2.x, frameCorner2.y, 0.), + true); + addLineToShapeGeometry(Base::Vector3d(corner3.x, corner3.y, 0.), + Base::Vector3d(frameCorner3.x, frameCorner3.y, 0.), + true); + addLineToShapeGeometry(Base::Vector3d(corner4.x, corner4.y, 0.), + Base::Vector3d(frameCorner4.x, frameCorner4.y, 0.), + true); + + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 8, + Sketcher::PointPos::start, + firstCurve, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 8, + Sketcher::PointPos::end, + firstCurve + 4, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 9, + Sketcher::PointPos::start, + firstCurve + 1, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 9, + Sketcher::PointPos::end, + firstCurve + 5, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 10, + Sketcher::PointPos::start, + firstCurve + 2, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 10, + Sketcher::PointPos::end, + firstCurve + 6, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 11, + Sketcher::PointPos::start, + firstCurve + 3, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Coincident, + firstCurve + 11, + Sketcher::PointPos::end, + firstCurve + 7, + Sketcher::PointPos::start); + + addToShapeConstraints(Sketcher::Perpendicular, + firstCurve + 8, + Sketcher::PointPos::none, + firstCurve + 9); + addToShapeConstraints(Sketcher::Perpendicular, + firstCurve + 9, + Sketcher::PointPos::none, + firstCurve + 10); + addToShapeConstraints(Sketcher::Perpendicular, + firstCurve + 10, + Sketcher::PointPos::none, + firstCurve + 11); + } + + if (constructionMethod() == ConstructionMethod::CenterAndCorner + || constructionMethod() == ConstructionMethod::CenterAnd3Points) { + if (fabs(thickness) > Precision::Confusion()) { + centerPointId = firstCurve + 12; + } + else { + centerPointId = firstCurve + 4; + } + + addPointToShapeGeometry(Base::Vector3d(center.x, center.y, 0.), true); + addToShapeConstraints(Sketcher::Symmetric, + firstCurve + 2, + Sketcher::PointPos::start, + firstCurve, + Sketcher::PointPos::start, + centerPointId, + Sketcher::PointPos::start); + } + } + } + } } -protected: - BoxMode Mode; - Base::Vector2d StartPos, EndPos; - double lengthX, lengthY, radius; - float signX, signY; - std::vector EditCurve; - std::vector sugConstr1, sugConstr2; + int getPointSideOfVector(Base::Vector2d pointToCheck, + Base::Vector2d separatingVector, + Base::Vector2d pointOnVector) + { + Base::Vector2d secondPointOnVec = pointOnVector + separatingVector; + double d = (pointToCheck.x - pointOnVector.x) * (secondPointOnVec.y - pointOnVector.y) + - (pointToCheck.y - pointOnVector.y) * (secondPointOnVec.x - pointOnVector.x); + if (abs(d) < Precision::Confusion()) { + return 0; + } + else if (d < 0) { + return -1; + } + else { + return 1; + } + } + + void calculateRadius(Base::Vector2d onSketchPos) + { + Base::Vector2d u = (corner2 - corner1) / (corner2 - corner1).Length(); + Base::Vector2d v = (corner4 - corner1) / (corner4 - corner1).Length(); + Base::Vector2d e = onSketchPos - corner1; + double du = (v.y * e.x - v.x * e.y) / (u.x * v.y - u.y * v.x); + double dv = (-u.y * e.x + u.x * e.y) / (u.x * v.y - u.y * v.x); + if (du < 0 || du > length || dv < 0 || dv > width) { + radius = 0.; + } + else { + if (du < length - du && dv < width - dv) { + radius = (du + dv + + std::max(2 * sqrt(du * dv) * sin(angle412 / 2), + -2 * sqrt(du * dv) * sin(angle412 / 2))) + * tan(angle412 / 2); + } + else if (du > length - du && dv < width - dv) { + du = length - du; + radius = (du + dv + + std::max(2 * sqrt(du * dv) * sin(angle123 / 2), + -2 * sqrt(du * dv) * sin(angle123 / 2))) + * tan(angle123 / 2); + } + else if (du < length - du && dv > width - dv) { + dv = width - dv; + radius = (du + dv + + std::max(2 * sqrt(du * dv) * sin(angle123 / 2), + -2 * sqrt(du * dv) * sin(angle123 / 2))) + * tan(angle123 / 2); + } + else { + du = length - du; + dv = width - dv; + radius = (du + dv + + std::max(2 * sqrt(du * dv) * sin(angle412 / 2), + -2 * sqrt(du * dv) * sin(angle412 / 2))) + * tan(angle412 / 2); + } + radius = std::min( + radius, + std::min(length * 0.999, width * 0.999) + / (cos(angle412 / 2) / sqrt(1 - cos(angle412 / 2) * cos(angle412 / 2)) + + cos(angle123 / 2) / sqrt(1 - cos(angle123 / 2) * cos(angle123 / 2)))); + } + + SbString text; + text.sprintf(" (%.1f radius)", radius); + setPositionText(onSketchPos, text); + } + + void calculateThickness(Base::Vector2d onSketchPos) + { + + Base::Vector2d u = (corner2 - corner1) / (corner2 - corner1).Length(); + Base::Vector2d v = (corner4 - corner1) / (corner4 - corner1).Length(); + Base::Vector2d e = onSketchPos - corner1; + double obliqueThickness = 0.; + double du = (v.y * e.x - v.x * e.y) / (u.x * v.y - u.y * v.x); + double dv = (-u.y * e.x + u.x * e.y) / (u.x * v.y - u.y * v.x); + if (du > 0 && du < length && !(dv > 0 && dv < width)) { + obliqueThickness = std::min(fabs(dv), fabs(width - dv)); + } + else if (dv > 0 && dv < width && !(du > 0 && du < length)) { + obliqueThickness = std::min(fabs(du), fabs(length - du)); + } + else if (du > 0 && du < length && dv > 0 && dv < width) { + obliqueThickness = -std::min(std::min(fabs(du), fabs(length - du)), + std::min(fabs(dv), fabs(width - dv))); + } + else { + obliqueThickness = std::max(std::min(fabs(du), fabs(length - du)), + std::min(fabs(dv), fabs(width - dv))); + } + + + frameCorner1 = corner1 - u * obliqueThickness - v * obliqueThickness; + frameCorner2 = corner2 + u * obliqueThickness - v * obliqueThickness; + frameCorner3 = corner3 + u * obliqueThickness + v * obliqueThickness; + frameCorner4 = corner4 - u * obliqueThickness + v * obliqueThickness; + + thickness = obliqueThickness * sin(angle412); + + SbString text; + text.sprintf(" (%.1fT)", thickness); + setPositionText(onSketchPos, text); + } }; +template<> +auto DSHRectangleControllerBase::getState(int labelindex) const +{ + if (handler->constructionMethod() == ConstructionMethod::Diagonal + || handler->constructionMethod() == ConstructionMethod::CenterAndCorner) { + switch (labelindex) { + case OnViewParameter::First: + case OnViewParameter::Second: + return SelectMode::SeekFirst; + break; + case OnViewParameter::Third: + case OnViewParameter::Fourth: + return SelectMode::SeekSecond; + break; + case OnViewParameter::Fifth: + return SelectMode::SeekThird; + break; + case OnViewParameter::Sixth: + if (!handler->roundCorners) { + return SelectMode::SeekThird; + } + else { + return SelectMode::SeekFourth; + } + break; + default: + THROWM(Base::ValueError, "Parameter index without an associated machine state") + } + } + else { + switch (labelindex) { + case OnViewParameter::First: + case OnViewParameter::Second: + return SelectMode::SeekFirst; + break; + case OnViewParameter::Third: + case OnViewParameter::Fourth: + return SelectMode::SeekSecond; + break; + case OnViewParameter::Fifth: + case OnViewParameter::Sixth: + return SelectMode::SeekThird; + break; + case OnViewParameter::Seventh: + return SelectMode::SeekFourth; + break; + case OnViewParameter::Eighth: + if (!handler->roundCorners) { + return SelectMode::SeekFourth; + } + else { + return SelectMode::SeekFifth; + } + break; + default: + THROWM(Base::ValueError, "Parameter index without an associated machine state") + } + } +} + +template<> +void DSHRectangleController::configureToolWidget() +{ + if (!init) { // Code to be executed only upon initialisation + QStringList names = {QStringLiteral("Diagonal corners"), + QStringLiteral("Center and corner"), + QStringLiteral("3 corners"), + QStringLiteral("Center and 2 corners")}; + toolWidget->setComboboxElements(WCombobox::FirstCombo, names); + + toolWidget->setCheckboxLabel( + WCheckbox::FirstBox, + QApplication::translate("TaskSketcherTool_c1_rectangle", "Rounded corners (U)")); + toolWidget->setCheckboxToolTip( + WCheckbox::FirstBox, + QApplication::translate("TaskSketcherTool_c1_rectangle", + "Create a rectangle with rounded corners.")); + syncCheckboxToHandler(WCheckbox::FirstBox, handler->roundCorners); + + toolWidget->setCheckboxLabel( + WCheckbox::SecondBox, + QApplication::translate("TaskSketcherTool_c2_rectangle", "Frame (J)")); + toolWidget->setCheckboxToolTip( + WCheckbox::SecondBox, + QApplication::translate( + "TaskSketcherTool_c2_rectangle", + "Create two rectangles, one in the other with a constant thickness.")); + syncCheckboxToHandler(WCheckbox::SecondBox, handler->makeFrame); + + if (isConstructionMode()) { + toolWidget->setComboboxItemIcon( + WCombobox::FirstCombo, + 0, + Gui::BitmapFactory().iconFromTheme("Sketcher_CreateRectangle_Constr")); + toolWidget->setComboboxItemIcon( + WCombobox::FirstCombo, + 1, + Gui::BitmapFactory().iconFromTheme("Sketcher_CreateRectangle_Center_Constr")); + toolWidget->setComboboxItemIcon( + WCombobox::FirstCombo, + 2, + Gui::BitmapFactory().iconFromTheme("Sketcher_CreateRectangle3Points_Constr")); + toolWidget->setComboboxItemIcon(WCombobox::FirstCombo, + 3, + Gui::BitmapFactory().iconFromTheme( + "Sketcher_CreateRectangle3Points_Center_Constr")); + + toolWidget->setCheckboxIcon( + WCheckbox::FirstBox, + Gui::BitmapFactory().iconFromTheme("Sketcher_CreateOblong_Constr")); + toolWidget->setCheckboxIcon( + WCheckbox::SecondBox, + Gui::BitmapFactory().iconFromTheme("Sketcher_CreateFrame_Constr")); + } + else { + toolWidget->setComboboxItemIcon( + WCombobox::FirstCombo, + 0, + Gui::BitmapFactory().iconFromTheme("Sketcher_CreateRectangle")); + toolWidget->setComboboxItemIcon( + WCombobox::FirstCombo, + 1, + Gui::BitmapFactory().iconFromTheme("Sketcher_CreateRectangle_Center")); + toolWidget->setComboboxItemIcon( + WCombobox::FirstCombo, + 2, + Gui::BitmapFactory().iconFromTheme("Sketcher_CreateRectangle3Points")); + toolWidget->setComboboxItemIcon( + WCombobox::FirstCombo, + 3, + Gui::BitmapFactory().iconFromTheme("Sketcher_CreateRectangle3Points_Center")); + + toolWidget->setCheckboxIcon( + WCheckbox::FirstBox, + Gui::BitmapFactory().iconFromTheme("Sketcher_CreateOblong")); + toolWidget->setCheckboxIcon(WCheckbox::SecondBox, + Gui::BitmapFactory().iconFromTheme("Sketcher_CreateFrame")); + } + } + + onViewParameters[OnViewParameter::First]->setLabelType(Gui::SoDatumLabel::DISTANCEX); + onViewParameters[OnViewParameter::Second]->setLabelType(Gui::SoDatumLabel::DISTANCEY); + + if (handler->constructionMethod() == ConstructionMethod::Diagonal + || handler->constructionMethod() == ConstructionMethod::CenterAndCorner) { + + onViewParameters[OnViewParameter::Third]->setLabelType(Gui::SoDatumLabel::DISTANCEX); + onViewParameters[OnViewParameter::Fourth]->setLabelType(Gui::SoDatumLabel::DISTANCEY); + onViewParameters[OnViewParameter::Fifth]->setLabelType(Gui::SoDatumLabel::RADIUS); + } + else if (handler->constructionMethod() == ConstructionMethod::ThreePoints) { + onViewParameters[OnViewParameter::Fourth]->setLabelType(Gui::SoDatumLabel::ANGLE); + onViewParameters[OnViewParameter::Sixth]->setLabelType(Gui::SoDatumLabel::ANGLE); + onViewParameters[OnViewParameter::Seventh]->setLabelType(Gui::SoDatumLabel::RADIUS); + } + else if (handler->constructionMethod() == ConstructionMethod::CenterAnd3Points) { + onViewParameters[OnViewParameter::Third]->setLabelType(Gui::SoDatumLabel::DISTANCEX); + onViewParameters[OnViewParameter::Fourth]->setLabelType(Gui::SoDatumLabel::DISTANCEY); + onViewParameters[OnViewParameter::Sixth]->setLabelType(Gui::SoDatumLabel::ANGLE); + onViewParameters[OnViewParameter::Seventh]->setLabelType(Gui::SoDatumLabel::RADIUS); + } +} + +template<> +void DSHRectangleController::adaptDrawingToCheckboxChange(int checkboxindex, bool value) +{ + Q_UNUSED(checkboxindex); + + switch (checkboxindex) { + case WCheckbox::FirstBox: + handler->roundCorners = value; + break; + case WCheckbox::SecondBox: + handler->makeFrame = value; + break; + } + + handler->updateCursor(); +} + +template<> +void DSHRectangleControllerBase::doEnforceControlParameters(Base::Vector2d& onSketchPos) +{ + switch (handler->state()) { + case SelectMode::SeekFirst: { + if (onViewParameters[OnViewParameter::First]->isSet) { + onSketchPos.x = onViewParameters[OnViewParameter::First]->getValue(); + } + + if (onViewParameters[OnViewParameter::Second]->isSet) { + onSketchPos.y = onViewParameters[OnViewParameter::Second]->getValue(); + } + } break; + case SelectMode::SeekSecond: { + if (handler->constructionMethod() == ConstructionMethod::Diagonal + || handler->constructionMethod() == ConstructionMethod::CenterAndCorner) { + if (onViewParameters[OnViewParameter::Third]->isSet) { + double length = onViewParameters[OnViewParameter::Third]->getValue(); + if (fabs(length) < Precision::Confusion()) { + unsetOnViewParameter(onViewParameters[OnViewParameter::Third].get()); + } + else { + if (handler->constructionMethod() == ConstructionMethod::Diagonal) { + int sign = (onSketchPos.x - handler->corner1.x) >= 0 ? 1 : -1; + onSketchPos.x = handler->corner1.x + sign * length; + } + else { + onSketchPos.x = handler->center.x + length / 2; + } + } + } + if (onViewParameters[OnViewParameter::Fourth]->isSet) { + double width = onViewParameters[OnViewParameter::Fourth]->getValue(); + if (fabs(width) < Precision::Confusion()) { + unsetOnViewParameter(onViewParameters[OnViewParameter::Fourth].get()); + } + else { + if (handler->constructionMethod() == ConstructionMethod::Diagonal) { + int sign = (onSketchPos.y - handler->corner1.y) >= 0 ? 1 : -1; + onSketchPos.y = handler->corner1.y + sign * width; + } + else { + onSketchPos.y = handler->center.y + width / 2; + } + } + } + } + else if (handler->constructionMethod() == ConstructionMethod::ThreePoints) { + Base::Vector2d dir = onSketchPos - handler->corner1; + double length = dir.Length(); + + if (onViewParameters[OnViewParameter::Third]->isSet) { + length = onViewParameters[OnViewParameter::Third]->getValue(); + if (length < Precision::Confusion()) { + unsetOnViewParameter(onViewParameters[OnViewParameter::Third].get()); + } + else { + if (dir.Length() < Precision::Confusion()) { + dir.x = 1; // if direction cannot be determined, default to (1,0) + } + + onSketchPos = handler->corner1 + length * dir.Normalize(); + } + } + + if (onViewParameters[OnViewParameter::Fourth]->isSet) { + double angle = + onViewParameters[OnViewParameter::Fourth]->getValue() * M_PI / 180; + onSketchPos.x = handler->corner1.x + cos(angle) * length; + onSketchPos.y = handler->corner1.y + sin(angle) * length; + } + } + else { + if (onViewParameters[OnViewParameter::Third]->isSet) { + onSketchPos.x = onViewParameters[OnViewParameter::Third]->getValue(); + } + + if (onViewParameters[OnViewParameter::Fourth]->isSet) { + onSketchPos.y = onViewParameters[OnViewParameter::Fourth]->getValue(); + } + } + } break; + case SelectMode::SeekThird: { + if (handler->constructionMethod() == ConstructionMethod::Diagonal + || handler->constructionMethod() == ConstructionMethod::CenterAndCorner) { + if (handler->roundCorners) { + if (onViewParameters[OnViewParameter::Fifth]->isSet) { + Base::Vector2d vecL = (handler->corner2 - handler->corner1).Normalize(); + onSketchPos = handler->corner1 + + vecL * onViewParameters[OnViewParameter::Fifth]->getValue(); + } + } + else { + if (onViewParameters[OnViewParameter::Sixth]->isSet) { + double thickness = onViewParameters[OnViewParameter::Sixth]->getValue(); + if (thickness < Precision::Confusion()) { + unsetOnViewParameter(onViewParameters[OnViewParameter::Sixth].get()); + } + else { + Base::Vector2d u = (handler->corner2 - handler->corner1).Normalize(); + Base::Vector2d v = (handler->corner4 - handler->corner1).Normalize(); + onSketchPos = handler->corner1 - u * thickness - v * thickness; + } + } + } + } + else if (handler->constructionMethod() == ConstructionMethod::ThreePoints) { + Base::Vector2d dir = onSketchPos - handler->corner2Initial; + double width = dir.Length(); + + if (onViewParameters[OnViewParameter::Fifth]->isSet) { + width = onViewParameters[OnViewParameter::Fifth]->getValue(); + if (width < Precision::Confusion()) { + unsetOnViewParameter(onViewParameters[OnViewParameter::Fifth].get()); + } + else { + if (dir.Length() < Precision::Confusion()) { + dir.x = 1; // if direction cannot be determined, default to (1,0) + } + + onSketchPos = handler->corner2Initial + width * dir.Normalize(); + } + } + if (onViewParameters[OnViewParameter::Sixth]->isSet) { + double angle = + onViewParameters[OnViewParameter::Sixth]->getValue() * M_PI / 180; + if (fmod(angle, M_PI) < Precision::Confusion()) { + unsetOnViewParameter(onViewParameters[OnViewParameter::Sixth].get()); + } + else { + int sign1 = handler->getPointSideOfVector(onSketchPos, + handler->corner2Initial + - handler->corner1, + handler->corner1); + + int sign = handler->side != sign1 ? 1 : -1; + + double angle123 = (handler->corner2Initial - handler->corner1).Angle() + + M_PI + sign * angle; + + onSketchPos.x = handler->corner2Initial.x + cos(angle123) * width; + onSketchPos.y = handler->corner2Initial.y + sin(angle123) * width; + } + } + } + else { + Base::Vector2d dir = onSketchPos - handler->corner1; + double width = dir.Length(); + if (onViewParameters[OnViewParameter::Fifth]->isSet) { + width = onViewParameters[OnViewParameter::Fifth]->getValue(); + if (width < Precision::Confusion()) { + unsetOnViewParameter(onViewParameters[OnViewParameter::Fifth].get()); + } + else { + if (dir.Length() < Precision::Confusion()) { + dir.x = 1; // if direction cannot be determined, default to (1,0) + } + + onSketchPos = handler->corner1 + width * dir.Normalize(); + } + } + if (onViewParameters[OnViewParameter::Sixth]->isSet) { + double c = onViewParameters[OnViewParameter::Sixth]->getValue() * M_PI / 180; + if (fmod(c, M_PI) < Precision::Confusion()) { + unsetOnViewParameter(onViewParameters[OnViewParameter::Sixth].get()); + } + else { + double a = asin(width * sin(M_PI - c) + / (handler->corner3 - handler->corner1).Length()); + + int sign1 = + handler->getPointSideOfVector(onSketchPos, + handler->corner3 - handler->corner1, + handler->corner1); + + int sign = handler->side != sign1 ? 1 : -1; + + double angle = + (handler->center - handler->corner1).Angle() + sign * (c - a); + + onSketchPos.x = handler->corner1.x + cos(angle) * width; + onSketchPos.y = handler->corner1.y + sin(angle) * width; + } + } + } + } break; + case SelectMode::SeekFourth: { + if (handler->constructionMethod() == ConstructionMethod::Diagonal + || handler->constructionMethod() == ConstructionMethod::CenterAndCorner) { + + if (onViewParameters[OnViewParameter::Sixth]->isSet) { + double thickness = onViewParameters[OnViewParameter::Sixth]->getValue(); + if (thickness < Precision::Confusion()) { + unsetOnViewParameter(onViewParameters[OnViewParameter::Sixth].get()); + } + else { + Base::Vector2d u = (handler->corner2 - handler->corner1).Normalize(); + Base::Vector2d v = (handler->corner4 - handler->corner1).Normalize(); + onSketchPos = handler->corner1 - u * thickness - v * thickness; + } + } + } + else { + if (handler->roundCorners) { + if (onViewParameters[OnViewParameter::Seventh]->isSet) { + double angleToUse = handler->angle412 / 2; + if (handler->constructionMethod() == ConstructionMethod::CenterAnd3Points) { + angleToUse = handler->angle123 / 2; + } + Base::Vector2d vecL = + (handler->corner2Initial - handler->corner1).Normalize(); + double L2 = onViewParameters[OnViewParameter::Seventh]->getValue() + / sqrt(1 - cos(angleToUse) * cos(angleToUse)); + onSketchPos = handler->corner1 + vecL * L2 * cos(angleToUse); + } + } + else { + if (onViewParameters[OnViewParameter::Eighth]->isSet) { + double thickness = onViewParameters[OnViewParameter::Eighth]->getValue(); + if (thickness < Precision::Confusion()) { + unsetOnViewParameter(onViewParameters[OnViewParameter::Eighth].get()); + } + else { + Base::Vector2d u = (handler->corner2 - handler->corner1).Normalize(); + Base::Vector2d v = (handler->corner4 - handler->corner1).Normalize(); + onSketchPos = handler->corner1 - u * thickness - v * thickness; + } + } + } + } + } break; + case SelectMode::SeekFifth: { + if (onViewParameters[OnViewParameter::Eighth]->isSet) { + double thickness = onViewParameters[OnViewParameter::Eighth]->getValue(); + if (thickness < Precision::Confusion()) { + unsetOnViewParameter(onViewParameters[OnViewParameter::Eighth].get()); + } + else { + Base::Vector2d u = (handler->corner2 - handler->corner1).Normalize(); + Base::Vector2d v = (handler->corner4 - handler->corner1).Normalize(); + onSketchPos = handler->corner1 - u * thickness - v * thickness; + } + } + } break; + default: + break; + } +} + +template<> +void DSHRectangleController::adaptParameters(Base::Vector2d onSketchPos) +{ + + // If checkboxes need synchronisation (they were changed by the DSH, e.g. by using 'M' to switch + // construction method), synchronise them and return. + if (syncCheckboxToHandler(WCheckbox::FirstBox, handler->roundCorners)) { + return; + } + + if (syncCheckboxToHandler(WCheckbox::SecondBox, handler->makeFrame)) { + return; + } + + switch (handler->state()) { + case SelectMode::SeekFirst: { + if (!onViewParameters[OnViewParameter::First]->isSet) { + onViewParameters[OnViewParameter::First]->setSpinboxValue(onSketchPos.x); + } + + if (!onViewParameters[OnViewParameter::Second]->isSet) { + onViewParameters[OnViewParameter::Second]->setSpinboxValue(onSketchPos.y); + } + + bool sameSign = onSketchPos.x * onSketchPos.y > 0.; + onViewParameters[OnViewParameter::First]->setLabelAutoDistanceReverse(!sameSign); + onViewParameters[OnViewParameter::Second]->setLabelAutoDistanceReverse(sameSign); + onViewParameters[OnViewParameter::First]->setPoints(Base::Vector3d(), + toVector3d(onSketchPos)); + onViewParameters[OnViewParameter::Second]->setPoints(Base::Vector3d(), + toVector3d(onSketchPos)); + } break; + case SelectMode::SeekSecond: { + if (handler->constructionMethod() == ConstructionMethod::Diagonal + || handler->constructionMethod() == ConstructionMethod::CenterAndCorner) { + if (!onViewParameters[OnViewParameter::Third]->isSet) { + double length = handler->cornersReversed ? handler->width : handler->length; + onViewParameters[OnViewParameter::Third]->setSpinboxValue(length); + } + + if (!onViewParameters[OnViewParameter::Fourth]->isSet) { + double width = handler->cornersReversed ? handler->length : handler->width; + onViewParameters[OnViewParameter::Fourth]->setSpinboxValue(width); + } + + Base::Vector3d start = toVector3d(handler->corner1); + Base::Vector3d vec = toVector3d(onSketchPos) - start; + bool sameSign = vec.x * vec.y > 0.; + + onViewParameters[OnViewParameter::Third]->setLabelAutoDistanceReverse(sameSign); + onViewParameters[OnViewParameter::Fourth]->setLabelAutoDistanceReverse(!sameSign); + + onViewParameters[OnViewParameter::Third]->setPoints( + start, + toVector3d(handler->cornersReversed ? handler->corner4 : handler->corner2)); + onViewParameters[OnViewParameter::Fourth]->setPoints( + start, + toVector3d(handler->cornersReversed ? handler->corner2 : handler->corner4)); + } + else if (handler->constructionMethod() == ConstructionMethod::ThreePoints) { + if (!onViewParameters[OnViewParameter::Third]->isSet) { + onViewParameters[OnViewParameter::Third]->setSpinboxValue(handler->length); + } + + onViewParameters[OnViewParameter::Third]->setPoints(toVector3d(handler->corner4), + toVector3d(handler->corner3)); + + if (!onViewParameters[OnViewParameter::Fourth]->isSet) { + onViewParameters[OnViewParameter::Fourth]->setSpinboxValue(handler->angle * 180 + / M_PI, + Base::Unit::Angle); + } + + onViewParameters[OnViewParameter::Fourth]->setPoints(toVector3d(handler->corner1), + Base::Vector3d()); + onViewParameters[OnViewParameter::Fourth]->setLabelRange( + (handler->corner2 - handler->corner1).Angle()); + } + else { + if (!onViewParameters[OnViewParameter::Third]->isSet) { + onViewParameters[OnViewParameter::Third]->setSpinboxValue(onSketchPos.x); + } + + if (!onViewParameters[OnViewParameter::Fourth]->isSet) { + onViewParameters[OnViewParameter::Fourth]->setSpinboxValue(onSketchPos.y); + } + + bool sameSign = onSketchPos.x * onSketchPos.y > 0.; + onViewParameters[OnViewParameter::Third]->setLabelAutoDistanceReverse(!sameSign); + onViewParameters[OnViewParameter::Fourth]->setLabelAutoDistanceReverse(sameSign); + onViewParameters[OnViewParameter::Third]->setPoints(Base::Vector3d(), + toVector3d(onSketchPos)); + onViewParameters[OnViewParameter::Fourth]->setPoints(Base::Vector3d(), + toVector3d(onSketchPos)); + } + } break; + case SelectMode::SeekThird: { + if (handler->constructionMethod() == ConstructionMethod::Diagonal + || handler->constructionMethod() == ConstructionMethod::CenterAndCorner) { + if (handler->roundCorners) { + if (!onViewParameters[OnViewParameter::Fifth]->isSet) { + onViewParameters[OnViewParameter::Fifth]->setSpinboxValue(handler->radius); + } + + Base::Vector3d center = handler->center3; + Base::Vector3d end = toVector3d(handler->corner3); + + if (handler->radius != 0.0) { + Base::Vector3d vec = (end - center).Normalize(); + end = center + vec * handler->radius; + } + + onViewParameters[OnViewParameter::Fifth]->setPoints(center, end); + } + else { + if (!onViewParameters[OnViewParameter::Sixth]->isSet) { + onViewParameters[OnViewParameter::Sixth]->setSpinboxValue( + handler->thickness); + } + + Base::Vector3d start = toVector3d(handler->corner3); + Base::Vector3d end = + Base::Vector3d(handler->corner3.x, handler->frameCorner3.y, 0.0); + onViewParameters[OnViewParameter::Sixth]->setPoints(start, end); + } + } + else { + onViewParameters[OnViewParameter::Third]->setPoints(toVector3d(handler->corner4), + toVector3d(handler->corner3)); + + bool threePoints = handler->constructionMethod() == ConstructionMethod::ThreePoints; + bool notReversed = threePoints && !handler->cornersReversed; + + if (!onViewParameters[OnViewParameter::Fifth]->isSet) { + onViewParameters[OnViewParameter::Fifth]->setSpinboxValue( + notReversed ? handler->width : handler->length); + } + + Base::Vector3d start = toVector3d(handler->corner1); + onViewParameters[OnViewParameter::Fifth]->setLabelAutoDistanceReverse(!notReversed); + onViewParameters[OnViewParameter::Fifth]->setPoints( + start, + toVector3d(notReversed ? handler->corner4 : handler->corner2)); + + + if (!onViewParameters[OnViewParameter::Sixth]->isSet) { + if (threePoints) { + double val = handler->angle123 * 180 / M_PI; + onViewParameters[OnViewParameter::Sixth]->setSpinboxValue( + val, + Base::Unit::Angle); + } + else { + double val = handler->angle412 * 180 / M_PI; + onViewParameters[OnViewParameter::Sixth]->setSpinboxValue( + val, + Base::Unit::Angle); + } + } + + if (threePoints) { + onViewParameters[OnViewParameter::Sixth]->setPoints( + toVector3d(notReversed ? handler->corner2 : handler->corner4), + Base::Vector3d()); + double startAngle = notReversed ? (handler->corner3 - handler->corner2).Angle() + : (handler->corner1 - handler->corner4).Angle(); + onViewParameters[OnViewParameter::Sixth]->setLabelStartAngle(startAngle); + onViewParameters[OnViewParameter::Sixth]->setLabelRange(handler->angle123); + } + else { + onViewParameters[OnViewParameter::Sixth]->setPoints( + toVector3d(handler->corner1), + Base::Vector3d()); + double startAngle = (handler->corner2 - handler->corner1).Angle(); + onViewParameters[OnViewParameter::Sixth]->setLabelStartAngle(startAngle); + onViewParameters[OnViewParameter::Sixth]->setLabelRange(handler->angle412); + } + } + + } break; + case SelectMode::SeekFourth: { + if (handler->constructionMethod() == ConstructionMethod::Diagonal + || handler->constructionMethod() == ConstructionMethod::CenterAndCorner) { + if (!onViewParameters[OnViewParameter::Sixth]->isSet) { + onViewParameters[OnViewParameter::Sixth]->setSpinboxValue(handler->thickness); + } + + Base::Vector3d start = toVector3d(handler->corner3); + Base::Vector3d end = + Base::Vector3d(handler->corner3.x, handler->frameCorner3.y, 0.0); + onViewParameters[OnViewParameter::Sixth]->setPoints(start, end); + } + else { + if (handler->roundCorners) { + if (!onViewParameters[OnViewParameter::Seventh]->isSet) { + onViewParameters[OnViewParameter::Seventh]->setSpinboxValue( + handler->radius); + } + + Base::Vector3d center = handler->center3; + Base::Vector3d end = toVector3d(handler->corner3); + + if (handler->radius != 0.0) { + Base::Vector3d vec = (end - center).Normalize(); + end = center + vec * handler->radius; + } + + onViewParameters[OnViewParameter::Seventh]->setPoints(center, end); + } + else { + if (!onViewParameters[OnViewParameter::Eighth]->isSet) { + onViewParameters[OnViewParameter::Eighth]->setSpinboxValue( + handler->thickness); + } + + Base::Vector3d start = toVector3d(handler->corner3); + Base::Vector3d vec = + toVector3d((handler->corner3 - handler->corner2).Normalize()); + Base::Vector3d end = start + handler->thickness * vec; + onViewParameters[OnViewParameter::Eighth]->setPoints(start, end); + } + } + } break; + case SelectMode::SeekFifth: { + if (!onViewParameters[OnViewParameter::Eighth]->isSet) { + onViewParameters[OnViewParameter::Eighth]->setSpinboxValue(handler->thickness); + } + + Base::Vector3d start = toVector3d(handler->corner3); + Base::Vector3d vec = toVector3d((handler->corner3 - handler->corner2).Normalize()); + Base::Vector3d end = start + handler->thickness * vec; + onViewParameters[OnViewParameter::Eighth]->setPoints(start, end); + } break; + default: + break; + } +} + +template<> +void DSHRectangleController::doChangeDrawSketchHandlerMode() +{ + switch (handler->state()) { + case SelectMode::SeekFirst: { + if (onViewParameters[OnViewParameter::First]->isSet + && onViewParameters[OnViewParameter::Second]->isSet) { + + handler->setState(SelectMode::SeekSecond); + } + } break; + case SelectMode::SeekSecond: { + if (onViewParameters[OnViewParameter::Third]->isSet + && onViewParameters[OnViewParameter::Fourth]->isSet) { + + if (handler->roundCorners || handler->makeFrame + || handler->constructionMethod() == ConstructionMethod::ThreePoints + || handler->constructionMethod() == ConstructionMethod::CenterAnd3Points) { + + handler->setState(SelectMode::SeekThird); + } + else { + handler->setState(SelectMode::End); + } + } + } break; + case SelectMode::SeekThird: { + if (handler->constructionMethod() == ConstructionMethod::Diagonal + || handler->constructionMethod() == ConstructionMethod::CenterAndCorner) { + if (handler->roundCorners && onViewParameters[OnViewParameter::Fifth]->isSet) { + + if (handler->makeFrame) { + handler->setState(SelectMode::SeekFourth); + } + else { + handler->setState(SelectMode::End); + } + } + else if (handler->makeFrame && onViewParameters[OnViewParameter::Sixth]->isSet) { + + handler->setState(SelectMode::End); + } + } + else { + if (onViewParameters[OnViewParameter::Fifth]->isSet + && onViewParameters[OnViewParameter::Sixth]->isSet) { + if (handler->roundCorners || handler->makeFrame) { + handler->setState(SelectMode::SeekFourth); + } + else { + handler->setState(SelectMode::End); + } + } + } + } break; + case SelectMode::SeekFourth: { + if (handler->constructionMethod() == ConstructionMethod::Diagonal + || handler->constructionMethod() == ConstructionMethod::CenterAndCorner) { + if (onViewParameters[OnViewParameter::Sixth]->isSet) { + handler->setState(SelectMode::End); + } + } + else { + if (handler->roundCorners && onViewParameters[OnViewParameter::Seventh]->isSet) { + + if (handler->makeFrame) { + handler->setState(SelectMode::SeekFifth); + } + else { + handler->setState(SelectMode::End); + } + } + else if (handler->makeFrame && onViewParameters[OnViewParameter::Eighth]->isSet) { + handler->setState(SelectMode::End); + } + } + } break; + case SelectMode::SeekFifth: { + if (handler->makeFrame && onViewParameters[OnViewParameter::Eighth]->isSet) { + handler->setState(SelectMode::End); + } + } break; + default: + break; + } +} + +template<> +void DSHRectangleController::addConstraints() +{ + App::DocumentObject* obj = handler->sketchgui->getObject(); + + int firstCurve = handler->firstCurve; + + auto x0 = onViewParameters[OnViewParameter::First]->getValue(); + auto y0 = onViewParameters[OnViewParameter::Second]->getValue(); + auto length = onViewParameters[OnViewParameter::Third]->getValue(); + auto width = onViewParameters[OnViewParameter::Fourth]->getValue(); + auto radius = onViewParameters[OnViewParameter::Fifth]->getValue(); + auto thickness = onViewParameters[OnViewParameter::Sixth]->getValue(); + + auto x0set = onViewParameters[OnViewParameter::First]->isSet; + auto y0set = onViewParameters[OnViewParameter::Second]->isSet; + auto lengthSet = onViewParameters[OnViewParameter::Third]->isSet; + auto widthSet = onViewParameters[OnViewParameter::Fourth]->isSet; + auto radiusSet = onViewParameters[OnViewParameter::Fifth]->isSet; + auto thicknessSet = onViewParameters[OnViewParameter::Sixth]->isSet; + + auto angle = onViewParameters[OnViewParameter::Fourth]->getValue() / 180 * M_PI; + auto innerAngle = onViewParameters[OnViewParameter::Sixth]->getValue() / 180 * M_PI; + + auto angleSet = onViewParameters[OnViewParameter::Fourth]->isSet; + auto innerAngleSet = onViewParameters[OnViewParameter::Sixth]->isSet; + + if (handler->constructionMethod() == ConstructionMethod::ThreePoints + || handler->constructionMethod() == ConstructionMethod::CenterAnd3Points) { + width = onViewParameters[OnViewParameter::Fifth]->getValue(); + radius = onViewParameters[OnViewParameter::Seventh]->getValue(); + thickness = onViewParameters[OnViewParameter::Eighth]->getValue(); + + widthSet = onViewParameters[OnViewParameter::Fifth]->isSet; + radiusSet = onViewParameters[OnViewParameter::Seventh]->isSet; + thicknessSet = onViewParameters[OnViewParameter::Eighth]->isSet; + } + + using namespace Sketcher; + + int firstPointId = firstCurve; + if (handler->constructionMethod() == ConstructionMethod::Diagonal + || handler->constructionMethod() == ConstructionMethod::ThreePoints) { + if (handler->radius > Precision::Confusion()) { + firstPointId = handler->constructionPointOneId; + } + } + else { + firstPointId = handler->centerPointId; + } + + auto constraintx0 = [&]() { + ConstraintToAttachment(GeoElementId(firstPointId, PointPos::start), + GeoElementId::VAxis, + x0, + obj); + }; + + auto constrainty0 = [&]() { + ConstraintToAttachment(GeoElementId(firstPointId, PointPos::start), + GeoElementId::HAxis, + y0, + obj); + }; + + auto constraintlength = [&]() { + int curveId = handler->cornersReversed ? firstCurve : firstCurve + 1; + + Gui::cmdAppObjectArgs(obj, + "addConstraint(Sketcher.Constraint('Distance',%d,%d,%d,%d,%f)) ", + curveId, + 1, + curveId + 2, + 2, + fabs(length)); + }; + + auto constraintwidth = [&]() { + int curveId = handler->cornersReversed ? firstCurve + 1 : firstCurve; + + Gui::cmdAppObjectArgs(obj, + "addConstraint(Sketcher.Constraint('Distance',%d,%d,%d,%d,%f)) ", + curveId, + 1, + curveId + 2, + 2, + fabs(width)); + }; + + // NOTE: if AutoConstraints is empty, we can add constraints directly without any diagnose. No + // diagnose was run. + if (handler->AutoConstraints.empty()) { + if (x0set) { + constraintx0(); + } + + if (y0set) { + constrainty0(); + } + + if (lengthSet) { + constraintlength(); + } + + if (widthSet) { + constraintwidth(); + } + } + else { // There is a valid diagnose. + auto firstpointinfo = handler->getPointInfo(GeoElementId(firstPointId, PointPos::start)); + + if (x0set && firstpointinfo.isXDoF()) { + constraintx0(); + + handler->diagnoseWithAutoConstraints(); // ensure we have recalculated parameters after + // each constraint addition + + firstpointinfo = handler->getPointInfo( + GeoElementId(firstPointId, PointPos::start)); // get updated point position + } + + if (y0set && firstpointinfo.isYDoF()) { + constrainty0(); + + handler->diagnoseWithAutoConstraints(); // ensure we have recalculated parameters after + // each constraint addition + } + + if (lengthSet) { + int curveId = handler->cornersReversed ? firstCurve : firstCurve + 1; + auto startpointinfo = handler->getPointInfo(GeoElementId(curveId, PointPos::start)); + auto endpointinfo = handler->getPointInfo(GeoElementId(curveId + 2, PointPos::end)); + + int DoFs = startpointinfo.getDoFs(); + DoFs += endpointinfo.getDoFs(); + + if (DoFs > 0) { + constraintlength(); + } + + handler->diagnoseWithAutoConstraints(); + } + + if (widthSet) { + int curveId = handler->cornersReversed ? firstCurve + 1 : firstCurve; + auto startpointinfo = handler->getPointInfo(GeoElementId(curveId, PointPos::start)); + auto endpointinfo = handler->getPointInfo(GeoElementId(curveId + 2, PointPos::end)); + + int DoFs = startpointinfo.getDoFs(); + DoFs += endpointinfo.getDoFs(); + + if (DoFs > 0) { + constraintwidth(); + } + } + } + + // NOTE: As of today, there are no autoconstraints on the radius or on the frame thickness, + // therefore, they are necessarily constrainable were applicable. + + if (handler->constructionMethod() == ConstructionMethod::ThreePoints + || handler->constructionMethod() == ConstructionMethod::CenterAnd3Points) { + + if (angleSet) { + if (fabs(angle - M_PI) < Precision::Confusion() + || fabs(angle + M_PI) < Precision::Confusion() + || fabs(angle) < Precision::Confusion()) { + Gui::cmdAppObjectArgs(obj, + "addConstraint(Sketcher.Constraint('Horizontal',%d)) ", + firstCurve); + } + else if (fabs(angle - M_PI / 2) < Precision::Confusion() + || fabs(angle + M_PI / 2) < Precision::Confusion()) { + Gui::cmdAppObjectArgs(obj, + "addConstraint(Sketcher.Constraint('Vertical',%d)) ", + firstCurve); + } + else { + Gui::cmdAppObjectArgs(obj, + "addConstraint(Sketcher.Constraint('Angle',%d,%d,%f)) ", + Sketcher::GeoEnum::HAxis, + firstCurve, + angle); + } + } + if (innerAngleSet) { + if (fabs(innerAngle - M_PI / 2) + > Precision::Confusion()) { // if 90? then perpendicular already created. + if (handler->constructionMethod() == ConstructionMethod::ThreePoints) { + Gui::cmdAppObjectArgs( + obj, + "addConstraint(Sketcher.Constraint('Angle',%d,%d,%d,%d,%f)) ", + firstCurve + 1, + 1, + firstCurve, + 2, + innerAngle); + } + else { + Gui::cmdAppObjectArgs( + obj, + "addConstraint(Sketcher.Constraint('Angle',%d,%d,%d,%d,%f)) ", + firstCurve, + 1, + firstCurve + 3, + 2, + innerAngle); + } + } + } + } + + if (radiusSet && radius > Precision::Confusion()) { + Gui::cmdAppObjectArgs(obj, + "addConstraint(Sketcher.Constraint('Radius',%d,%f)) ", + firstCurve + 5, + radius); + } + + if (thicknessSet) { + Gui::cmdAppObjectArgs(obj, + "addConstraint(Sketcher.Constraint('Distance',%d,%d,%d,%f)) ", + firstCurve + (handler->roundCorners == true ? 8 : 4), + 1, + firstCurve, + fabs(thickness)); + } +} + } // namespace SketcherGui diff --git a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc index f0ec6a7e20..5e67404fe2 100644 --- a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc +++ b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc @@ -143,6 +143,8 @@ icons/geometry/Sketcher_CreateElliptical_Arc.svg icons/geometry/Sketcher_CreateElliptical_Arc_Constr.svg icons/geometry/Sketcher_CreateFillet.svg + icons/geometry/Sketcher_CreateFrame.svg + icons/geometry/Sketcher_CreateFrame_Constr.svg icons/geometry/Sketcher_CreatePointFillet.svg icons/geometry/Sketcher_CreateHeptagon.svg icons/geometry/Sketcher_CreateHeptagon_Constr.svg @@ -173,6 +175,10 @@ icons/geometry/Sketcher_CreateRectangle_Constr.svg icons/geometry/Sketcher_CreateRectangle_Center.svg icons/geometry/Sketcher_CreateRectangle_Center_Constr.svg + icons/geometry/Sketcher_CreateRectangle3Points.svg + icons/geometry/Sketcher_CreateRectangle3Points_Constr.svg + icons/geometry/Sketcher_CreateRectangle3Points_Center.svg + icons/geometry/Sketcher_CreateRectangle3Points_Center_Constr.svg icons/geometry/Sketcher_CreateRegularPolygon.svg icons/geometry/Sketcher_CreateRegularPolygon_Constr.svg icons/geometry/Sketcher_CreateSlot.svg @@ -208,6 +214,7 @@ icons/pointers/Sketcher_Pointer_Create_ArcOfHyperbola.svg icons/pointers/Sketcher_Pointer_Create_ArcOfParabola.svg icons/pointers/Sketcher_Pointer_Create_Box.svg + icons/pointers/Sketcher_Pointer_Create_Box_Center.svg icons/pointers/Sketcher_Pointer_Create_BSpline.svg icons/pointers/Sketcher_Pointer_Create_Circle.svg icons/pointers/Sketcher_Pointer_Create_Ellipse.svg @@ -219,7 +226,12 @@ icons/pointers/Sketcher_Pointer_Extension.svg icons/pointers/Sketcher_Pointer_External.svg icons/pointers/Sketcher_Pointer_InsertKnot.svg + icons/pointers/Sketcher_Pointer_Create_Frame.svg + icons/pointers/Sketcher_Pointer_Create_Frame_Center.svg icons/pointers/Sketcher_Pointer_Oblong.svg + icons/pointers/Sketcher_Pointer_Oblong_Center.svg + icons/pointers/Sketcher_Pointer_Oblong_Frame.svg + icons/pointers/Sketcher_Pointer_Oblong_Frame_Center.svg icons/pointers/Sketcher_Pointer_Regular_Polygon.svg icons/pointers/Sketcher_Pointer_Slot.svg icons/pointers/Sketcher_Pointer_Splitting.svg diff --git a/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateFrame.svg b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateFrame.svg new file mode 100644 index 0000000000..f084ce6168 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateFrame.svg @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + [wmayer] + + + 2011-10-10 + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + FreeCAD + + + FreeCAD/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_CreateRectangle.svg + + + FreeCAD LGPL2+ + + + https://www.gnu.org/copyleft/lesser.html + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateFrame_Constr.svg b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateFrame_Constr.svg new file mode 100644 index 0000000000..7a34bbcc92 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateFrame_Constr.svg @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + [wmayer] + + + 2011-10-10 + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + FreeCAD + + + FreeCAD/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_CreateRectangle.svg + + + FreeCAD LGPL2+ + + + https://www.gnu.org/copyleft/lesser.html + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateRectangle3Points.svg b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateRectangle3Points.svg new file mode 100644 index 0000000000..5029aa18b4 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateRectangle3Points.svg @@ -0,0 +1,221 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + [wmayer] + + + 2011-10-10 + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + FreeCAD + + + FreeCAD/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_CreateRectangle.svg + + + FreeCAD LGPL2+ + + + https://www.gnu.org/copyleft/lesser.html + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateRectangle3Points_Center.svg b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateRectangle3Points_Center.svg new file mode 100644 index 0000000000..fbaa1f1489 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateRectangle3Points_Center.svg @@ -0,0 +1,221 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + [wmayer] + + + 2011-10-10 + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + FreeCAD + + + FreeCAD/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_CreateRectangle.svg + + + FreeCAD LGPL2+ + + + https://www.gnu.org/copyleft/lesser.html + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateRectangle3Points_Center_Constr.svg b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateRectangle3Points_Center_Constr.svg new file mode 100644 index 0000000000..1d499fb3f1 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateRectangle3Points_Center_Constr.svg @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + [wmayer] + + + 2011-10-10 + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + FreeCAD + + + FreeCAD/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_CreateRectangle.svg + + + FreeCAD LGPL2+ + + + https://www.gnu.org/copyleft/lesser.html + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateRectangle3Points_Constr.svg b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateRectangle3Points_Constr.svg new file mode 100644 index 0000000000..bdbbf9197d --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateRectangle3Points_Constr.svg @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + [wmayer] + + + 2011-10-10 + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + FreeCAD + + + FreeCAD/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_CreateRectangle.svg + + + FreeCAD LGPL2+ + + + https://www.gnu.org/copyleft/lesser.html + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Create_Box_Center.svg b/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Create_Box_Center.svg new file mode 100644 index 0000000000..b272bb2be3 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Create_Box_Center.svg @@ -0,0 +1,52 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Create_Frame.svg b/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Create_Frame.svg new file mode 100644 index 0000000000..51253a24a3 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Create_Frame.svg @@ -0,0 +1,63 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Create_Frame_Center.svg b/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Create_Frame_Center.svg new file mode 100644 index 0000000000..38ddc6c53c --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Create_Frame_Center.svg @@ -0,0 +1,60 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Oblong_Center.svg b/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Oblong_Center.svg new file mode 100644 index 0000000000..6a833f742f --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Oblong_Center.svg @@ -0,0 +1,48 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Oblong_Frame.svg b/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Oblong_Frame.svg new file mode 100644 index 0000000000..97ad28f9a9 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Oblong_Frame.svg @@ -0,0 +1,51 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Oblong_Frame_Center.svg b/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Oblong_Frame_Center.svg new file mode 100644 index 0000000000..6bfb142875 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Oblong_Frame_Center.svg @@ -0,0 +1,58 @@ + + + + + + image/svg+xml + + + + + + + + + + + + +