Fix issue in tool cut spline.

Infinite loop while calculating a t parameter.
This commit is contained in:
Roman Telezhynskyi 2022-02-03 15:48:52 +02:00
parent 11b8ba9e78
commit e876a4d611
9 changed files with 85 additions and 17 deletions

View File

@ -29,6 +29,7 @@
- New path validation Invalid segment.
- [smart-pattern/valentina#43] Background image.
- Fix alias for tool Cut Arc.
- Fix infinite loop in tool cut spline.
# Valentina 0.7.49 July 1, 2021
- Fix crash.

View File

@ -503,28 +503,38 @@ QString VAbstractCubicBezier::NameForHistory(const QString &toolName) const
}
//---------------------------------------------------------------------------------------------------------------------
qreal VAbstractCubicBezier::GetParmT(qreal length) const
auto VAbstractCubicBezier::GetParmT(qreal length) const -> qreal
{
const qreal base = GetRealLength();
if (length < 0)
{
return 0;
}
else if (length > GetLength())
if (length > base)
{
length = GetLength();
length = base;
}
const qreal eps = 0.001 * length;
constexpr qreal eps = UnitConvertor(0.001, Unit::Mm, Unit::Px);
qreal parT = 0.5;
qreal step = parT;
qreal splLength = LengthT(parT);
qreal splLength = 0;
while (qAbs(splLength - length) > eps)
do
{
splLength = RealLengthByT(parT);
step /= 2.0;
if (qFuzzyIsNull(step))
{
break;
}
splLength > length ? parT -= step : parT += step;
splLength = LengthT(parT);
}
while (qAbs(splLength - length) > eps);
return parT;
}
@ -591,7 +601,7 @@ qreal VAbstractCubicBezier::LengthBezier(const QPointF &p1, const QPointF &p2, c
}
//---------------------------------------------------------------------------------------------------------------------
qreal VAbstractCubicBezier::LengthT(qreal t) const
qreal VAbstractCubicBezier::RealLengthByT(qreal t) const
{
if (t < 0 || t > 1)
{
@ -622,5 +632,5 @@ qreal VAbstractCubicBezier::LengthT(qreal t) const
seg123_234.setLength(seg123_234.length () * t);
const QPointF p1234 = seg123_234.p2();
return LengthBezier ( static_cast<QPointF>(GetP1()), p12, p123, p1234, GetApproximationScale());
return LengthBezier ( static_cast<QPointF>(GetP1()), p12, p123, p1234, maxCurveApproximationScale);
}

View File

@ -62,7 +62,7 @@ public:
virtual QString NameForHistory(const QString &toolName) const override;
qreal GetParmT(qreal length) const;
qreal LengthT(qreal t) const;
qreal RealLengthByT(qreal t) const;
protected:
virtual void CreateName() override;
@ -75,6 +75,7 @@ protected:
virtual QPointF GetControlPoint1() const =0;
virtual QPointF GetControlPoint2() const =0;
virtual auto GetRealLength() const -> qreal =0;
};
QT_WARNING_POP

View File

@ -252,3 +252,10 @@ QPointF VCubicBezier::GetControlPoint2() const
{
return static_cast<QPointF>(GetP3());
}
//---------------------------------------------------------------------------------------------------------------------
qreal VCubicBezier::GetRealLength() const
{
return LengthBezier (static_cast<QPointF>(GetP1()), static_cast<QPointF>(GetP2()),
static_cast<QPointF>(GetP3()), static_cast<QPointF>(GetP4()), maxCurveApproximationScale);
}

View File

@ -84,6 +84,7 @@ public:
protected:
virtual QPointF GetControlPoint1() const override;
virtual QPointF GetControlPoint2() const override;
auto GetRealLength() const -> qreal override;
private:
QSharedDataPointer<VCubicBezierData> d;

View File

@ -611,3 +611,10 @@ QPointF VSpline::GetControlPoint2() const
{
return static_cast<QPointF>(GetP3 ());
}
//---------------------------------------------------------------------------------------------------------------------
auto VSpline::GetRealLength() const -> qreal
{
return LengthBezier(static_cast<QPointF>(GetP1()), static_cast<QPointF>(GetP2()), static_cast<QPointF>(GetP3()),
static_cast<QPointF>(GetP4()), maxCurveApproximationScale);
}

View File

@ -117,6 +117,7 @@ public:
protected:
virtual QPointF GetControlPoint1() const override;
virtual QPointF GetControlPoint2() const override;
auto GetRealLength () const -> qreal override;
private:
QSharedDataPointer<VSplineData> d;
QVector<qreal> CalcT(qreal curveCoord1, qreal curveCoord2, qreal curveCoord3, qreal curveCoord4,

View File

@ -28,6 +28,7 @@
#include "tst_vspline.h"
#include "../vgeometry/vspline.h"
#include "def.h"
#include <QtTest>
@ -717,18 +718,56 @@ void TST_VSpline::CompareThreeWays()
CompareSplines(spl3, spl1);
}
//---------------------------------------------------------------------------------------------------------------------
void TST_VSpline::TestParametrT_data()
{
QTest::addColumn<VSpline>("spl");
QTest::addColumn<qreal>("length");
VPointF p1(30, 39.999874015748034, QStringLiteral("p1"), 15, 30);
VPointF p4(2883.86674323853821, 805.33182541168674, QStringLiteral("p4"), 9.9999874015748045, 15);
VSpline spl(p1, p4, 240.60499999999999, QStringLiteral("240.605"), 260.36399999999998, QStringLiteral("260.364"),
6614.8535433070883, QStringLiteral("175.018"), 10695.382677165355, QStringLiteral("282.982"));
qreal base = spl.GetLength();
qreal step = 0;
do
{
QTest::newRow(qUtf8Printable(QStringLiteral("Curve 1. Step = %1").arg(step))) << spl << base * step;
step += 0.001;
}
while(step <= 1);
p1 = VPointF(3476.6410658375944, 334.08136371135333, QStringLiteral("p1"), -141.34148031496062, 109.00951181102363);
p4 = VPointF(3483.5141183177025, 333.72231804361377, QStringLiteral("p4"), 48, 102.99930708661418);
spl = VSpline(p1, p4, 3.1976200000000001, QStringLiteral("3.19762"), 175.24700000000001, QStringLiteral("175.247"),
7.5076913385826796, QStringLiteral("0.198641"), 9.7351181102362219, QStringLiteral("0.257575"));
base = spl.GetLength();
step = 0;
do
{
QTest::newRow(qUtf8Printable(QStringLiteral("Curve 2. Step = %1").arg(step))) << spl << base * step;
step += 0.001;
}
while(step <= 1);
QTest::newRow(qUtf8Printable(QStringLiteral("Curve 2. Bug.").arg(step))) << spl << 4.7813492845686536;
}
//---------------------------------------------------------------------------------------------------------------------
void TST_VSpline::TestParametrT()
{
VPointF p1(1168.8582803149607, 39.999874015748034, "p1", 5.0000125984251973, 9.9999874015748045);
VPointF p4(681.33729132409951, 1815.7969526662778, "p4", 5.0000125984251973, 9.9999874015748045);
QFETCH(VSpline, spl);
QFETCH(qreal, length);
VSpline spl(p1, p4, 229.381, 41.6325, 0.96294100000000005, 1.00054, 1);
const qreal resLength = spl.RealLengthByT(spl.GetParmT(length));
const qreal halfLength = spl.GetLength()/2.0;
const qreal resLength = spl.LengthT(spl.GetParmT(halfLength));
QVERIFY(qAbs(halfLength - resLength) < UnitConvertor(0.5, Unit::Mm, Unit::Px));
QVERIFY(qAbs(length - resLength) < UnitConvertor(1, Unit::Mm, Unit::Px));
}
//---------------------------------------------------------------------------------------------------------------------

View File

@ -49,6 +49,7 @@ private slots:
void GetSegmentPoints_RotateTool();
void GetSegmentPoints_issue767();
void CompareThreeWays();
void TestParametrT_data();
void TestParametrT();
void TestLengthByPoint_data();
void TestLengthByPoint();