From 9470f76ba90084906b80c44722ecc8ebe8465a2f Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Sat, 2 Apr 2016 14:59:43 +0300 Subject: [PATCH] New method curve length by given point. --HG-- branch : develop --- src/libs/vgeometry/vabstractcubicbezier.cpp | 9 +-- src/libs/vgeometry/vabstractcurve.cpp | 63 +++++++++++++++++++-- src/libs/vgeometry/vabstractcurve.h | 6 +- src/libs/vgeometry/vellipticalarc.cpp | 10 +--- src/libs/vgeometry/vgobject.cpp | 6 +- src/libs/vgeometry/vspline.h | 1 + src/test/ValentinaTest/tst_vspline.cpp | 35 ++++++++++++ src/test/ValentinaTest/tst_vspline.h | 2 + 8 files changed, 107 insertions(+), 25 deletions(-) diff --git a/src/libs/vgeometry/vabstractcubicbezier.cpp b/src/libs/vgeometry/vabstractcubicbezier.cpp index cc1172268..75b1f5434 100644 --- a/src/libs/vgeometry/vabstractcubicbezier.cpp +++ b/src/libs/vgeometry/vabstractcubicbezier.cpp @@ -524,14 +524,7 @@ QVector VAbstractCubicBezier::GetCubicBezierPoints(const QPointF &p1, c */ qreal VAbstractCubicBezier::LengthBezier(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4) { - QPainterPath splinePath; - QVector points = GetCubicBezierPoints(p1, p2, p3, p4); - splinePath.moveTo(points.at(0)); - for (qint32 i = 1; i < points.count(); ++i) - { - splinePath.lineTo(points.at(i)); - } - return splinePath.length(); + return PathLength(GetCubicBezierPoints(p1, p2, p3, p4)); } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/libs/vgeometry/vabstractcurve.cpp b/src/libs/vgeometry/vabstractcurve.cpp index 431549162..ec79e104c 100644 --- a/src/libs/vgeometry/vabstractcurve.cpp +++ b/src/libs/vgeometry/vabstractcurve.cpp @@ -89,10 +89,19 @@ QVector VAbstractCurve::GetSegmentPoints(const QPointF &begin, const QP //--------------------------------------------------------------------------------------------------------------------- -QVector VAbstractCurve::FromBegin(const QVector &points, const QPointF &begin) +QVector VAbstractCurve::FromBegin(const QVector &points, const QPointF &begin, bool *ok) { if (points.count() >= 2) { + if (points.first().toPoint() == begin.toPoint()) + { + if (ok != nullptr) + { + *ok = true; + } + return points; + } + QVector segment; bool theBegin = false; for (qint32 i = 0; i < points.count()-1; ++i) @@ -122,25 +131,36 @@ QVector VAbstractCurve::FromBegin(const QVector &points, const if (segment.isEmpty()) { + if (ok != nullptr) + { + *ok = false; + } return points; } else { + if (ok != nullptr) + { + *ok = true; + } return segment; } } else { + if (ok != nullptr) + { + *ok = false; + } return points; } - return points; } //--------------------------------------------------------------------------------------------------------------------- -QVector VAbstractCurve::ToEnd(const QVector &points, const QPointF &end) +QVector VAbstractCurve::ToEnd(const QVector &points, const QPointF &end, bool *ok) { QVector reversed = GetReversePoints(points); - reversed = FromBegin(reversed, end); + reversed = FromBegin(reversed, end, ok); return GetReversePoints(reversed); } @@ -170,6 +190,29 @@ QPainterPath VAbstractCurve::GetPath(PathDirection direction) const return path; } +//--------------------------------------------------------------------------------------------------------------------- +qreal VAbstractCurve::GetLengthByPoint(const QPointF &point) const +{ + const QVector points = GetPoints(); + if (points.size() < 2) + { + return -1; + } + + if (points.first().toPoint() == point.toPoint()) + { + return 0; + } + + bool ok = false; + const QVector segment = ToEnd(points, point, &ok); + if (not ok) + { + return -1; + } + return PathLength(segment); +} + //--------------------------------------------------------------------------------------------------------------------- /** * @brief IntersectLine return list of points for real intersection with line @@ -257,3 +300,15 @@ QPainterPath VAbstractCurve::ShowDirection(const QVector &points) const } return path; } + +//--------------------------------------------------------------------------------------------------------------------- +qreal VAbstractCurve::PathLength(const QVector &path) +{ + QPainterPath splinePath; + splinePath.moveTo(path.at(0)); + for (qint32 i = 1; i < path.count(); ++i) + { + splinePath.lineTo(path.at(i)); + } + return splinePath.length(); +} diff --git a/src/libs/vgeometry/vabstractcurve.h b/src/libs/vgeometry/vabstractcurve.h index 77d4be482..1b3f5c8a5 100644 --- a/src/libs/vgeometry/vabstractcurve.h +++ b/src/libs/vgeometry/vabstractcurve.h @@ -59,6 +59,7 @@ public: virtual QPainterPath GetPath(PathDirection direction = PathDirection::Hide) const; virtual qreal GetLength() const =0; + qreal GetLengthByPoint(const QPointF &point) const; virtual QVector IntersectLine(const QLineF &line) const; virtual bool IsIntersectLine(const QLineF &line) const; @@ -74,11 +75,12 @@ public: protected: QPainterPath ShowDirection(const QVector &points) const; virtual void CreateName() =0; + static qreal PathLength(const QVector &path); private: QSharedDataPointer d; - static QVector FromBegin(const QVector &points, const QPointF &begin); - static QVector ToEnd(const QVector &points, const QPointF &end); + static QVector FromBegin(const QVector &points, const QPointF &begin, bool *ok = nullptr); + static QVector ToEnd(const QVector &points, const QPointF &end, bool *ok = nullptr); }; Q_DECLARE_TYPEINFO(VAbstractCurve, Q_MOVABLE_TYPE); diff --git a/src/libs/vgeometry/vellipticalarc.cpp b/src/libs/vgeometry/vellipticalarc.cpp index be50f5d6d..853e94ad4 100644 --- a/src/libs/vgeometry/vellipticalarc.cpp +++ b/src/libs/vgeometry/vellipticalarc.cpp @@ -128,15 +128,7 @@ VEllipticalArc::~VEllipticalArc() */ qreal VEllipticalArc::GetLength() const { - qreal length = 0; - QPainterPath elArc; - QVector points = GetPoints(); - elArc.moveTo(points.at(0)); - for (qint32 i = 1; i < points.count(); ++i) - { - elArc.lineTo(points.at(i)); - } - length = elArc.length(); + qreal length = PathLength(GetPoints()); if (d->isFlipped) { diff --git a/src/libs/vgeometry/vgobject.cpp b/src/libs/vgeometry/vgobject.cpp index adab12b34..2b4696b10 100644 --- a/src/libs/vgeometry/vgobject.cpp +++ b/src/libs/vgeometry/vgobject.cpp @@ -531,10 +531,12 @@ QVector VGObject::GetReversePoints(const QVector &points) { return points; } - QVector reversePoints; + QVector reversePoints(points.size()); + qint32 j = 0; for (qint32 i = points.size() - 1; i >= 0; --i) { - reversePoints.append(points.at(i)); + reversePoints.replace(j, points.at(i)); + ++j; } return reversePoints; } diff --git a/src/libs/vgeometry/vspline.h b/src/libs/vgeometry/vspline.h index 6b420ab3d..c92e4f907 100644 --- a/src/libs/vgeometry/vspline.h +++ b/src/libs/vgeometry/vspline.h @@ -107,6 +107,7 @@ private: static int Sign(long double ld); }; +Q_DECLARE_METATYPE(VSpline) Q_DECLARE_TYPEINFO(VSpline, Q_MOVABLE_TYPE); #endif // VSPLINE_H diff --git a/src/test/ValentinaTest/tst_vspline.cpp b/src/test/ValentinaTest/tst_vspline.cpp index 27d1ce216..3b4098dd1 100644 --- a/src/test/ValentinaTest/tst_vspline.cpp +++ b/src/test/ValentinaTest/tst_vspline.cpp @@ -307,6 +307,41 @@ void TST_VSpline::TestParametrT() QVERIFY(qAbs(halfLength - resLength) < UnitConvertor(0.5, Unit::Mm, Unit::Px)); } +//--------------------------------------------------------------------------------------------------------------------- +void TST_VSpline::TestLengthByPoint_data() +{ + VPointF p1(1168.8582803149607, 39.999874015748034, "p1", 5.0000125984251973, 9.9999874015748045); + VPointF p4(681.33729132409951, 1815.7969526662778, "p4", 5.0000125984251973, 9.9999874015748045); + + VSpline spl(p1, p4, 229.381, 41.6325, 0.96294100000000005, 1.00054, 1); + + QTest::addColumn("spl"); + QTest::addColumn("point"); + QTest::addColumn("length"); + + const qreal length = spl.GetLength(); + const qreal testLength = length*(2.0/3.0); + VSpline spl1, spl2; + const QPointF p = spl.CutSpline(testLength, spl1, spl2); + + QTest::newRow("Point on spline") << spl << p << testLength; + QTest::newRow("Wrong point") << spl << QPointF(-10000, -10000) << -1.0; + QTest::newRow("First point") << spl << p1.toQPointF() << 0.0; + QTest::newRow("Last point") << spl << p4.toQPointF() << length; +} + +//--------------------------------------------------------------------------------------------------------------------- +void TST_VSpline::TestLengthByPoint() +{ + QFETCH(VSpline, spl); + QFETCH(QPointF, point); + QFETCH(qreal, length); + + const qreal resLength = spl.GetLengthByPoint(point); + + QVERIFY(qAbs(resLength - length) < ToPixel(0.5, Unit::Mm)); +} + //--------------------------------------------------------------------------------------------------------------------- void TST_VSpline::CompareSplines(const VSpline &spl1, const VSpline &spl2) const { diff --git a/src/test/ValentinaTest/tst_vspline.h b/src/test/ValentinaTest/tst_vspline.h index bfd49e0c1..30937d5b5 100644 --- a/src/test/ValentinaTest/tst_vspline.h +++ b/src/test/ValentinaTest/tst_vspline.h @@ -48,6 +48,8 @@ private slots: void GetSegmentPoints_NullSegment(); void CompareThreeWays(); void TestParametrT(); + void TestLengthByPoint_data(); + void TestLengthByPoint(); private: Q_DISABLE_COPY(TST_VSpline)