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: 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; 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;