diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerArcOfEllipse.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerArcOfEllipse.h index b47de691aa..e561828d83 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerArcOfEllipse.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerArcOfEllipse.h @@ -50,26 +50,23 @@ class DrawSketchHandlerArcOfEllipse: public DrawSketchHandler public: DrawSketchHandlerArcOfEllipse() - : Mode(STATUS_SEEK_First) + : Mode(SelectMode::First) , EditCurve(34) - , rx(0) - , ry(0) , startAngle(0) , endAngle(0) , arcAngle(0) - , arcAngle_t(0) {} ~DrawSketchHandlerArcOfEllipse() override = default; /// mode table - enum SelectMode + enum class SelectMode { - STATUS_SEEK_First, - STATUS_SEEK_Second, - STATUS_SEEK_Third, - STATUS_SEEK_Fourth, - STATUS_Close + First, + Second, + Third, + Fourth, + End }; void mouseMove(SnapManager::SnapHandle snapHandle) override @@ -77,13 +74,13 @@ public: using std::numbers::pi; Base::Vector2d onSketchPos = snapHandle.compute(); - if (Mode == STATUS_SEEK_First) { + if (Mode == SelectMode::First) { setPositionText(onSketchPos); seekAndRenderAutoConstraint(sugConstr1, onSketchPos, Base::Vector2d(0.f, 0.f)); // TODO: // ellipse // prio 1 } - else if (Mode == STATUS_SEEK_Second) { + else if (Mode == SelectMode::Second) { double rx0 = onSketchPos.x - EditCurve[0].x; double ry0 = onSketchPos.y - EditCurve[0].y; for (int i = 0; i < 16; i++) { @@ -113,23 +110,33 @@ public: AutoConstraint::CURVE ); } - else if (Mode == STATUS_SEEK_Third) { - // angle between the major axis of the ellipse and the X axis - double a = (EditCurve[1] - EditCurve[0]).Length(); - double phi = atan2(EditCurve[1].y - EditCurve[0].y, EditCurve[1].x - EditCurve[0].x); + else if (Mode == SelectMode::Third) { + Base::Vector2d delta12 = axisPoint - centerPoint; - // This is the angle at cursor point - double angleatpoint = acos( - (onSketchPos.x - EditCurve[0].x + (onSketchPos.y - EditCurve[0].y) * tan(phi)) - / (a * (cos(phi) + tan(phi) * sin(phi))) + double a = delta12.Length(); + + Base::Vector2d aDir = delta12.Normalize(); + Base::Vector2d bDir(-aDir.y, aDir.x); + + Base::Vector2d delta13 = onSketchPos - centerPoint; + Base::Vector2d delta13Prime( + delta13.x * aDir.x + delta13.y * aDir.y, + delta13.x * bDir.x + delta13.y * bDir.y ); - double b = (onSketchPos.y - EditCurve[0].y - a * cos(angleatpoint) * sin(phi)) - / (sin(angleatpoint) * cos(phi)); + + double cosT = max(-1.0, min(1.0, delta13Prime.x / a)); + double sinT = sqrt(max(0.0, 1 - cosT * cosT)); + + double b = abs(delta13Prime.y) / sinT; + if (sinT == 0.0) { + b = 0.0; + a = 0.0; + } for (int i = 1; i < 16; i++) { double angle = i * pi / 16.0; - double rx1 = a * cos(angle) * cos(phi) - b * sin(angle) * sin(phi); - double ry1 = a * cos(angle) * sin(phi) + b * sin(angle) * cos(phi); + double rx1 = a * cos(angle) * aDir.x + b * sin(angle) * bDir.x; + double ry1 = a * cos(angle) * aDir.y + b * sin(angle) * bDir.y; EditCurve[1 + i] = Base::Vector2d(EditCurve[0].x + rx1, EditCurve[0].y + ry1); EditCurve[17 + i] = Base::Vector2d(EditCurve[0].x - rx1, EditCurve[0].y - ry1); } @@ -148,49 +155,43 @@ public: drawEdit(EditCurve); seekAndRenderAutoConstraint(sugConstr3, onSketchPos, Base::Vector2d(0.f, 0.f)); } - else if (Mode == STATUS_SEEK_Fourth) { // here we differ from ellipse creation - // angle between the major axis of the ellipse and the X axis - double a = (axisPoint - centerPoint).Length(); - double phi = atan2(axisPoint.y - centerPoint.y, axisPoint.x - centerPoint.x); + else if (Mode == SelectMode::Fourth) { // here we differ from ellipse creation + Base::Vector2d delta12 = axisPoint - centerPoint; - // This is the angle at cursor point - double angleatpoint = acos( - (startingPoint.x - centerPoint.x + (startingPoint.y - centerPoint.y) * tan(phi)) - / (a * (cos(phi) + tan(phi) * sin(phi))) - ); - double b = abs( - (startingPoint.y - centerPoint.y - a * cos(angleatpoint) * sin(phi)) - / (sin(angleatpoint) * cos(phi)) + double a = delta12.Length(); + + Base::Vector2d aDir = delta12.Normalize(); + Base::Vector2d bDir(-aDir.y, aDir.x); + + Base::Vector2d delta13 = startingPoint - centerPoint; + Base::Vector2d delta13Prime( + delta13.x * aDir.x + delta13.y * aDir.y, + delta13.x * bDir.x + delta13.y * bDir.y ); - double rxs = startingPoint.x - centerPoint.x; - double rys = startingPoint.y - centerPoint.y; - startAngle = atan2( - a * (rys * cos(phi) - rxs * sin(phi)), - b * (rxs * cos(phi) + rys * sin(phi)) - ); // eccentric anomaly angle + double cosT = max(-1.0, min(1.0, delta13Prime.x / a)); + double sinT = sqrt(max(0.0, 1 - cosT * cosT)); - double angle1 = atan2( - a - * ((onSketchPos.y - centerPoint.y) * cos(phi) - - (onSketchPos.x - centerPoint.x) * sin(phi)), - b - * ((onSketchPos.x - centerPoint.x) * cos(phi) - + (onSketchPos.y - centerPoint.y) * sin(phi)) - ) - - startAngle; + double b = abs(delta13Prime.y) / sinT; + startAngle = atan2(delta13Prime.y / b, delta13Prime.x / a); + + Base::Vector2d delta14 = onSketchPos - centerPoint; + Base::Vector2d delta14Prime( + delta14.x * aDir.x + delta14.y * aDir.y, + delta14.x * bDir.x + delta14.y * bDir.y + ); + double angle1 = atan2(delta14Prime.y / b, delta14Prime.x / a) - startAngle; double angle2 = angle1 + (angle1 < 0. ? 2 : -2) * pi; + arcAngle = abs(angle1 - arcAngle) < abs(angle2 - arcAngle) ? angle1 : angle2; for (int i = 0; i < 34; i++) { - double angle = startAngle + i * arcAngle / 34.0; - double rx1 = a * cos(angle) * cos(phi) - b * sin(angle) * sin(phi); - double ry1 = a * cos(angle) * sin(phi) + b * sin(angle) * cos(phi); + double angle = startAngle + i * arcAngle / 33.0; + double rx1 = a * cos(angle) * aDir.x + b * sin(angle) * bDir.x; + double ry1 = a * cos(angle) * aDir.y + b * sin(angle) * bDir.y; EditCurve[i] = Base::Vector2d(centerPoint.x + rx1, centerPoint.y + ry1); } - // EditCurve[33] = EditCurve[1]; - // EditCurve[17] = EditCurve[16]; // Display radii and angle for user if (showCursorCoords()) { @@ -202,35 +203,43 @@ public: setPositionText(onSketchPos, text); } - drawEdit(EditCurve); + if (onSketchPos != centerPoint) { + drawEdit(EditCurve); + } + else { + drawEdit(std::vector()); + } seekAndRenderAutoConstraint(sugConstr4, onSketchPos, Base::Vector2d(0.f, 0.f)); } } bool pressButton(Base::Vector2d onSketchPos) override { - if (Mode == STATUS_SEEK_First) { + using std::numbers::pi; + + if (Mode == SelectMode::First) { EditCurve[0] = onSketchPos; centerPoint = onSketchPos; setAngleSnapping(true, centerPoint); - Mode = STATUS_SEEK_Second; + Mode = SelectMode::Second; } - else if (Mode == STATUS_SEEK_Second) { + else if (Mode == SelectMode::Second + && (centerPoint - onSketchPos).Length() >= Precision::Confusion()) { EditCurve[1] = onSketchPos; axisPoint = onSketchPos; - Mode = STATUS_SEEK_Third; + Mode = SelectMode::Third; } - else if (Mode == STATUS_SEEK_Third) { + else if (Mode == SelectMode::Third && validThirdPoint(onSketchPos)) { startingPoint = onSketchPos; arcAngle = 0.; - arcAngle_t = 0.; - Mode = STATUS_SEEK_Fourth; + Mode = SelectMode::Fourth; } - else { // Fourth + else if (Mode == SelectMode::Fourth && centerPoint != onSketchPos && arcAngle != 0 + && abs(arcAngle) != 2 * pi) { endPoint = onSketchPos; setAngleSnapping(false); - Mode = STATUS_Close; + Mode = SelectMode::End; } updateHint(); @@ -243,35 +252,36 @@ public: using std::numbers::pi; - if (Mode == STATUS_Close) { + if (Mode == SelectMode::End) { unsetCursor(); resetPositionText(); - // angle between the major axis of the ellipse and the X axisEllipse - double a = (axisPoint - centerPoint).Length(); - double phi = atan2(axisPoint.y - centerPoint.y, axisPoint.x - centerPoint.x); + Base::Vector2d delta12 = axisPoint - centerPoint; - // This is the angle at cursor point - double angleatpoint = acos( - (startingPoint.x - centerPoint.x + (startingPoint.y - centerPoint.y) * tan(phi)) - / (a * (cos(phi) + tan(phi) * sin(phi))) - ); - double b = abs( - (startingPoint.y - centerPoint.y - a * cos(angleatpoint) * sin(phi)) - / (sin(angleatpoint) * cos(phi)) + double a = delta12.Length(); + + Base::Vector2d aDir = delta12.Normalize(); + Base::Vector2d bDir(-aDir.y, aDir.x); + + Base::Vector2d delta13 = startingPoint - centerPoint; + Base::Vector2d delta13Prime( + delta13.x * aDir.x + delta13.y * aDir.y, + delta13.x * bDir.x + delta13.y * bDir.y ); - double angle1 = atan2( - a - * ((endPoint.y - centerPoint.y) * cos(phi) - - (endPoint.x - centerPoint.x) * sin(phi)), - b - * ((endPoint.x - centerPoint.x) * cos(phi) - + (endPoint.y - centerPoint.y) * sin(phi)) - ) - - startAngle; + double cosT = max(-1.0, min(1.0, delta13Prime.x / a)); + double sinT = sqrt(max(0.0, 1 - cosT * cosT)); + double b = abs(delta13Prime.y) / sinT; + + Base::Vector2d delta14 = endPoint - centerPoint; + Base::Vector2d delta14Prime( + delta14.x * aDir.x + delta14.y * aDir.y, + delta14.x * bDir.x + delta14.y * bDir.y + ); + double angle1 = atan2(delta14Prime.y / b, delta14Prime.x / a) - startAngle; double angle2 = angle1 + (angle1 < 0. ? 2 : -2) * pi; + arcAngle = abs(angle1 - arcAngle) < abs(angle2 - arcAngle) ? angle1 : angle2; bool isOriginalArcCCW = true; @@ -391,7 +401,7 @@ public: bool continuousMode = hGrp->GetBool("ContinuousCreationMode", true); if (continuousMode) { // This code enables the continuous creation mode. - Mode = STATUS_SEEK_First; + Mode = SelectMode::First; EditCurve.clear(); drawEdit(EditCurve); EditCurve.resize(34); @@ -422,7 +432,7 @@ protected: SelectMode Mode; std::vector EditCurve; Base::Vector2d centerPoint, axisPoint, startingPoint, endPoint; - double rx, ry, startAngle, endAngle, arcAngle, arcAngle_t; + double startAngle, endAngle, arcAngle; std::vector sugConstr1, sugConstr2, sugConstr3, sugConstr4; private: @@ -433,28 +443,47 @@ private: return Gui::lookupHints( Mode, { - {.state = STATUS_SEEK_First, + {.state = SelectMode::First, .hints = { {tr("%1 pick ellipse center"), {MouseLeft}}, }}, - {.state = STATUS_SEEK_Second, + {.state = SelectMode::Second, .hints = { {tr("%1 pick axis point"), {MouseLeft}}, }}, - {.state = STATUS_SEEK_Third, + {.state = SelectMode::Third, .hints = { {tr("%1 pick arc start point"), {MouseLeft}}, }}, - {.state = STATUS_SEEK_Fourth, + {.state = SelectMode::Fourth, .hints = { {tr("%1 pick arc end point"), {MouseLeft}}, }}, }); } + + bool validThirdPoint(Base::Vector2d onSketchPos) + { + Base::Vector2d delta12 = axisPoint - centerPoint; + + double a = delta12.Length(); + + Base::Vector2d aDir = delta12.Normalize(); + Base::Vector2d bDir(-aDir.y, aDir.x); + + Base::Vector2d delta13 = onSketchPos - centerPoint; + Base::Vector2d delta13Prime( + delta13.x * aDir.x + delta13.y * aDir.y, + delta13.x * bDir.x + delta13.y * bDir.y + ); + + double cosT = max(-1.0, min(1.0, delta13Prime.x / a)); + return cosT != -1.0 && cosT != 1.0 && delta13Prime.y != 0; + } }; } // namespace SketcherGui