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