New method curve length by given point.

--HG--
branch : develop
This commit is contained in:
Roman Telezhynskyi 2016-04-02 14:59:43 +03:00
parent c99cdb69ec
commit 9470f76ba9
8 changed files with 107 additions and 25 deletions

View file

@ -524,14 +524,7 @@ QVector<QPointF> VAbstractCubicBezier::GetCubicBezierPoints(const QPointF &p1, c
*/ */
qreal VAbstractCubicBezier::LengthBezier(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4) qreal VAbstractCubicBezier::LengthBezier(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4)
{ {
QPainterPath splinePath; return PathLength(GetCubicBezierPoints(p1, p2, p3, p4));
QVector<QPointF> 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();
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------

View file

@ -89,10 +89,19 @@ QVector<QPointF> VAbstractCurve::GetSegmentPoints(const QPointF &begin, const QP
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
QVector<QPointF> VAbstractCurve::FromBegin(const QVector<QPointF> &points, const QPointF &begin) QVector<QPointF> VAbstractCurve::FromBegin(const QVector<QPointF> &points, const QPointF &begin, bool *ok)
{ {
if (points.count() >= 2) if (points.count() >= 2)
{ {
if (points.first().toPoint() == begin.toPoint())
{
if (ok != nullptr)
{
*ok = true;
}
return points;
}
QVector<QPointF> segment; QVector<QPointF> segment;
bool theBegin = false; bool theBegin = false;
for (qint32 i = 0; i < points.count()-1; ++i) for (qint32 i = 0; i < points.count()-1; ++i)
@ -122,25 +131,36 @@ QVector<QPointF> VAbstractCurve::FromBegin(const QVector<QPointF> &points, const
if (segment.isEmpty()) if (segment.isEmpty())
{ {
if (ok != nullptr)
{
*ok = false;
}
return points; return points;
} }
else else
{ {
if (ok != nullptr)
{
*ok = true;
}
return segment; return segment;
} }
} }
else else
{ {
if (ok != nullptr)
{
*ok = false;
}
return points; return points;
} }
return points;
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
QVector<QPointF> VAbstractCurve::ToEnd(const QVector<QPointF> &points, const QPointF &end) QVector<QPointF> VAbstractCurve::ToEnd(const QVector<QPointF> &points, const QPointF &end, bool *ok)
{ {
QVector<QPointF> reversed = GetReversePoints(points); QVector<QPointF> reversed = GetReversePoints(points);
reversed = FromBegin(reversed, end); reversed = FromBegin(reversed, end, ok);
return GetReversePoints(reversed); return GetReversePoints(reversed);
} }
@ -170,6 +190,29 @@ QPainterPath VAbstractCurve::GetPath(PathDirection direction) const
return path; return path;
} }
//---------------------------------------------------------------------------------------------------------------------
qreal VAbstractCurve::GetLengthByPoint(const QPointF &point) const
{
const QVector<QPointF> points = GetPoints();
if (points.size() < 2)
{
return -1;
}
if (points.first().toPoint() == point.toPoint())
{
return 0;
}
bool ok = false;
const QVector<QPointF> segment = ToEnd(points, point, &ok);
if (not ok)
{
return -1;
}
return PathLength(segment);
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
/** /**
* @brief IntersectLine return list of points for real intersection with line * @brief IntersectLine return list of points for real intersection with line
@ -257,3 +300,15 @@ QPainterPath VAbstractCurve::ShowDirection(const QVector<QPointF> &points) const
} }
return path; return path;
} }
//---------------------------------------------------------------------------------------------------------------------
qreal VAbstractCurve::PathLength(const QVector<QPointF> &path)
{
QPainterPath splinePath;
splinePath.moveTo(path.at(0));
for (qint32 i = 1; i < path.count(); ++i)
{
splinePath.lineTo(path.at(i));
}
return splinePath.length();
}

View file

@ -59,6 +59,7 @@ public:
virtual QPainterPath GetPath(PathDirection direction = PathDirection::Hide) const; virtual QPainterPath GetPath(PathDirection direction = PathDirection::Hide) const;
virtual qreal GetLength() const =0; virtual qreal GetLength() const =0;
qreal GetLengthByPoint(const QPointF &point) const;
virtual QVector<QPointF> IntersectLine(const QLineF &line) const; virtual QVector<QPointF> IntersectLine(const QLineF &line) const;
virtual bool IsIntersectLine(const QLineF &line) const; virtual bool IsIntersectLine(const QLineF &line) const;
@ -74,11 +75,12 @@ public:
protected: protected:
QPainterPath ShowDirection(const QVector<QPointF> &points) const; QPainterPath ShowDirection(const QVector<QPointF> &points) const;
virtual void CreateName() =0; virtual void CreateName() =0;
static qreal PathLength(const QVector<QPointF> &path);
private: private:
QSharedDataPointer<VAbstractCurveData> d; QSharedDataPointer<VAbstractCurveData> d;
static QVector<QPointF> FromBegin(const QVector<QPointF> &points, const QPointF &begin); static QVector<QPointF> FromBegin(const QVector<QPointF> &points, const QPointF &begin, bool *ok = nullptr);
static QVector<QPointF> ToEnd(const QVector<QPointF> &points, const QPointF &end); static QVector<QPointF> ToEnd(const QVector<QPointF> &points, const QPointF &end, bool *ok = nullptr);
}; };
Q_DECLARE_TYPEINFO(VAbstractCurve, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(VAbstractCurve, Q_MOVABLE_TYPE);

View file

@ -128,15 +128,7 @@ VEllipticalArc::~VEllipticalArc()
*/ */
qreal VEllipticalArc::GetLength() const qreal VEllipticalArc::GetLength() const
{ {
qreal length = 0; qreal length = PathLength(GetPoints());
QPainterPath elArc;
QVector<QPointF> points = GetPoints();
elArc.moveTo(points.at(0));
for (qint32 i = 1; i < points.count(); ++i)
{
elArc.lineTo(points.at(i));
}
length = elArc.length();
if (d->isFlipped) if (d->isFlipped)
{ {

View file

@ -531,10 +531,12 @@ QVector<QPointF> VGObject::GetReversePoints(const QVector<QPointF> &points)
{ {
return points; return points;
} }
QVector<QPointF> reversePoints; QVector<QPointF> reversePoints(points.size());
qint32 j = 0;
for (qint32 i = points.size() - 1; i >= 0; --i) for (qint32 i = points.size() - 1; i >= 0; --i)
{ {
reversePoints.append(points.at(i)); reversePoints.replace(j, points.at(i));
++j;
} }
return reversePoints; return reversePoints;
} }

View file

@ -107,6 +107,7 @@ private:
static int Sign(long double ld); static int Sign(long double ld);
}; };
Q_DECLARE_METATYPE(VSpline)
Q_DECLARE_TYPEINFO(VSpline, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(VSpline, Q_MOVABLE_TYPE);
#endif // VSPLINE_H #endif // VSPLINE_H

View file

@ -307,6 +307,41 @@ void TST_VSpline::TestParametrT()
QVERIFY(qAbs(halfLength - resLength) < UnitConvertor(0.5, Unit::Mm, Unit::Px)); 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<VSpline>("spl");
QTest::addColumn<QPointF>("point");
QTest::addColumn<qreal>("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 void TST_VSpline::CompareSplines(const VSpline &spl1, const VSpline &spl2) const
{ {

View file

@ -48,6 +48,8 @@ private slots:
void GetSegmentPoints_NullSegment(); void GetSegmentPoints_NullSegment();
void CompareThreeWays(); void CompareThreeWays();
void TestParametrT(); void TestParametrT();
void TestLengthByPoint_data();
void TestLengthByPoint();
private: private:
Q_DISABLE_COPY(TST_VSpline) Q_DISABLE_COPY(TST_VSpline)