Fix incorrect elliptical arc end angle. Closes #121

This commit is contained in:
Roman Telezhynskyi 2021-04-20 20:20:20 +03:00
parent 5128669d0b
commit 27a3e28855
9 changed files with 93 additions and 55 deletions

View File

@ -42,6 +42,7 @@
- Fix incorrect filename regular expressions.
- Enabling Show Curve Details option causes constant redraw.
- Fix regression with country flags.
- [smart-pattern/valentina#121] Incorrect elliptical arc end angle
# Version 0.6.1 October 23, 2018
- [#885] Regression. Broken support for multi size measurements.

View File

@ -271,7 +271,7 @@ QVector<QPointF> VEllipticalArc::GetPoints() const
QLineF endLine = startLine;
startLine.setAngle(VAbstractArc::GetStartAngle());
endLine.setAngle(VAbstractArc::GetEndAngle());
endLine.setAngle(RealEndAngle());
qreal sweepAngle = startLine.angleTo(endLine);
if (qFuzzyIsNull(sweepAngle))
@ -480,6 +480,26 @@ QPointF VEllipticalArc::GetP(qreal angle) const
return line2.p2() + VAbstractArc::GetCenter().toQPointF();
}
//---------------------------------------------------------------------------------------------------------------------
qreal VEllipticalArc::RealEndAngle() const
{
qreal endAngle = VEllipticalArc::OptimizeAngle(VAbstractArc::GetEndAngle());
if (qFuzzyIsNull(endAngle) ||
VFuzzyComparePossibleNulls(endAngle, 90) ||
VFuzzyComparePossibleNulls(endAngle, 180) ||
VFuzzyComparePossibleNulls(endAngle, 270) ||
VFuzzyComparePossibleNulls(endAngle, 360))
{
return endAngle;
}
endAngle = qRadiansToDegrees(qAtan2(d->radius1 * qSin(qDegreesToRadians(endAngle)),
d->radius2 * qCos(qDegreesToRadians(endAngle))));
return endAngle;
}
//---------------------------------------------------------------------------------------------------------------------
/**
* @brief GetFormulaRadius1 return formula for major radius.

View File

@ -112,6 +112,8 @@ private:
qreal MaxLength() const;
QPointF GetP(qreal angle) const;
qreal RealEndAngle() const;
};
Q_DECLARE_METATYPE(VEllipticalArc)

View File

@ -466,10 +466,11 @@ static inline bool VFuzzyComparePossibleNulls(double p1, double p2)
constexpr qreal accuracyPointOnLine = (0.12/*mm*/ / 25.4) * PrintDPI;
Q_REQUIRED_RESULT Q_DECL_CONSTEXPR static inline bool VFuzzyComparePoints(const QPointF &p1, const QPointF &p2);
Q_DECL_CONSTEXPR static inline bool VFuzzyComparePoints(const QPointF &p1, const QPointF &p2)
Q_REQUIRED_RESULT Q_DECL_CONSTEXPR static inline bool VFuzzyComparePoints(const QPointF &p1, const QPointF &p2,
qreal accuracy = accuracyPointOnLine);
Q_DECL_CONSTEXPR static inline bool VFuzzyComparePoints(const QPointF &p1, const QPointF &p2, qreal accuracy)
{
return qAbs(p1.x() - p2.x()) <= accuracyPointOnLine && qAbs(p1.y() - p2.y()) <= accuracyPointOnLine;
return qAbs(p1.x() - p2.x()) <= accuracy && qAbs(p1.y() - p2.y()) <= accuracy;
}
/**

View File

@ -62,25 +62,22 @@ void AbstractTest::Comparison(const QVector<QPointF> &ekv, const QVector<QPointF
{
// Begin comparison
QCOMPARE(ekv.size(), ekvOrig.size());// First check if sizes equal
const qreal testAccuracy = (1.0/*mm*/ / 25.4) * PrintDPI;
for (int i=0; i < ekv.size(); i++)
{
const QPointF p1 = ekv.at(i);
const QPointF p2 = ekvOrig.at(i);
const QString msg = QString("Index: %1. Got '%2;%3', Expected '%4;%5'.")
.arg(i).arg(p1.x()).arg(p1.y()).arg(p2.x()).arg(p2.y());
// Check each point. Don't use comparison float values
QVERIFY2(VFuzzyComparePoints(p1, p2), qUtf8Printable(msg));
Comparison(ekv.at(i), ekvOrig.at(i), testAccuracy);
}
}
//---------------------------------------------------------------------------------------------------------------------
void AbstractTest::Comparison(const QPointF &result, const QPointF &expected) const
void AbstractTest::Comparison(const QPointF &result, const QPointF &expected, qreal testAccuracy) const
{
const QString msg = QStringLiteral("Got '%2;%3', Expected '%4;%5'.")
.arg(result.x()).arg(result.y()).arg(expected.x()).arg(expected.y());
const QString msg = QStringLiteral("Actual '%2;%3', Expected '%4;%5'. Distance between points %6 mm.")
.arg(result.x()).arg(result.y()).arg(expected.x()).arg(expected.y())
.arg(UnitConvertor(QLineF(result, expected).length(), Unit::Px, Unit::Mm));
// Check each point. Don't use comparison float values
QVERIFY2(VFuzzyComparePoints(result, expected), qUtf8Printable(msg));
QVERIFY2(VFuzzyComparePoints(result, expected, testAccuracy), qUtf8Printable(msg));
}

View File

@ -63,7 +63,7 @@ public:
protected:
void Comparison(const QVector<QPointF> &ekv, const QVector<QPointF> &ekvOrig) const;
void Comparison(const QPointF &result, const QPointF &expected) const;
void Comparison(const QPointF &result, const QPointF &expected, qreal testAccuracy) const;
void Comparison(const QVector<QLineF> &result, const QVector<QLineF> &expected) const;
QString ValentinaPath() const;

View File

@ -170,7 +170,7 @@ void TST_FindPoint::TestPointOfIntersectionCurves()
static_cast<VCrossCurvesPoint>(vCross),
static_cast<HCrossCurvesPoint>(hCross), &result);
Comparison(result, expect);
Comparison(result, expect, accuracyPointOnLine);
}
//---------------------------------------------------------------------------------------------------------------------
@ -211,8 +211,8 @@ void TST_FindPoint::TestTrueDarts()
VToolTrueDarts::FindPoint(baseLineP1, baseLineP2, dartP1, dartP2, dartP3, p1, p2);
Comparison(p1, expectP1);
Comparison(p2, expectP2);
Comparison(p1, expectP1, accuracyPointOnLine);
Comparison(p2, expectP2, accuracyPointOnLine);
}
//---------------------------------------------------------------------------------------------------------------------
@ -239,7 +239,7 @@ void TST_FindPoint::TestLineIntersectAxis()
QPointF resultPoint;
VToolLineIntersectAxis::FindPoint(axis, line, &resultPoint);
Comparison(resultPoint, point);
Comparison(resultPoint, point, accuracyPointOnLine);
}
//---------------------------------------------------------------------------------------------------------------------
@ -272,7 +272,7 @@ void TST_FindPoint::TestTriangle()
QPointF resultPoint;
VToolTriangle::FindPoint(axisP1, axisP2, firstPoint, secondPoint, &resultPoint);
Comparison(point, resultPoint);
Comparison(point, resultPoint, accuracyPointOnLine);
}
//---------------------------------------------------------------------------------------------------------------------
@ -312,7 +312,7 @@ void TST_FindPoint::TestShoulderPoint()
QPointF resultPoint = VToolShoulderPoint::FindPoint(p1, p2, pShoulder, length);
Comparison(point, resultPoint);
Comparison(point, resultPoint, accuracyPointOnLine);
}
//---------------------------------------------------------------------------------------------------------------------
@ -745,5 +745,5 @@ void TST_FindPoint::TestCurveIntersectAxis()
QPointF resultPoint;
VToolCurveIntersectAxis::FindPoint(basePoint, angle, curvePoints, &resultPoint);
Comparison(resultPoint, result);
Comparison(resultPoint, result, accuracyPointOnLine);
}

View File

@ -35,7 +35,7 @@
#include <QtTest>
//---------------------------------------------------------------------------------------------------------------------
TST_VEllipticalArc::TST_VEllipticalArc(QObject *parent) : QObject(parent)
TST_VEllipticalArc::TST_VEllipticalArc(QObject *parent) : AbstractTest(parent)
{}
//---------------------------------------------------------------------------------------------------------------------
@ -169,7 +169,7 @@ void TST_VEllipticalArc::TestData()
QTest::newRow("Full circle: radiuses 150, 200, rotation 30; start 0") << 150.0 << 200.0 << 0.0 << 360.0 << 30.0;
QTest::newRow("Full circle: radiuses 1500, 1000; start 0") << 1500.0 << 1000.0 << 0.0 << 360.0 << 0.0;
QTest::newRow("Full circle: radiuses 1500, 1000, rotation 50; start 0") << 1500.0 << 1000.0 << 0.0 << 360.0 << 50.0;
QTest::newRow("Full circle: radiuses 90000, 80000, rotation 90; start 0") << 90000.0 << 80000.0 << 0.0 << 360.0
QTest::newRow("Full circle: radiuses 15000, 10000, rotation 90; start 0") << 15000.0 << 10000.0 << 0.0 << 360.0
<< 90.0;
QTest::newRow("Full circle: radiuses 10, 20; start 90") << 10.0 << 20.0 << 90.0 << 90.0 << 0.0;
@ -178,21 +178,21 @@ void TST_VEllipticalArc::TestData()
QTest::newRow("Full circle: radiuses 1500, 1000; start 90") << 1500.0 << 1000.0 << 90.0 << 90.0 << 0.0;
QTest::newRow("Full circle: radiuses 1500, 1000, rotation 50; start 90") << 1500.0 << 1000.0 << 90.0 << 90.0
<< 50.0;
QTest::newRow("Full circle: radiuses 90000, 80000, rotation 90; start 90") << 90000.0 << 80000.0 << 90.0 << 90.0
QTest::newRow("Full circle: radiuses 15000, 10000, rotation 90; start 90") << 15000.0 << 10000.0 << 90.0 << 90.0
<< 90.0;
QTest::newRow("Arc less than 45 degree, radiuses 100, 50") << 100.0 << 50.0 << 0.0 << 10.5 << 0.0;
QTest::newRow("Arc less than 45 degree, radiuses 150, 50, rotation 180") << 150.0 << 50.0 << 0.0 << 10.5 << 180.0;
QTest::newRow("Arc less than 45 degree, radiuses 1500, 800, rotation 90") << 1500.0 << 800.0 << 0.0 << 10.5 << 90.0;
QTest::newRow("Arc less than 45 degree, radiuses 50000, 10000, rotation 40")
QTest::newRow("Arc less than 45 degree, radiuses 15000, 10000, rotation 40")
<< 50000.0 << 10000.0 << 0.0 << 10.5 << 40.0;
QTest::newRow("Arc less than 45 degree, radiuses 90000, 10000") << 90000.0 << 10000.0 << 0.0 << 10.5 << 0.0;
QTest::newRow("Arc less than 45 degree, radiuses 15000, 10000") << 15000.0 << 10000.0 << 0.0 << 10.5 << 0.0;
QTest::newRow("Arc 45 degree, radiuses 100, 50, rotation 45") << 100.0 << 50.0 << 0.0 << 45.0 << 45.0;
QTest::newRow("Arc 45 degree, radiuses 150, 15, rotation 30") << 150.0 << 15.0 << 0.0 << 45.0 << 30.0;
QTest::newRow("Arc 45 degree, radiuses 1500, 150, rotation 45") << 1500.0 << 150.0 << 0.0 << 45.0 << 45.0;
QTest::newRow("Arc 45 degree, radiuses 50000, 50000") << 50000.0 << 50000.0 << 0.0 << 45.0 << 0.0;
QTest::newRow("Arc 45 degree, radiuses 90000, 50000, rotation 270") << 90000.0 << 50000.0 << 0.0 << 45.0 << 270.0;
QTest::newRow("Arc 45 degree, radiuses 15000, 15000") << 15000.0 << 15000.0 << 0.0 << 45.0 << 0.0;
QTest::newRow("Arc 45 degree, radiuses 15000, 10000, rotation 270") << 15000.0 << 10000.0 << 0.0 << 45.0 << 270.0;
QTest::newRow("Arc less than 90 degree, radiuses 100, 400, rotation 50") << 100.0 << 400.0 << 0.0 << 75.0 << 50.0;
QTest::newRow("Arc less than 90 degree, radiuses 150, 400, rotation 90") << 150.0 << 400.0 << 0.0 << 75.0 << 90.0;
@ -206,65 +206,65 @@ void TST_VEllipticalArc::TestData()
QTest::newRow("Arc 90 degree, radiuses 100, 50, rotation 30") << 100.0 << 50.0 << 0.0 << 90.0 << 30.0;
QTest::newRow("Arc 90 degree, radiuses 150, 400") << 150.0 << 400.0 << 0.0 << 90.0 << 0.0;
QTest::newRow("Arc 90 degree, radiuses 1500, 800, rotation 70") << 1500.0 << 800.0 << 0.0 << 90.0 << 70.0;
QTest::newRow("Arc 90 degree, radiuses 50000, 5000, rotation 30") << 50000.0 << 5000.0 << 0.0 << 90.0 << 30.0;
QTest::newRow("Arc 90 degree, radiuses 90000, 50000, rotation 235") << 90000.0 << 50000.0 << 0.0 << 90.0 << 235.0;
QTest::newRow("Arc 90 degree, radiuses 15000, 5000, rotation 30") << 15000.0 << 1500.0 << 0.0 << 90.0 << 30.0;
QTest::newRow("Arc 90 degree, radiuses 15000, 14000, rotation 235") << 15000.0 << 14000.0 << 0.0 << 90.0 << 235.0;
QTest::newRow("Arc less than 135 degree, radiuses 100, 50, rotation 60") << 100.0 << 50.0 << 0.0 << 110.6 << 60.0;
QTest::newRow("Arc less than 135 degree, radiuses 150, 400, rotation 300")
<< 150.0 << 400.0 << 0.0 << 110.6 << 300.0;
QTest::newRow("Arc less than 135 degree, radiuses 1500, 800, rotation 360")
<< 1500.0 << 800.0 << 0.0 << 110.6 << 360.0;
QTest::newRow("Arc less than 135 degree, radiuses 50000, 5000, rotation 290")
<< 50000.0 << 5000.0 << 0.0 << 110.6 << 290.0;
QTest::newRow("Arc less than 135 degree, radiuses 90000, 50000") << 90000.0 << 50000.0 << 0.0 << 110.6 << 0.0;
QTest::newRow("Arc less than 135 degree, radiuses 15000, 1500, rotation 290")
<< 15000.0 << 1500.0 << 0.0 << 110.6 << 290.0;
QTest::newRow("Arc less than 135 degree, radiuses 15000, 1500") << 15000.0 << 1500.0 << 0.0 << 110.6 << 0.0;
QTest::newRow("Arc 135 degree, radiuses 100, 50") << 100.0 << 50.0 << 0.0 << 135.0 << 0.0;
QTest::newRow("Arc 135 degree, radiuses 150, 400") << 150.0 << 400.0 << 0.0 << 135.0 << 0.0;
QTest::newRow("Arc 135 degree, radiuses 1500, 800") << 1500.0 << 800.0 << 0.0 << 135.0 << 0.0;
QTest::newRow("Arc 135 degree, radiuses 50000, 5000, rotation 20") << 50000.0 << 5000.0 << 0.0 << 135.0 << 20.0;
QTest::newRow("Arc 135 degree, radiuses 90000, 50000") << 90000.0 << 50000.0 << 0.0 << 135.0 << 0.0;
QTest::newRow("Arc 135 degree, radiuses 15000, 1500, rotation 20") << 15000.0 << 1500.0 << 0.0 << 135.0 << 20.0;
QTest::newRow("Arc 135 degree, radiuses 15000, 10000") << 15000.0 << 10000.0 << 0.0 << 135.0 << 0.0;
QTest::newRow("Arc less than 180 degree, radiuses 100, 50") << 100.0 << 50.0 << 0.0 << 160.7 << 0.0;
QTest::newRow("Arc less than 180 degree, radiuses 150, 400") << 150.0 << 400.0 << 0.0 << 160.7 << 0.0;
QTest::newRow("Arc less than 180 degree, radiuses 1500, 800") << 1500.0 << 800.0 << 0.0 << 160.7 << 0.0;
QTest::newRow("Arc less than 180 degree, radiuses 50000, 5000, rotation 270")
<< 50000.0 << 5000.0 << 0.0 << 160.7 << 270.0;
QTest::newRow("Arc less than 180 degree, radiuses 90000, 50000") << 90000.0 << 50000.0 << 0.0 << 160.7 << 0.0;
QTest::newRow("Arc less than 180 degree, radiuses 15000, 1500, rotation 270")
<< 15000.0 << 1500.0 << 0.0 << 160.7 << 270.0;
QTest::newRow("Arc less than 180 degree, radiuses 15000, 10000") << 15000.0 << 10000.0 << 0.0 << 160.7 << 0.0;
QTest::newRow("Arc 180 degree, radiuses 100, 50") << 100.0 << 50.0 << 0.0 << 180.0 << 0.0;
QTest::newRow("Arc 180 degree, radiuses 150, 400") << 150.0 << 400.0 << 0.0 << 180.0 << 0.0;
QTest::newRow("Arc 180 degree, radiuses 1500, 800") << 1500.0 << 800.0 << 0.0 << 180.0 << 0.0;
QTest::newRow("Arc 180 degree, radiuses 50000, 5000, rotation 60") << 50000.0 << 5000.0 << 0.0 << 180.0 << 60.0;
QTest::newRow("Arc 180 degree, radiuses 90000, 50000") << 90000.0 << 50000.0 << 0.0 << 180.0 << 0.0;
QTest::newRow("Arc 180 degree, radiuses 15000, 1500, rotation 60") << 15000.0 << 1500.0 << 0.0 << 180.0 << 60.0;
QTest::newRow("Arc 180 degree, radiuses 15000, 10000") << 15000.0 << 10000.0 << 0.0 << 180.0 << 0.0;
QTest::newRow("Arc less than 270 degree, radiuses 100, 50") << 100.0 << 50.0 << 0.0 << 150.3 << 0.0;
QTest::newRow("Arc less than 270 degree, radiuses 150, 400") << 150.0 << 400.0 << 0.0 << 150.3 << 0.0;
QTest::newRow("Arc less than 270 degree, radiuses 1500, 800") << 1500.0 << 800.0 << 0.0 << 150.3 << 0.0;
QTest::newRow("Arc less than 270 degree, radiuses 50000, 5000, rotation 20")
<< 50000.0 << 5000.0 << 0.0 << 150.3 << 20.0;
QTest::newRow("Arc less than 270 degree, radiuses 90000, 50000") << 90000.0 << 50000.0 << 0.0 << 150.3 << 0.0;
QTest::newRow("Arc less than 270 degree, radiuses 15000, 1500, rotation 20")
<< 15000.0 << 1500.0 << 0.0 << 150.3 << 20.0;
QTest::newRow("Arc less than 270 degree, radiuses 15000, 10000") << 15000.0 << 10000.0 << 0.0 << 150.3 << 0.0;
QTest::newRow("Arc 270 degree, radiuses 100, 50") << 100.0 << 50.0 << 0.0 << 270.0 << 0.0;
QTest::newRow("Arc 270 degree, radiuses 150, 400") << 150.0 << 400.0 << 0.0 << 270.0 << 0.0;
QTest::newRow("Arc 270 degree, radiuses 1500, 800") << 1500.0 << 800.0 << 0.0 << 270.0 << 0.0;
QTest::newRow("Arc 270 degree, radiuses 50000, 5000, rotation 90") << 50000.0 << 5000.0 << 0.0 << 270.0 << 90.0;
QTest::newRow("Arc 270 degree, radiuses 90000, 50000") << 90000.0 << 50000.0 << 0.0 << 270.0 << 0.0;
QTest::newRow("Arc 270 degree, radiuses 15000, 1500, rotation 90") << 15000.0 << 1500.0 << 0.0 << 270.0 << 90.0;
QTest::newRow("Arc 270 degree, radiuses 15000, 10000") << 15000.0 << 10000.0 << 0.0 << 270.0 << 0.0;
QTest::newRow("Arc less than 360 degree, radiuses 100, 50") << 100.0 << 50.0 << 0.0 << 340.0 << 0.0;
QTest::newRow("Arc less than 360 degree, radiuses 150, 400") << 150.0 << 400.0 << 0.0 << 340.0 << 0.0;
QTest::newRow("Arc less than 360 degree, radiuses 1500, 800") << 1500.0 << 800.0 << 0.0 << 340.0 << 0.0;
QTest::newRow("Arc less than 360 degree, radiuses 50000, 5000, rotation 30")
<< 50000.0 << 5000.0 << 0.0 << 340.0 << 30.0;
QTest::newRow("Arc less than 360 degree, radiuses 90000, 50000") << 90000.0 << 50000.0 << 0.0 << 340.0 << 0.0;
QTest::newRow("Arc less than 360 degree, radiuses 12000, 1200, rotation 30")
<< 12000.0 << 1200.0 << 0.0 << 340.0 << 30.0;
QTest::newRow("Arc less than 360 degree, radiuses 12000, 10000") << 15000.0 << 10000.0 << 0.0 << 340.0 << 0.0;
QTest::newRow("Arc start 90 degree, angle 45 degree, radiuses 100, 50") << 100.0 << 50.0 << 90.0 << 135.0 << 0.0;
QTest::newRow("Arc start 90 degree, angle 45 degree, radiuses 150, 400") << 150.0 << 400.0 << 90.0 << 135.0 << 0.0;
QTest::newRow("Arc start 90 degree, angle 45 degree, radiuses 1500, 800")
<< 1500.0 << 800.0 << 90.0 << 135.0 << 0.0;
QTest::newRow("Arc start 90 degree, angle 45 degree, radiuses 50000, 5000")
<< 50000.0 << 5000.0 << 90.0 << 135.0 << 0.0;
QTest::newRow("Arc start 90 degree, angle 45 degree, radiuses 90000, 50000")
<< 90000.0 << 50000.0 << 90.0 << 135.0 << 0.0;
QTest::newRow("Arc start 90 degree, angle 45 degree, radiuses 13000, 1000")
<< 15000.0 << 1000.0 << 90.0 << 135.0 << 0.0;
QTest::newRow("Arc start 90 degree, angle 45 degree, radiuses 15000, 10000")
<< 15000.0 << 10000.0 << 90.0 << 135.0 << 0.0;
}
//---------------------------------------------------------------------------------------------------------------------
@ -461,6 +461,23 @@ void TST_VEllipticalArc::TestGetPoints5()
QCOMPARE(f1, stAngle);
QCOMPARE(f2, enAngle);
QVector<QPointF> points = arc.GetPoints();
if (points.size() > 2 && qFuzzyIsNull(rotationAngle))
{
const qreal testAccuracy = (1.5/*mm*/ / 25.4) * PrintDPI;
Comparison(arc.GetP1(), points.first(), testAccuracy);
Comparison(arc.GetP2(), points.last(), testAccuracy);
const qreal eps = 0.15;
f1 = QLineF(static_cast<QPointF>(center), points.first()).angle();
QVERIFY2(f1 - stAngle <= eps, qUtf8Printable(QStringLiteral("f1: %1; expected: %2").arg(f1).arg(stAngle)));
f2 = QLineF(static_cast<QPointF>(center), points.last()).angle();
QVERIFY2(f2 - enAngle <= eps, qUtf8Printable(QStringLiteral("f2: %1; expected: %2").arg(f2).arg(enAngle)));
}
}
//---------------------------------------------------------------------------------------------------------------------

View File

@ -29,9 +29,9 @@
#ifndef TST_VELLIPTICALARC_H
#define TST_VELLIPTICALARC_H
#include <QObject>
#include "../vtest/abstracttest.h"
class TST_VEllipticalArc : public QObject
class TST_VEllipticalArc : public AbstractTest
{
Q_OBJECT
public: