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)
{
QPainterPath splinePath;
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();
return PathLength(GetCubicBezierPoints(p1, p2, p3, p4));
}
//---------------------------------------------------------------------------------------------------------------------

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.first().toPoint() == begin.toPoint())
{
if (ok != nullptr)
{
*ok = true;
}
return points;
}
QVector<QPointF> segment;
bool theBegin = false;
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 (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<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);
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<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
@ -257,3 +300,15 @@ QPainterPath VAbstractCurve::ShowDirection(const QVector<QPointF> &points) const
}
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 qreal GetLength() const =0;
qreal GetLengthByPoint(const QPointF &point) const;
virtual QVector<QPointF> IntersectLine(const QLineF &line) const;
virtual bool IsIntersectLine(const QLineF &line) const;
@ -74,11 +75,12 @@ public:
protected:
QPainterPath ShowDirection(const QVector<QPointF> &points) const;
virtual void CreateName() =0;
static qreal PathLength(const QVector<QPointF> &path);
private:
QSharedDataPointer<VAbstractCurveData> d;
static QVector<QPointF> FromBegin(const QVector<QPointF> &points, const QPointF &begin);
static QVector<QPointF> ToEnd(const QVector<QPointF> &points, const QPointF &end);
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, bool *ok = nullptr);
};
Q_DECLARE_TYPEINFO(VAbstractCurve, Q_MOVABLE_TYPE);

View file

@ -128,15 +128,7 @@ VEllipticalArc::~VEllipticalArc()
*/
qreal VEllipticalArc::GetLength() const
{
qreal length = 0;
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();
qreal length = PathLength(GetPoints());
if (d->isFlipped)
{

View file

@ -531,10 +531,12 @@ QVector<QPointF> VGObject::GetReversePoints(const QVector<QPointF> &points)
{
return points;
}
QVector<QPointF> reversePoints;
QVector<QPointF> 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;
}

View file

@ -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

View file

@ -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<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
{

View file

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