diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h index db6d16e073..7d004ca9a5 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h @@ -19,173 +19,708 @@ * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ + + #ifndef SKETCHERGUI_DrawSketchHandlerLine_H #define SKETCHERGUI_DrawSketchHandlerLine_H -#include +#include "DrawSketchDefaultWidgetController.h" +#include "DrawSketchControllableHandler.h" #include "GeometryCreationMode.h" - +#include "Utils.h" namespace SketcherGui { extern GeometryCreationMode geometryCreationMode; // defined in CommandCreateGeo.cpp -class DrawSketchHandlerLine: public DrawSketchHandler +class DrawSketchHandlerLine; + +namespace ConstructionMethods { + +enum class LineConstructionMethod +{ + OnePointLengthAngle, + OnePointLengthWidth, + TwoPoints, + End // Must be the last one +}; + +} + +using DSHLineController = + DrawSketchDefaultWidgetController, + /*WidgetParametersT =*/WidgetParameters<0, 0, 0>, + /*WidgetCheckboxesT =*/WidgetCheckboxes<0, 0, 0>, + /*WidgetComboboxesT =*/WidgetComboboxes<1, 1, 1>, + ConstructionMethods::LineConstructionMethod, + /*bool PFirstComboboxIsConstructionMethod =*/true>; + +using DSHLineControllerBase = DSHLineController::ControllerBase; + +using DrawSketchHandlerLineBase = DrawSketchControllableHandler; + + +class DrawSketchHandlerLine: public DrawSketchHandlerLineBase +{ + friend DSHLineController; + friend DSHLineControllerBase; + public: - DrawSketchHandlerLine() - : Mode(STATUS_SEEK_First) - , EditCurve(2) - {} - ~DrawSketchHandlerLine() override - {} - /// mode table - enum SelectMode - { - STATUS_SEEK_First, /**< enum value ----. */ - STATUS_SEEK_Second, /**< enum value ----. */ - STATUS_End - }; + DrawSketchHandlerLine(ConstructionMethod constrMethod = ConstructionMethod::OnePointLengthAngle) + : DrawSketchHandlerLineBase(constrMethod) {}; + ~DrawSketchHandlerLine() override = default; - void mouseMove(Base::Vector2d onSketchPos) override +private: + void updateDataAndDrawToPosition(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) { - float length = (onSketchPos - EditCurve[0]).Length(); - float angle = (onSketchPos - EditCurve[0]).GetAngle(Base::Vector2d(1.f, 0.f)); - if (showCursorCoords()) { - SbString text; - std::string lengthString = lengthToDisplayFormat(length, 1); - std::string angleString = angleToDisplayFormat(angle * 180.0 / M_PI, 1); - text.sprintf(" (%s, %s)", lengthString.c_str(), angleString.c_str()); - setPositionText(onSketchPos, text); - } + switch (state()) { + case SelectMode::SeekFirst: { + startPoint = onSketchPos; - EditCurve[1] = onSketchPos; - drawEdit(EditCurve); - if (seekAutoConstraint(sugConstr2, onSketchPos, onSketchPos - EditCurve[0])) { - renderSuggestConstraintsCursor(sugConstr2); - return; - } + if (seekAutoConstraint(sugConstraints[0], onSketchPos, Base::Vector2d(0.f, 0.f))) { + renderSuggestConstraintsCursor(sugConstraints[0]); + return; + } + } break; + case SelectMode::SeekSecond: { + endPoint = onSketchPos; + + try { + CreateAndDrawShapeGeometry(); + } + catch (const Base::ValueError&) { + } // equal points while hovering raise an objection that can be safely ignored + + if (seekAutoConstraint(sugConstraints[1], onSketchPos, onSketchPos - startPoint)) { + renderSuggestConstraintsCursor(sugConstraints[1]); + return; + } + } break; + default: + break; } - applyCursor(); } - bool pressButton(Base::Vector2d onSketchPos) override + void executeCommands() override { - if (Mode == STATUS_SEEK_First) { - EditCurve[0] = onSketchPos; + try { + createShape(false); - setAngleSnapping(true, EditCurve[0]); - Mode = STATUS_SEEK_Second; + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add sketch line")); + + commandAddShapeGeometryAndConstraints(); + + Gui::Command::commitCommand(); + } + catch (const Base::Exception& e) { + Gui::NotifyError(sketchgui, + QT_TRANSLATE_NOOP("Notifications", "Error"), + QT_TRANSLATE_NOOP("Notifications", "Failed to add line")); + + 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 + { + int LineGeoId = getHighestCurveIndex(); + + // Generate temporary autoconstraints (but do not actually add them to the sketch) + if (avoidRedundants) { + removeRedundantHorizontalVertical(getSketchObject(), + sugConstraints[0], + sugConstraints[1]); + } + + auto& ac1 = sugConstraints[0]; + auto& ac2 = sugConstraints[1]; + + generateAutoConstraintsOnElement(ac1, LineGeoId, Sketcher::PointPos::start); + generateAutoConstraintsOnElement(ac2, LineGeoId, Sketcher::PointPos::end); + + // 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(); + } + + std::string getToolName() const override + { + return "DSH_Line"; + } + + QString getCrosshairCursorSVGName() const override + { + if (constructionMethod() == ConstructionMethod::OnePointLengthAngle) { + return QString::fromLatin1("Sketcher_Pointer_Create_Line_Polar"); } else { - EditCurve[1] = onSketchPos; - drawEdit(EditCurve); - setAngleSnapping(false); - Mode = STATUS_End; + return QString::fromLatin1("Sketcher_Pointer_Create_Line.svg"); + } + } + + 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_CreateLine"); + } + + QString getToolWidgetText() const override + { + return QString(QObject::tr("Line parameters")); + } + + bool canGoToNextMode() override + { + if (state() == SelectMode::SeekSecond && length < Precision::Confusion()) { + // Prevent validation of null line. + return false; } return true; } - bool releaseButton(Base::Vector2d onSketchPos) override + void angleSnappingControl() override { - Q_UNUSED(onSketchPos); - if (Mode == STATUS_End) { - unsetCursor(); - resetPositionText(); - - try { - Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add sketch line")); - Gui::cmdAppObjectArgs( - sketchgui->getObject(), - "addGeometry(Part.LineSegment(App.Vector(%f,%f,0),App.Vector(%f,%f,0)),%s)", - EditCurve[0].x, - EditCurve[0].y, - EditCurve[1].x, - EditCurve[1].y, - geometryCreationMode == Construction ? "True" : "False"); - - Gui::Command::commitCommand(); - } - catch (const Base::Exception&) { - Gui::NotifyError(sketchgui, - QT_TRANSLATE_NOOP("Notifications", "Error"), - QT_TRANSLATE_NOOP("Notifications", "Failed to add line")); - - Gui::Command::abortCommand(); - } - - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( - "User parameter:BaseApp/Preferences/Mod/Sketcher"); - bool avoidredundant = - sketchgui->AvoidRedundant.getValue() && sketchgui->Autoconstraints.getValue(); - - if (avoidredundant) { - removeRedundantHorizontalVertical( - static_cast(sketchgui->getObject()), - sugConstr1, - sugConstr2); - } - - // add auto constraints for the line segment start - if (!sugConstr1.empty()) { - createAutoConstraints(sugConstr1, - getHighestCurveIndex(), - Sketcher::PointPos::start); - sugConstr1.clear(); - } - - // add auto constraints for the line segment end - if (!sugConstr2.empty()) { - createAutoConstraints(sugConstr2, getHighestCurveIndex(), Sketcher::PointPos::end); - sugConstr2.clear(); - } - - tryAutoRecomputeIfNotSolve( - static_cast(sketchgui->getObject())); - - EditCurve.clear(); - drawEdit(EditCurve); - - bool continuousMode = hGrp->GetBool("ContinuousCreationMode", true); - if (continuousMode) { - // This code enables the continuous creation mode. - Mode = STATUS_SEEK_First; - EditCurve.resize(2); - applyCursor(); - /* It 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::SeekSecond) { + setAngleSnapping(true, startPoint); + } + + else { + setAngleSnapping(false); } - return true; } private: - QString getCrosshairCursorSVGName() const override + Base::Vector2d startPoint, endPoint; + double length; + + void createShape(bool onlyeditoutline) override { - return QString::fromLatin1("Sketcher_Pointer_Create_Line"); + Q_UNUSED(onlyeditoutline); + ShapeGeometry.clear(); + + Base::Vector2d vecL = endPoint - startPoint; + length = vecL.Length(); + if (length > Precision::Confusion()) { + + addLineToShapeGeometry(toVector3d(startPoint), + toVector3d(endPoint), + isConstructionMode()); + } + } +}; + +template<> +auto DSHLineControllerBase::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; + default: + THROWM(Base::ValueError, "Label index without an associated machine state") + } +} + +template<> +void DSHLineController::configureToolWidget() +{ + if (!init) { // Code to be executed only upon initialisation + QStringList names = {QStringLiteral("Point, length, angle"), + QStringLiteral("Point, length, width"), + QStringLiteral("2 points")}; + toolWidget->setComboboxElements(WCombobox::FirstCombo, names); + + if (isConstructionMode()) { + toolWidget->setComboboxItemIcon( + WCombobox::FirstCombo, + 0, + Gui::BitmapFactory().iconFromTheme("Sketcher_CreateLineAngleLength_Constr")); + toolWidget->setComboboxItemIcon( + WCombobox::FirstCombo, + 1, + Gui::BitmapFactory().iconFromTheme("Sketcher_CreateLineLengthWidth_Constr")); + toolWidget->setComboboxItemIcon( + WCombobox::FirstCombo, + 2, + Gui::BitmapFactory().iconFromTheme("Sketcher_CreateLine_Constr")); + } + else { + toolWidget->setComboboxItemIcon( + WCombobox::FirstCombo, + 0, + Gui::BitmapFactory().iconFromTheme("Sketcher_CreateLineAngleLength")); + toolWidget->setComboboxItemIcon( + WCombobox::FirstCombo, + 1, + Gui::BitmapFactory().iconFromTheme("Sketcher_CreateLineLengthWidth")); + toolWidget->setComboboxItemIcon( + WCombobox::FirstCombo, + 2, + Gui::BitmapFactory().iconFromTheme("Sketcher_CreateLine")); + } } -protected: - SelectMode Mode; - std::vector EditCurve; - std::vector sugConstr1, sugConstr2; -}; + onViewParameters[OnViewParameter::First]->setLabelType(Gui::SoDatumLabel::DISTANCEX); + onViewParameters[OnViewParameter::Second]->setLabelType(Gui::SoDatumLabel::DISTANCEY); + + if (handler->constructionMethod() == ConstructionMethod::OnePointLengthAngle) { + onViewParameters[OnViewParameter::Fourth]->setLabelType(Gui::SoDatumLabel::ANGLE); + } + else { + onViewParameters[OnViewParameter::Third]->setLabelType(Gui::SoDatumLabel::DISTANCEX); + onViewParameters[OnViewParameter::Fourth]->setLabelType(Gui::SoDatumLabel::DISTANCEY); + } +} + + +template<> +void DSHLineControllerBase::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::OnePointLengthWidth) { + if (onViewParameters[OnViewParameter::Third]->isSet) { + onSketchPos.x = handler->startPoint.x + + onViewParameters[OnViewParameter::Third]->getValue(); + } + + if (onViewParameters[OnViewParameter::Fourth]->isSet) { + onSketchPos.y = handler->startPoint.y + + onViewParameters[OnViewParameter::Fourth]->getValue(); + } + } + else if (handler->constructionMethod() == ConstructionMethod::OnePointLengthAngle) { + + Base::Vector2d dir = onSketchPos - handler->startPoint; + 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->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; + } + } + else { + if (onViewParameters[OnViewParameter::Third]->isSet) { + onSketchPos.x = onViewParameters[OnViewParameter::Third]->getValue(); + } + if (onViewParameters[OnViewParameter::Fourth]->isSet) { + onSketchPos.y = onViewParameters[OnViewParameter::Fourth]->getValue(); + } + } + } break; + default: + break; + } +} + +template<> +void DSHLineController::adaptParameters(Base::Vector2d onSketchPos) +{ + 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::OnePointLengthWidth) { + Base::Vector3d start = toVector3d(handler->startPoint); + Base::Vector3d end = toVector3d(handler->endPoint); + Base::Vector3d vec = end - start; + + if (!onViewParameters[OnViewParameter::Third]->isSet) { + onViewParameters[OnViewParameter::Third]->setSpinboxValue(vec.x); + } + + if (!onViewParameters[OnViewParameter::Fourth]->isSet) { + onViewParameters[OnViewParameter::Fourth]->setSpinboxValue(vec.y); + } + + bool sameSign = vec.x * vec.y > 0.; + + onViewParameters[OnViewParameter::Third]->setLabelAutoDistanceReverse(!sameSign); + onViewParameters[OnViewParameter::Fourth]->setLabelAutoDistanceReverse(sameSign); + + onViewParameters[OnViewParameter::Third]->setPoints(start, end); + onViewParameters[OnViewParameter::Fourth]->setPoints(start, end); + } + else if (handler->constructionMethod() == ConstructionMethod::OnePointLengthAngle) { + Base::Vector3d start = toVector3d(handler->startPoint); + Base::Vector3d end = toVector3d(handler->endPoint); + Base::Vector3d vec = end - start; + + if (!onViewParameters[OnViewParameter::Third]->isSet) { + onViewParameters[OnViewParameter::Third]->setSpinboxValue(vec.Length()); + } + + double range = (handler->endPoint - 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); + } + 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; + default: + break; + } +} + +template<> +void DSHLineController::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::End); + } + } break; + default: + break; + } +} + +// Function responsible to add widget mandated constraints (it is executed before creating +// autoconstraints) +template<> +void DSHLineController::addConstraints() +{ + App::DocumentObject* obj = handler->sketchgui->getObject(); + + int firstCurve = handler->getHighestCurveIndex(); + + auto x0 = onViewParameters[OnViewParameter::First]->getValue(); + auto y0 = onViewParameters[OnViewParameter::Second]->getValue(); + auto p3 = onViewParameters[OnViewParameter::Third]->getValue(); + auto p4 = onViewParameters[OnViewParameter::Fourth]->getValue(); + + auto x0set = onViewParameters[OnViewParameter::First]->isSet; + auto y0set = onViewParameters[OnViewParameter::Second]->isSet; + auto p3set = onViewParameters[OnViewParameter::Third]->isSet; + auto p4set = onViewParameters[OnViewParameter::Fourth]->isSet; + + using namespace Sketcher; + + auto constraintToOrigin = [&]() { + ConstraintToAttachment(GeoElementId(firstCurve, PointPos::start), + GeoElementId::RtPnt, + x0, + obj); + }; + + auto constraintx0 = [&]() { + ConstraintToAttachment(GeoElementId(firstCurve, PointPos::start), + GeoElementId::VAxis, + x0, + obj); + }; + + auto constrainty0 = [&]() { + ConstraintToAttachment(GeoElementId(firstCurve, PointPos::start), + GeoElementId::HAxis, + y0, + obj); + }; + + auto constraintp3DistanceX = [&]() { + if (fabs(p3) < Precision::Confusion()) { + Gui::cmdAppObjectArgs(obj, + "addConstraint(Sketcher.Constraint('Vertical',%d)) ", + firstCurve); + } + else { + Gui::cmdAppObjectArgs(obj, + "addConstraint(Sketcher.Constraint('DistanceX',%d,%d,%d,%d,%f)) ", + firstCurve, + 1, + firstCurve, + 2, + fabs(p3)); + } + }; + + auto constraintp3length = [&]() { + Gui::cmdAppObjectArgs(obj, + "addConstraint(Sketcher.Constraint('Distance',%d,%f)) ", + firstCurve, + fabs(p3)); + }; + + auto constraintp3x = [&]() { + ConstraintToAttachment(GeoElementId(firstCurve, PointPos::end), + GeoElementId::VAxis, + p3, + obj); + }; + + auto constraintp4DistanceY = [&]() { + if (fabs(p4) < Precision::Confusion()) { + Gui::cmdAppObjectArgs(obj, + "addConstraint(Sketcher.Constraint('Horizontal',%d)) ", + firstCurve); + } + else { + Gui::cmdAppObjectArgs(obj, + "addConstraint(Sketcher.Constraint('DistanceY',%d,%d,%d,%d,%f)) ", + firstCurve, + 1, + firstCurve, + 2, + fabs(p4)); + } + }; + + auto constraintp4angle = [&]() { + double angle = p4 / 180 * M_PI; + 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); + } + }; + + auto constraintp4y = [&]() { + ConstraintToAttachment(GeoElementId(firstCurve, PointPos::end), + GeoElementId::HAxis, + p4, + obj); + }; + + if (handler->AutoConstraints.empty()) { // No valid diagnosis. Every constraint can be added. + + if (x0set && y0set && x0 == 0. && y0 == 0.) { + constraintToOrigin(); + } + else { + if (x0set) { + constraintx0(); + } + + if (y0set) { + constrainty0(); + } + } + + if (handler->constructionMethod() + == DrawSketchHandlerLine::ConstructionMethod::OnePointLengthWidth) { + if (p3set) { + constraintp3DistanceX(); + } + + if (p4set) { + constraintp4DistanceY(); + } + } + else if (handler->constructionMethod() + == DrawSketchHandlerLine::ConstructionMethod::OnePointLengthAngle) { + if (p3set) { + constraintp3length(); + } + + if (p4set) { + constraintp4angle(); + } + } + else { + if (p3set) { + constraintp3x(); + } + + if (p4set) { + constraintp4y(); + } + } + } + else { // Valid diagnosis. Must check which constraints may be added. + auto startpointinfo = handler->getPointInfo(GeoElementId(firstCurve, PointPos::start)); + + if (x0set && startpointinfo.isXDoF()) { + constraintx0(); + + handler->diagnoseWithAutoConstraints(); // ensure we have recalculated parameters after + // each constraint addition + + startpointinfo = handler->getPointInfo( + GeoElementId(firstCurve, PointPos::start)); // get updated point position + } + + if (y0set && startpointinfo.isYDoF()) { + constrainty0(); + + handler->diagnoseWithAutoConstraints(); // ensure we have recalculated parameters after + // each constraint addition + + startpointinfo = handler->getPointInfo( + GeoElementId(firstCurve, PointPos::start)); // get updated point position + } + + auto endpointinfo = handler->getPointInfo(GeoElementId(firstCurve, PointPos::end)); + + if (handler->constructionMethod() + == DrawSketchHandlerLine::ConstructionMethod::OnePointLengthWidth) { + + int DoFs = startpointinfo.getDoFs(); + DoFs += endpointinfo.getDoFs(); + + if (p3set && DoFs > 0) { + constraintp3DistanceX(); + DoFs--; + } + + if (p4set && DoFs > 0) { + constraintp4DistanceY(); + } + } + else if (handler->constructionMethod() + == DrawSketchHandlerLine::ConstructionMethod::OnePointLengthAngle) { + + int DoFs = startpointinfo.getDoFs(); + DoFs += endpointinfo.getDoFs(); + + if (p3set && DoFs > 0) { + constraintp3length(); + DoFs--; + } + + if (p4set && DoFs > 0) { + constraintp4angle(); + } + } + else { + if (p3set && endpointinfo.isXDoF()) { + constraintp3x(); + + handler->diagnoseWithAutoConstraints(); // ensure we have recalculated parameters + // after each constraint addition + + startpointinfo = handler->getPointInfo( + GeoElementId(firstCurve, PointPos::start)); // get updated point position + endpointinfo = handler->getPointInfo(GeoElementId(firstCurve, PointPos::end)); + } + + if (p4set && endpointinfo.isYDoF()) { + constraintp4y(); + } + } + } +} + } // namespace SketcherGui diff --git a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc index 6ee58b00c1..f0ec6a7e20 100644 --- a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc +++ b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc @@ -152,6 +152,10 @@ icons/geometry/Sketcher_CreateHyperbolic_Arc_Constr.svg icons/geometry/Sketcher_CreateLine.svg icons/geometry/Sketcher_CreateLine_Constr.svg + icons/geometry/Sketcher_CreateLineAngleLength.svg + icons/geometry/Sketcher_CreateLineAngleLength_Constr.svg + icons/geometry/Sketcher_CreateLineLengthWidth.svg + icons/geometry/Sketcher_CreateLineLengthWidth_Constr.svg icons/geometry/Sketcher_CreateOblong.svg icons/geometry/Sketcher_CreateOblong_Constr.svg icons/geometry/Sketcher_CreateOctagon.svg @@ -209,6 +213,7 @@ icons/pointers/Sketcher_Pointer_Create_Ellipse.svg icons/pointers/Sketcher_Pointer_Create_Fillet.svg icons/pointers/Sketcher_Pointer_Create_Line.svg + icons/pointers/Sketcher_Pointer_Create_Line_Polar.svg icons/pointers/Sketcher_Pointer_Create_Lineset.svg icons/pointers/Sketcher_Pointer_Create_Point.svg icons/pointers/Sketcher_Pointer_Extension.svg diff --git a/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateLineAngleLength.svg b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateLineAngleLength.svg new file mode 100644 index 0000000000..fd6217cf78 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateLineAngleLength.svg @@ -0,0 +1,235 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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_CreateLine.svg + + + FreeCAD LGPL2+ + + + https://www.gnu.org/copyleft/lesser.html + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateLineAngleLength_Constr.svg b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateLineAngleLength_Constr.svg new file mode 100644 index 0000000000..e019b23ebc --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateLineAngleLength_Constr.svg @@ -0,0 +1,244 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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_CreateLine.svg + + + FreeCAD LGPL2+ + + + https://www.gnu.org/copyleft/lesser.html + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateLineLengthWidth.svg b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateLineLengthWidth.svg new file mode 100644 index 0000000000..3ff695b419 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateLineLengthWidth.svg @@ -0,0 +1,219 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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_CreateLine.svg + + + FreeCAD LGPL2+ + + + https://www.gnu.org/copyleft/lesser.html + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateLineLengthWidth_Constr.svg b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateLineLengthWidth_Constr.svg new file mode 100644 index 0000000000..654f129fdb --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/geometry/Sketcher_CreateLineLengthWidth_Constr.svg @@ -0,0 +1,219 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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_CreateLine.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_Line_Polar.svg b/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Create_Line_Polar.svg new file mode 100644 index 0000000000..9a8b616772 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/pointers/Sketcher_Pointer_Create_Line_Polar.svg @@ -0,0 +1,65 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + +