From cb19b1036e1da1c88a372c8a36eff7b932428f16 Mon Sep 17 00:00:00 2001 From: Paddle Date: Fri, 3 Nov 2023 18:36:20 +0100 Subject: [PATCH] Slot DSH : implement tool parameters. --- src/Mod/Sketcher/Gui/DrawSketchHandlerSlot.h | 837 ++++++++++++------- 1 file changed, 523 insertions(+), 314 deletions(-) diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerSlot.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerSlot.h index 6dd04f399b..40bb4e2d0c 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerSlot.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerSlot.h @@ -20,6 +20,7 @@ * * ***************************************************************************/ + #ifndef SKETCHERGUI_DrawSketchHandlerSlot_H #define SKETCHERGUI_DrawSketchHandlerSlot_H @@ -33,7 +34,8 @@ #include -#include "DrawSketchHandler.h" +#include "DrawSketchDefaultWidgetController.h" +#include "DrawSketchControllableHandler.h" #include "GeometryCreationMode.h" #include "Utils.h" #include "ViewProviderSketch.h" @@ -44,333 +46,540 @@ namespace SketcherGui extern GeometryCreationMode geometryCreationMode; // defined in CommandCreateGeo.cpp -class DrawSketchHandlerSlot: public DrawSketchHandler + +class DrawSketchHandlerSlot; + +using DSHSlotController = + DrawSketchDefaultWidgetController, + /*WidgetParametersT =*/WidgetParameters<0>, + /*WidgetCheckboxesT =*/WidgetCheckboxes<0>, + /*WidgetComboboxesT =*/WidgetComboboxes<0>>; + +using DSHSlotControllerBase = DSHSlotController::ControllerBase; + +using DrawSketchHandlerSlotBase = DrawSketchControllableHandler; + +class DrawSketchHandlerSlot: public DrawSketchHandlerSlotBase { + friend DSHSlotController; + friend DSHSlotControllerBase; + public: DrawSketchHandlerSlot() - : Mode(STATUS_SEEK_First) - , SnapMode(SNAP_MODE_Free) - , SnapDir(SNAP_DIR_Horz) - , dx(0) - , dy(0) - , r(0) - , EditCurve(35) + : radius(1.0) + , length(0.0) + , angle(0.0) + , isHorizontal(false) + , isVertical(false) + , firstCurve(0) {} - ~DrawSketchHandlerSlot() override - {} - /// mode table - enum BoxMode - { - STATUS_SEEK_First, /**< enum value ----. */ - STATUS_SEEK_Second, /**< enum value ----. */ - STATUS_End - }; - enum SNAP_MODE - { - SNAP_MODE_Free, - SNAP_MODE_Straight - }; - - enum SNAP_DIR - { - SNAP_DIR_Horz, - SNAP_DIR_Vert - }; - - 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) { - dx = onSketchPos.x - StartPos.x; - dy = onSketchPos.y - StartPos.y; - - if (QApplication::keyboardModifiers() == Qt::ControlModifier) { - SnapMode = SNAP_MODE_Straight; - } - else { - SnapMode = SNAP_MODE_Free; - } - - double a = 0; - double rev = 0; - if (fabs(dx) > fabs(dy)) { - r = fabs(dx) / 4; - rev = Base::sgn(dx); - SnapDir = SNAP_DIR_Horz; - if (SnapMode == SNAP_MODE_Straight) { - dy = 0; - } - } - else { - r = fabs(dy) / 4; - a = 8; - rev = Base::sgn(dy); - SnapDir = SNAP_DIR_Vert; - if (SnapMode == SNAP_MODE_Straight) { - dx = 0; - } - } - - // draw the arcs with each 16 segments - for (int i = 0; i < 17; i++) { - // first get the position at the arc - // if a is 0, the end points of the arc are at the y-axis, if it is 8, they are on - // the x-axis - double angle = (i + a) * M_PI / 16.0; - double rx = -r * rev * sin(angle); - double ry = r * rev * cos(angle); - // now apply the rotation matrix according to the angle between StartPos and - // onSketchPos - if (!(dx == 0 || dy == 0)) { - double rotAngle = atan(dy / dx); - if (a > 0) { - rotAngle = -atan(dx / dy); - } - double rxRot = rx * cos(rotAngle) - ry * sin(rotAngle); - double ryRot = rx * sin(rotAngle) + ry * cos(rotAngle); - rx = rxRot; - ry = ryRot; - } - EditCurve[i] = Base::Vector2d(StartPos.x + rx, StartPos.y + ry); - EditCurve[17 + i] = Base::Vector2d(StartPos.x + dx - rx, StartPos.y + dy - ry); - } - EditCurve[34] = EditCurve[0]; - - if (showCursorCoords()) { - SbString text; - std::string rString = lengthToDisplayFormat(r, 1); - std::string sqrtString = lengthToDisplayFormat(sqrt(dx * dx + dy * dy), 1); - text.sprintf(" (R%s L%s))", rString.c_str(), sqrtString.c_str()); - setPositionText(onSketchPos, text); - } - - drawEdit(EditCurve); - if (seekAutoConstraint(sugConstr2, - onSketchPos, - Base::Vector2d(dx, dy), - AutoConstraint::VERTEX_NO_TANGENCY)) { - renderSuggestConstraintsCursor(sugConstr2); - return; - } - } - applyCursor(); - } - - bool pressButton(Base::Vector2d onSketchPos) override - { - if (Mode == STATUS_SEEK_First) { - StartPos = onSketchPos; - Mode = STATUS_SEEK_Second; - } - else { - Mode = STATUS_End; - } - return true; - } - - bool releaseButton(Base::Vector2d onSketchPos) override - { - Q_UNUSED(onSketchPos); - if (Mode == STATUS_End) { - unsetCursor(); - resetPositionText(); - - int firstCurve = getHighestCurveIndex() + 1; - // add the geometry to the sketch - // first determine the rotation angle for the first arc - double start, end; - if (fabs(dx) > fabs(dy)) { - if (dx > 0) { - start = 0.5 * M_PI; - end = 1.5 * M_PI; - } - else { - start = 1.5 * M_PI; - end = 0.5 * M_PI; - } - } - else { - if (dy > 0) { - start = -M_PI; - end = 0; - } - else { - start = 0; - end = -M_PI; - } - } - - try { - Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add slot")); - - AutoConstraint lastCons = {Sketcher::None, - Sketcher::GeoEnum::GeoUndef, - Sketcher::PointPos::none}; - - if (!sugConstr2.empty()) { - lastCons = sugConstr2.back(); - } - - std::ostringstream snapCon = std::ostringstream(""); - if (SnapMode == SNAP_MODE_Straight) { - snapCon << "conList.append(Sketcher.Constraint('"; - if (SnapDir == SNAP_DIR_Horz) { - snapCon << "Horizontal"; - } - else { - snapCon << "Vertical"; - } - snapCon << "'," << firstCurve + 2 << "))\n"; - - // If horizontal/vertical already applied because of snap, do not duplicate with - // Autocontraint - if (lastCons.Type == Sketcher::Horizontal - || lastCons.Type == Sketcher::Vertical) { - sugConstr2.pop_back(); - } - } - else { - // If horizontal/vertical Autoconstraint suggested, applied it on first line - // (rather than last arc) - if (lastCons.Type == Sketcher::Horizontal - || lastCons.Type == Sketcher::Vertical) { - sugConstr2.back().GeoId = firstCurve + 2; - } - } - - Gui::Command::doCommand( - Gui::Command::Doc, - "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.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.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, 2, %i, 1))\n" - "conList.append(Sketcher.Constraint('Tangent', %i, 2, %i, 1))\n" - "conList.append(Sketcher.Constraint('Tangent', %i, 2, %i, 1))\n" - "conList.append(Sketcher.Constraint('Tangent', %i, 2, %i, 1))\n" - "conList.append(Sketcher.Constraint('Equal', %i, %i))\n" - "%s" - "%s.addConstraint(conList)\n" - "del geoList, conList\n", - StartPos.x, - StartPos.y, // center of the arc1 - r, // radius arc1 - start, - end, // start and end angle of arc1 - StartPos.x + dx, - StartPos.y + dy, // center of the arc2 - r, // radius arc2 - end, - end + M_PI, // start and end angle of arc2 - EditCurve[16].x, - EditCurve[16].y, - EditCurve[17].x, - EditCurve[17].y, // line1 - EditCurve[33].x, - EditCurve[33].y, - EditCurve[34].x, - EditCurve[34].y, // line2 - Gui::Command::getObjectCmd(sketchgui->getObject()).c_str(), // the sketch - constructionModeAsBooleanText(), // geometry as construction or not - firstCurve, - firstCurve + 2, // tangent1 - firstCurve + 2, - firstCurve + 1, // tangent2 - firstCurve + 1, - firstCurve + 3, // tangent3 - firstCurve + 3, - firstCurve, // tangent4 - firstCurve, - firstCurve + 1, // equal constraint - snapCon.str().c_str(), // horizontal/vertical constraint if snapping - Gui::Command::getObjectCmd(sketchgui->getObject()).c_str()); // the sketch - - Gui::Command::commitCommand(); - - // add auto constraints at the center of the first arc - if (!sugConstr1.empty()) { - createAutoConstraints(sugConstr1, - getHighestCurveIndex() - 3, - Sketcher::PointPos::mid); - sugConstr1.clear(); - } - - // add auto constraints at the center of the second arc - if (!sugConstr2.empty()) { - createAutoConstraints(sugConstr2, - getHighestCurveIndex() - 2, - Sketcher::PointPos::mid); - sugConstr2.clear(); - } - - tryAutoRecomputeIfNotSolve( - static_cast(sketchgui->getObject())); - } - catch (const Base::Exception&) { - Gui::NotifyError(sketchgui, - QT_TRANSLATE_NOOP("Notifications", "Error"), - QT_TRANSLATE_NOOP("Notifications", "Failed to add slot")); - - 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(35); - 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 - } - SnapMode = SNAP_MODE_Straight; - } - return true; - } + ~DrawSketchHandlerSlot() override = default; private: + void updateDataAndDrawToPosition(Base::Vector2d onSketchPos) override + { + switch (state()) { + case SelectMode::SeekFirst: { + startPoint = onSketchPos; + + if (seekAutoConstraint(sugConstraints[0], onSketchPos, Base::Vector2d(0.f, 0.f))) { + renderSuggestConstraintsCursor(sugConstraints[0]); + return; + } + } break; + case SelectMode::SeekSecond: { + secondPoint = onSketchPos; + angle = GetPointAngle(startPoint, secondPoint); + checkHorizontalVertical(); + length = (secondPoint - startPoint).Length(); + radius = length / 5; // radius chosen at 1/5 of length + + CreateAndDrawShapeGeometry(); + + if ((isHorizontal || isVertical) + && seekAutoConstraint(sugConstraints[1], + onSketchPos, + secondPoint - startPoint, + AutoConstraint::VERTEX_NO_TANGENCY)) { + renderSuggestConstraintsCursor(sugConstraints[1]); + return; + } + else if (seekAutoConstraint(sugConstraints[1], + onSketchPos, + Base::Vector2d(0.f, 0.f))) { + renderSuggestConstraintsCursor(sugConstraints[1]); + return; + } + } break; + case SelectMode::SeekThird: { + /*To follow the cursor, r should adapt depending on the position of the cursor. If + cursor is 'between' the center points, then its distance to that line and not + distance to the second center. A is "between" B and C if angle ?ABC and angle ?ACB + are both less than or equal to ninety degrees. An angle ?ABC is greater than ninety + degrees iff AB^2 + BC^2 < AC^2.*/ + + double L1 = (onSketchPos - startPoint) + .Length(); // distance between first center and onSketchPos + double L2 = (onSketchPos - secondPoint) + .Length(); // distance between second center and onSketchPos + + if ((L1 * L1 + length * length > L2 * L2) + && (L2 * L2 + length * length > L1 * L1)) { + // distance of onSketchPos to the line StartPos-SecondPos + radius = (abs((secondPoint.y - startPoint.y) * onSketchPos.x + - (secondPoint.x - startPoint.x) * onSketchPos.y + + secondPoint.x * startPoint.y - secondPoint.y * startPoint.x)) + / length; + } + else { + radius = std::min(L1, L2); + } + + CreateAndDrawShapeGeometry(); + } break; + default: + break; + } + } + + void executeCommands() override + { + firstCurve = getHighestCurveIndex() + 1; + + try { + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add slot")); + + createShape(false); + + commandAddShapeGeometryAndConstraints(); + + Gui::Command::commitCommand(); + } + catch (const Base::Exception& e) { + Gui::NotifyError(sketchgui, + QT_TRANSLATE_NOOP("Notifications", "Error"), + QT_TRANSLATE_NOOP("Notifications", "Failed to add slot")); + + Gui::Command::abortCommand(); + THROWM(Base::RuntimeError, + QT_TRANSLATE_NOOP( + "Notifications", + "Tool execution aborted") "\n") // This prevents constraints from being + // applied on non existing geometry + } + } + + void generateAutoConstraints() override + { + bool isHorizontalVertical = isHorizontal || isVertical; + + // add auto constraints for the center of 1st arc + generateAutoConstraintsOnElement(sugConstraints[0], + getHighestCurveIndex() - 3, + Sketcher::PointPos::mid); + + generateAutoConstraintsOnElement( + sugConstraints[1], + isHorizontalVertical ? getHighestCurveIndex() : getHighestCurveIndex() - 2, + isHorizontalVertical ? Sketcher::PointPos::none : Sketcher::PointPos::mid); + + // 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 + { + // execute python command to create autoconstraints + createGeneratedAutoConstraints(true); + + sugConstraints[0].clear(); + sugConstraints[1].clear(); + isHorizontal = false; + isVertical = false; + } + + std::string getToolName() const override + { + return "DSH_Slot"; + } + QString getCrosshairCursorSVGName() const override { return QString::fromLatin1("Sketcher_Pointer_Slot"); } -protected: - BoxMode Mode; - SNAP_MODE SnapMode; - SNAP_DIR SnapDir; - Base::Vector2d StartPos; - double dx, dy, r; - std::vector EditCurve; - std::vector sugConstr1, sugConstr2; + std::unique_ptr createWidget() const override + { + return std::make_unique(); + } + + bool canGoToNextMode() override + { + if (state() == SelectMode::SeekSecond && length < Precision::Confusion()) { + // Prevent validation of null slot. + return false; + } + + if (state() == SelectMode::SeekThird + && (length < Precision::Confusion() || radius < Precision::Confusion())) { + // Prevent validation of null slot. + return false; + } + + return true; + } + + void angleSnappingControl() override + { + if (state() == SelectMode::SeekSecond) { + setAngleSnapping(true, startPoint); + } + + else { + setAngleSnapping(false); + } + } + + void createShape(bool onlyeditoutline) override + { + ShapeGeometry.clear(); + + if (length < Precision::Confusion() || radius < Precision::Confusion()) { + return; + } + + auto arc1 = std::make_unique(); + arc1->setRadius(radius); + arc1->setRange(M_PI / 2 + angle, 1.5 * M_PI + angle, true); + arc1->setCenter(toVector3d(startPoint)); + Sketcher::GeometryFacade::setConstruction(arc1.get(), isConstructionMode()); + + auto arc2 = std::make_unique(); + arc2->setRadius(radius); + arc2->setRange(1.5 * M_PI + angle, M_PI / 2 + angle, true); + arc2->setCenter(toVector3d(secondPoint)); + Sketcher::GeometryFacade::setConstruction(arc2.get(), isConstructionMode()); + + Base::Vector3d p11 = arc1->getStartPoint(); + Base::Vector3d p12 = arc1->getEndPoint(); + Base::Vector3d p21 = arc2->getStartPoint(); + Base::Vector3d p22 = arc2->getEndPoint(); + + ShapeGeometry.push_back(std::move(arc1)); + ShapeGeometry.push_back(std::move(arc2)); + + addLineToShapeGeometry(p11, p22, isConstructionMode()); + + addLineToShapeGeometry(p12, p21, isConstructionMode()); + + if (!onlyeditoutline) { + addToShapeConstraints(Sketcher::Tangent, + firstCurve, + Sketcher::PointPos::start, + firstCurve + 2, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Tangent, + firstCurve, + Sketcher::PointPos::end, + firstCurve + 3, + Sketcher::PointPos::start); + addToShapeConstraints(Sketcher::Tangent, + firstCurve + 1, + Sketcher::PointPos::end, + firstCurve + 2, + Sketcher::PointPos::end); + addToShapeConstraints(Sketcher::Tangent, + firstCurve + 1, + Sketcher::PointPos::start, + firstCurve + 3, + Sketcher::PointPos::end); + addToShapeConstraints(Sketcher::Equal, + firstCurve, + Sketcher::PointPos::none, + firstCurve + 1); + } + } + + void checkHorizontalVertical() + { + if (fmod(angle, M_PI) < Precision::Confusion()) { + isHorizontal = true; + isVertical = false; + } + else if (fmod(angle + M_PI / 2, M_PI) < Precision::Confusion()) { + isHorizontal = false; + isVertical = true; + } + } + +private: + Base::Vector2d startPoint, secondPoint; + double radius, length, angle; + bool isHorizontal, isVertical; + int firstCurve; }; +template<> +auto DSHSlotControllerBase::getState(int labelindex) const +{ + 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; + default: + THROWM(Base::ValueError, "OnViewParameter index without an associated machine state") + } +} + +template<> +void DSHSlotController::configureToolWidget() +{ + onViewParameters[OnViewParameter::First]->setLabelType(Gui::SoDatumLabel::DISTANCEX); + onViewParameters[OnViewParameter::Second]->setLabelType(Gui::SoDatumLabel::DISTANCEY); + onViewParameters[OnViewParameter::Third]->setLabelType( + Gui::SoDatumLabel::DISTANCE, + Gui::EditableDatumLabel::Function::Dimensioning); + onViewParameters[OnViewParameter::Fourth]->setLabelType( + Gui::SoDatumLabel::ANGLE, + Gui::EditableDatumLabel::Function::Dimensioning); + onViewParameters[OnViewParameter::Fifth]->setLabelType( + Gui::SoDatumLabel::RADIUS, + Gui::EditableDatumLabel::Function::Dimensioning); +} + +template<> +void DSHSlotControllerBase::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: { + Base::Vector2d dir = onSketchPos - handler->startPoint; + if (dir.Length() < Precision::Confusion()) { + dir.x = 1.0; // if direction null, default to (1,0) + } + double length = dir.Length(); + + if (onViewParameters[OnViewParameter::Third]->isSet) { + length = onViewParameters[OnViewParameter::Third]->getValue(); + if (length < Precision::Confusion()) { + unsetOnViewParameter(onViewParameters[OnViewParameter::Third].get()); + return; + } + + onSketchPos = handler->startPoint + length * dir.Normalize(); + } + + if (onViewParameters[OnViewParameter::Fourth]->isSet) { + double angle = onViewParameters[OnViewParameter::Fourth]->getValue() * M_PI / 180; + onSketchPos.x = handler->startPoint.x + cos(angle) * length; + onSketchPos.y = handler->startPoint.y + sin(angle) * length; + } + } break; + case SelectMode::SeekThird: { + if (onViewParameters[OnViewParameter::Fifth]->isSet) { + double radius = onViewParameters[OnViewParameter::Fifth]->getValue(); + + if (radius < Precision::Confusion()) { + unsetOnViewParameter(onViewParameters[OnViewParameter::Fifth].get()); + return; + } + + onSketchPos.x = handler->secondPoint.x + cos(handler->angle) * radius; + onSketchPos.y = handler->secondPoint.y + sin(handler->angle) * radius; + } + } break; + default: + break; + } +} + +template<> +void DSHSlotController::adaptParameters(Base::Vector2d onSketchPos) +{ + switch (handler->state()) { + case SelectMode::SeekFirst: { + if (!onViewParameters[OnViewParameter::First]->isSet) { + setOnViewParameterValue(OnViewParameter::First, onSketchPos.x); + } + + if (!onViewParameters[OnViewParameter::Second]->isSet) { + setOnViewParameterValue(OnViewParameter::Second, 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: { + Base::Vector3d start = toVector3d(handler->startPoint); + Base::Vector3d end = toVector3d(handler->secondPoint); + Base::Vector3d vec = end - start; + + if (!onViewParameters[OnViewParameter::Third]->isSet) { + onViewParameters[OnViewParameter::Third]->setSpinboxValue(vec.Length()); + } + + double range = (handler->secondPoint - handler->startPoint).Angle(); + if (!onViewParameters[OnViewParameter::Fourth]->isSet) { + onViewParameters[OnViewParameter::Fourth]->setSpinboxValue(range * 180 / M_PI, + Base::Unit::Angle); + } + + onViewParameters[OnViewParameter::Third]->setPoints(start, end); + onViewParameters[OnViewParameter::Fourth]->setPoints(start, Base::Vector3d()); + onViewParameters[OnViewParameter::Fourth]->setLabelRange(range); + } break; + case SelectMode::SeekThird: { + if (!onViewParameters[OnViewParameter::Fifth]->isSet) { + setOnViewParameterValue(OnViewParameter::Fifth, handler->radius); + } + + Base::Vector3d labelSecondPoint = Base::Vector3d(); + labelSecondPoint.x = handler->secondPoint.x + cos(handler->angle) * handler->radius; + labelSecondPoint.y = handler->secondPoint.y + sin(handler->angle) * handler->radius; + + onViewParameters[OnViewParameter::Fifth]->setPoints(toVector3d(handler->secondPoint), + labelSecondPoint); + + } break; + default: + break; + } +} + +template<> +void DSHSlotController::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) { + + handler->setState(SelectMode::SeekThird); + } + } break; + case SelectMode::SeekThird: { + if (onViewParameters[OnViewParameter::Fifth]->isSet) { + + handler->setState(SelectMode::End); + } + } break; + default: + break; + } +} + +template<> +void DSHSlotController::addConstraints() +{ + App::DocumentObject* obj = handler->sketchgui->getObject(); + + int firstCurve = handler->getHighestCurveIndex() - 3; + + auto x0 = onViewParameters[OnViewParameter::First]->getValue(); + auto y0 = onViewParameters[OnViewParameter::Second]->getValue(); + + auto x0set = onViewParameters[OnViewParameter::First]->isSet; + auto y0set = onViewParameters[OnViewParameter::Second]->isSet; + auto lengthSet = onViewParameters[OnViewParameter::Third]->isSet; + auto angleSet = onViewParameters[OnViewParameter::Fourth]->isSet; + auto radiusSet = onViewParameters[OnViewParameter::Fifth]->isSet; + + using namespace Sketcher; + + if (x0set && y0set && x0 == 0. && y0 == 0.) { + ConstraintToAttachment(GeoElementId(firstCurve, PointPos::mid), + GeoElementId::RtPnt, + x0, + handler->sketchgui->getObject()); + } + else { + if (x0set) { + ConstraintToAttachment(GeoElementId(firstCurve, PointPos::mid), + GeoElementId::VAxis, + x0, + handler->sketchgui->getObject()); + } + + if (y0set) { + ConstraintToAttachment(GeoElementId(firstCurve, PointPos::mid), + GeoElementId::HAxis, + y0, + handler->sketchgui->getObject()); + } + } + + if (lengthSet) { + Gui::cmdAppObjectArgs(obj, + "addConstraint(Sketcher.Constraint('Distance',%d,%d,%d,%d,%f)) ", + firstCurve, + 3, + firstCurve + 1, + 3, + handler->length); + } + + if (angleSet) { + handler->checkHorizontalVertical(); + if (handler->isHorizontal) { + Gui::cmdAppObjectArgs(obj, + "addConstraint(Sketcher.Constraint('Horizontal',%d)) ", + firstCurve + 2); + } + else if (handler->isVertical) { + Gui::cmdAppObjectArgs(obj, + "addConstraint(Sketcher.Constraint('Vertical',%d)) ", + firstCurve + 2); + } + else { + Gui::cmdAppObjectArgs(obj, + "addConstraint(Sketcher.Constraint('Angle',%d,%d,%f)) ", + Sketcher::GeoEnum::HAxis, + firstCurve + 2, + handler->angle); + } + } + + if (radiusSet) { + Gui::cmdAppObjectArgs(obj, + "addConstraint(Sketcher.Constraint('Radius',%d,%f)) ", + firstCurve, + handler->radius); + } +} } // namespace SketcherGui