From fbca26780851289f68723e0a69d3d200e3e1bf3b Mon Sep 17 00:00:00 2001 From: tetektoza Date: Tue, 28 Oct 2025 23:50:11 +0100 Subject: [PATCH 1/3] Sketcher: Remember cursor angle for Slot OVPs after OVP is set As the title says. Currently user is able to change geometry if OVP is set on labels. This is because `doEnforceControlParameters` reads mouse position every mouse move and calculates angle from it, resulting in a new angle every time mouse is moved. So, this patch basically reads the position before it was set, and once it is set, locks the position of the mouse and calculates angle from it which will be maintained until user cleans the OVP or makes a new primitive. --- src/Mod/Sketcher/Gui/DrawSketchHandlerSlot.h | 24 +++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerSlot.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerSlot.h index baf206eeec..de778a4cee 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerSlot.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerSlot.h @@ -74,6 +74,7 @@ public: , length(0.0) , angle(0.0) , firstCurve(0) + , capturedDirection(0.0, 0.0) {} ~DrawSketchHandlerSlot() override = default; @@ -339,6 +340,9 @@ private: Base::Vector2d startPoint, secondPoint; double radius, length, angle; int firstCurve; + + // Direction tracking to prevent OVP from flipping (issue #23459) + Base::Vector2d capturedDirection; }; template<> @@ -403,20 +407,28 @@ void DSHSlotControllerBase::doEnforceControlParameters(Base::Vector2d& onSketchP } double length = dir.Length(); + if (fourthParam->isSet) { + const double angle = Base::toRadians(fourthParam->getValue()); + const Base::Vector2d ovpDir(cos(angle), sin(angle)); + handler->capturedDirection = ovpDir; + } + else { + handler->capturedDirection = dir.Normalize(); + } + if (thirdParam->isSet) { length = thirdParam->getValue(); if (length < Precision::Confusion() && thirdParam->hasFinishedEditing) { unsetOnViewParameter(thirdParam.get()); + handler->capturedDirection = Base::Vector2d(0.0, 0.0); return; } - onSketchPos = handler->startPoint + length * dir.Normalize(); + onSketchPos = handler->startPoint + length * handler->capturedDirection; } - - if (fourthParam->isSet) { - double angle = Base::toRadians(fourthParam->getValue()); - Base::Vector2d ovpDir(cos(angle), sin(angle)); - onSketchPos.ProjectToLine(onSketchPos - handler->startPoint, ovpDir); + else if (fourthParam->isSet) { + onSketchPos.ProjectToLine(onSketchPos - handler->startPoint, + handler->capturedDirection); onSketchPos += handler->startPoint; } } break; From d4991564d7a3935ddf7020c074d8f6ed6024c325 Mon Sep 17 00:00:00 2001 From: tetektoza Date: Tue, 28 Oct 2025 23:50:43 +0100 Subject: [PATCH 2/3] Sketcher: Remember cursor angle for Line OVPs after OVP is set As the title says. Currently user is able to change geometry if OVP is set on labels. This is because `doEnforceControlParameters` reads mouse position every mouse move and calculates angle from it, resulting in a new angle every time mouse is moved. So, this patch basically reads the position before it was set, and once it is set, locks the position of the mouse and calculates angle from it which will be maintained until user cleans the OVP or makes a new primitive. --- src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h | 57 ++++++++++++++++---- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h index 5ff0a6238c..1a2bf0cebd 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerLine.h @@ -86,7 +86,10 @@ public: explicit DrawSketchHandlerLine( ConstructionMethod constrMethod = ConstructionMethod::OnePointLengthAngle) : DrawSketchHandlerLineBase(constrMethod) - , length(0.0) {}; + , length(0.0) + , lengthSign(0) + , widthSign(0) + , capturedDirection(0.0, 0.0) {}; ~DrawSketchHandlerLine() override = default; private: @@ -237,10 +240,23 @@ private: } } + void onReset() override + { + lengthSign = 0; + widthSign = 0; + capturedDirection = Base::Vector2d(0.0, 0.0); + toolWidgetManager.resetControls(); + } + private: Base::Vector2d startPoint, endPoint; double length; + // These store the direction sign when OVP is first set to prevent sign flipping + int lengthSign, widthSign; + // Direction tracking to check once OVP is locked + Base::Vector2d capturedDirection; + void createShape(bool onlyeditoutline) override { Q_UNUSED(onlyeditoutline); @@ -427,12 +443,17 @@ void DSHLineControllerBase::doEnforceControlParameters(Base::Vector2d& onSketchP if (fabs(width) < Precision::Confusion() && fourthParam->hasFinishedEditing) { unsetOnViewParameter(thirdParam.get()); + handler->lengthSign = 0; return; } } } - int sign = (onSketchPos.x - handler->startPoint.x) >= 0 ? 1 : -1; - onSketchPos.x = handler->startPoint.x + sign * length; + // get sign on the first time we set the OVP label, so it won't get flipped + // with mouse next time + if (handler->lengthSign == 0) { + handler->lengthSign = (onSketchPos.x - handler->startPoint.x) >= 0 ? 1 : -1; + } + onSketchPos.x = handler->startPoint.x + handler->lengthSign * length; } if (fourthParam->isSet) { @@ -444,12 +465,15 @@ void DSHLineControllerBase::doEnforceControlParameters(Base::Vector2d& onSketchP if (fabs(length) < Precision::Confusion() && thirdParam->hasFinishedEditing) { unsetOnViewParameter(fourthParam.get()); + handler->widthSign = 0; return; } } } - int sign = (onSketchPos.y - handler->startPoint.y) >= 0 ? 1 : -1; - onSketchPos.y = handler->startPoint.y + sign * width; + if (handler->widthSign == 0) { + handler->widthSign = (onSketchPos.y - handler->startPoint.y) >= 0 ? 1 : -1; + } + onSketchPos.y = handler->startPoint.y + handler->widthSign * width; } } else if (handler->constructionMethod() == ConstructionMethod::OnePointLengthAngle) { @@ -460,20 +484,29 @@ void DSHLineControllerBase::doEnforceControlParameters(Base::Vector2d& onSketchP } double length = dir.Length(); + if (fourthParam->isSet) { + const double angle = Base::toRadians(fourthParam->getValue()); + const Base::Vector2d ovpDir(cos(angle), sin(angle)); + handler->capturedDirection = ovpDir; + } + else { + handler->capturedDirection = dir.Normalize(); + } + if (thirdParam->isSet) { length = thirdParam->getValue(); if (length < Precision::Confusion() && thirdParam->hasFinishedEditing) { unsetOnViewParameter(thirdParam.get()); + handler->capturedDirection = Base::Vector2d(0.0, 0.0); return; } - onSketchPos = handler->startPoint + length * dir.Normalize(); + onSketchPos = handler->startPoint + length * handler->capturedDirection; } - - if (fourthParam->isSet) { - double angle = Base::toRadians(fourthParam->getValue()); - Base::Vector2d ovpDir(cos(angle), sin(angle)); - onSketchPos.ProjectToLine(onSketchPos - handler->startPoint, ovpDir); + else if (fourthParam->isSet) { + // only angle is set, project current position onto that angle + onSketchPos.ProjectToLine(onSketchPos - handler->startPoint, + handler->capturedDirection); onSketchPos += handler->startPoint; } } @@ -490,6 +523,8 @@ void DSHLineControllerBase::doEnforceControlParameters(Base::Vector2d& onSketchP && (onSketchPos - handler->startPoint).Length() < Precision::Confusion()) { unsetOnViewParameter(thirdParam.get()); unsetOnViewParameter(fourthParam.get()); + handler->lengthSign = 0; + handler->widthSign = 0; } } break; default: From d4ad75ba0eb784876d24e97934cb832653df91db Mon Sep 17 00:00:00 2001 From: tetektoza Date: Tue, 28 Oct 2025 23:51:02 +0100 Subject: [PATCH 3/3] Sketcher: Remember cursor angle for Rectangle OVPs after OVP is set As the title says. Currently user is able to change geometry if OVP is set on labels. This is because `doEnforceControlParameters` reads mouse position every mouse move and calculates angle from it, resulting in a new angle every time mouse is moved. So, this patch basically reads the position before it was set, and once it is set, locks the position of the mouse and calculates angle from it which will be maintained until user cleans the OVP or makes a new primitive. --- .../Sketcher/Gui/DrawSketchHandlerRectangle.h | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerRectangle.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerRectangle.h index 679007857d..90c94b9452 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerRectangle.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerRectangle.h @@ -104,6 +104,8 @@ public: , constructionPointThreeId(Sketcher::GeoEnum::GeoUndef) , centerPointId(Sketcher::GeoEnum::GeoUndef) , side(0) + , lengthSign(0) + , widthSign(0) {} ~DrawSketchHandlerRectangle() override = default; @@ -815,6 +817,8 @@ private: void onReset() override { thickness = 0.; + lengthSign = 0; + widthSign = 0; toolWidgetManager.resetControls(); } @@ -827,6 +831,10 @@ private: int firstCurve, constructionPointOneId, constructionPointTwoId, constructionPointThreeId, centerPointId, side; + // Sign tracking for OVP lock fix (issue #23459) + // These store the direction sign when OVP is first set to prevent sign flipping + int lengthSign, widthSign; + void createShape(bool onlyeditoutline) override { ShapeGeometry.clear(); @@ -1987,12 +1995,16 @@ void DSHRectangleControllerBase::doEnforceControlParameters(Base::Vector2d& onSk if (fabs(length) < Precision::Confusion() && onViewParameters[OnViewParameter::Third]->hasFinishedEditing) { unsetOnViewParameter(onViewParameters[OnViewParameter::Third].get()); + handler->lengthSign = 0; return; } if (handler->constructionMethod() == ConstructionMethod::Diagonal) { - int sign = (onSketchPos.x - handler->corner1.x) >= 0 ? 1 : -1; - onSketchPos.x = handler->corner1.x + sign * length; + if (handler->lengthSign == 0) { + handler->lengthSign = + (onSketchPos.x - handler->corner1.x) >= 0 ? 1 : -1; + } + onSketchPos.x = handler->corner1.x + handler->lengthSign * length; } else { onSketchPos.x = handler->center.x + length / 2; @@ -2003,12 +2015,15 @@ void DSHRectangleControllerBase::doEnforceControlParameters(Base::Vector2d& onSk if (fabs(width) < Precision::Confusion() && onViewParameters[OnViewParameter::Fourth]->hasFinishedEditing) { unsetOnViewParameter(onViewParameters[OnViewParameter::Fourth].get()); + handler->widthSign = 0; return; } if (handler->constructionMethod() == ConstructionMethod::Diagonal) { - int sign = (onSketchPos.y - handler->corner1.y) >= 0 ? 1 : -1; - onSketchPos.y = handler->corner1.y + sign * width; + if (handler->widthSign == 0) { + handler->widthSign = (onSketchPos.y - handler->corner1.y) >= 0 ? 1 : -1; + } + onSketchPos.y = handler->corner1.y + handler->widthSign * width; } else { onSketchPos.y = handler->center.y + width / 2;