Class VSpline now can be controlled by formulas.

--HG--
branch : feature
This commit is contained in:
Roman Telezhynskyi 2016-02-24 21:47:39 +02:00
parent 7024df4ab2
commit f2ee4cfd35
5 changed files with 294 additions and 71 deletions

View File

@ -82,6 +82,34 @@ VSpline::VSpline (VPointF p1, QPointF p2, QPointF p3, VPointF p4, qreal kCurve,
}
//---------------------------------------------------------------------------------------------------------------------
/**
* @brief VSpline constructor
* @param p1 first point spline.
* @param p4 first control point.
* @param angle1 angle from first point to first control point.
* @param angle1Formula formula angle from first point to first control point.
* @param angle2 angle from second point to second control point.
* @param angle2Formula formula angle from second point to second control point.
* @param c1Length length from first point to first control point.
* @param c1LengthFormula formula length from first point to first control point.
* @param c2Length length from second point to first control point.
* @param c2LengthFormula formula length from second point to first control point.
* @param kCurve coefficient of curvature spline.
* @param idObject
* @param mode
*/
VSpline::VSpline(VPointF p1, VPointF p4, qreal angle1, const QString &angle1Formula, qreal angle2,
const QString &angle2Formula, qreal c1Length, const QString &c1LengthFormula, qreal c2Length,
const QString &c2LengthFormula, qreal kCurve, quint32 idObject, Draw mode)
: VAbstractCurve(GOType::Spline, idObject, mode),
d(new VSplineData(p1, p4, angle1, angle1Formula, angle2,angle2Formula, c1Length, c1LengthFormula, c2Length,
c2LengthFormula, kCurve))
{
CreateName();
}
//---------------------------------------------------------------------------------------------------------------------
VSpline::~VSpline()
{}
@ -93,7 +121,7 @@ VSpline::~VSpline()
*/
qreal VSpline::GetLength () const
{
return LengthBezier ( GetP1().toQPointF(), d->p2, d->p3, GetP4().toQPointF());
return LengthBezier ( GetP1().toQPointF(), GetP2(), GetP3(), GetP4().toQPointF());
}
//---------------------------------------------------------------------------------------------------------------------
@ -222,7 +250,7 @@ QPointF VSpline::CutSpline(qreal length, VSpline &spl1, VSpline &spl2) const
*/
QVector<QPointF> VSpline::GetPoints () const
{
return GetPoints(GetP1().toQPointF(), d->p2, d->p3, GetP4().toQPointF());
return GetPoints(GetP1().toQPointF(), GetP2(), GetP3(), GetP4().toQPointF());
}
//---------------------------------------------------------------------------------------------------------------------
@ -589,8 +617,8 @@ void VSpline::PointBezier_r ( qreal x1, qreal y1, qreal x2, qreal y2,
*/
qreal VSpline::CalcSqDistance (qreal x1, qreal y1, qreal x2, qreal y2)
{
qreal dx = x2 - x1;
qreal dy = y2 - y1;
const qreal dx = x2 - x1;
const qreal dy = y2 - y1;
return dx * dx + dy * dy;
}
@ -668,7 +696,9 @@ VPointF VSpline::GetP1() const
*/
QPointF VSpline::GetP2() const
{
return d->p2;
QLineF p1p2(d->p1.x(), d->p1.y(), d->p1.x() + d->c1Length, d->p1.y());
p1p2.setAngle(d->angle1);
return p1p2.p2();
}
//---------------------------------------------------------------------------------------------------------------------
@ -678,7 +708,9 @@ QPointF VSpline::GetP2() const
*/
QPointF VSpline::GetP3() const
{
return d->p3;
QLineF p4p3(d->p4.x(), d->p4.y(), d->p4.x() + d->c2Length, d->p4.y());
p4p3.setAngle(d->angle2);
return p4p3.p2();
}
//---------------------------------------------------------------------------------------------------------------------
@ -711,6 +743,42 @@ qreal VSpline::GetEndAngle() const
return d->angle2;
}
//---------------------------------------------------------------------------------------------------------------------
QString VSpline::GetStartAngleFormula() const
{
return d->angle1F;
}
//---------------------------------------------------------------------------------------------------------------------
QString VSpline::GetEndAngleFormula() const
{
return d->angle2F;
}
//---------------------------------------------------------------------------------------------------------------------
qreal VSpline::GetC1Length() const
{
return d->c1Length;
}
//---------------------------------------------------------------------------------------------------------------------
qreal VSpline::GetC2Length() const
{
return d->c2Length;
}
//---------------------------------------------------------------------------------------------------------------------
QString VSpline::C1LengthFormula() const
{
return d->c1LengthF;
}
//---------------------------------------------------------------------------------------------------------------------
QString VSpline::C2LengthFormula() const
{
return d->c2LengthF;
}
//---------------------------------------------------------------------------------------------------------------------
/**
* @brief GetKasm1 return coefficient of length first control line.
@ -718,7 +786,8 @@ qreal VSpline::GetEndAngle() const
*/
qreal VSpline::GetKasm1() const
{
return d->kAsm1;
return QLineF(d->p1.toQPointF(), GetP2()).length() / VSplineData::GetL(d->p1.toQPointF(), d->p4.toQPointF(),
d->kCurve);
}
//---------------------------------------------------------------------------------------------------------------------
@ -728,7 +797,8 @@ qreal VSpline::GetKasm1() const
*/
qreal VSpline::GetKasm2() const
{
return d->kAsm2;
return QLineF(d->p4.toQPointF(), GetP3()).length() / VSplineData::GetL(d->p1.toQPointF(), d->p4.toQPointF(),
d->kCurve);
}
//---------------------------------------------------------------------------------------------------------------------
@ -846,8 +916,8 @@ qreal VSpline::ParamT (const QPointF &pBt) const
{
QVector<qreal> ts;
// Calculate t coefficient for each axis
ts += CalcT (GetP1().toQPointF().x(), d->p2.x(), d->p3.x(), GetP4().toQPointF().x(), pBt.x());
ts += CalcT (GetP1().toQPointF().y(), d->p2.y(), d->p3.y(), GetP4().toQPointF().y(), pBt.y());
ts += CalcT (GetP1().toQPointF().x(), GetP2().x(), GetP3().x(), GetP4().toQPointF().x(), pBt.x());
ts += CalcT (GetP1().toQPointF().y(), GetP2().y(), GetP3().y(), GetP4().toQPointF().y(), pBt.y());
if (ts.isEmpty())
{
@ -863,8 +933,8 @@ qreal VSpline::ParamT (const QPointF &pBt) const
{
const qreal t = ts.at(i);
const QPointF p0 = GetP1().toQPointF();
const QPointF p1 = d->p2;
const QPointF p2 = d->p3;
const QPointF p1 = GetP2();
const QPointF p2 = GetP3();
const QPointF p3 = GetP4().toQPointF();
//The explicit form of the Cubic Bézier curve
const qreal pointX = pow(1-t, 3)*p0.x() + 3*pow(1-t, 2)*t*p1.x() + 3*(1-t)*pow(t, 2)*p2.x() + pow(t, 3)*p3.x();

View File

@ -51,6 +51,9 @@ public:
quint32 idObject = 0, Draw mode = Draw::Calculation);
VSpline (VPointF p1, QPointF p2, QPointF p3, VPointF p4, qreal kCurve, quint32 idObject = 0,
Draw mode = Draw::Calculation);
VSpline (VPointF p1, VPointF p4, qreal angle1, const QString &angle1Formula, qreal angle2,
const QString &angle2Formula, qreal c1Length, const QString &c1LengthFormula, qreal c2Length,
const QString &c2LengthFormula, qreal kCurve, quint32 idObject = 0, Draw mode = Draw::Calculation);
virtual ~VSpline() Q_DECL_OVERRIDE;
VSpline &operator=(const VSpline &spl);
VPointF GetP1 () const;
@ -61,6 +64,15 @@ public:
virtual qreal GetStartAngle () const Q_DECL_OVERRIDE;
virtual qreal GetEndAngle() const Q_DECL_OVERRIDE;
QString GetStartAngleFormula () const;
QString GetEndAngleFormula() const;
qreal GetC1Length() const;
qreal GetC2Length() const;
QString C1LengthFormula() const;
QString C2LengthFormula() const;
qreal GetLength () const;
qreal GetKasm1() const;
qreal GetKasm2() const;

View File

@ -42,85 +42,171 @@
class VSplineData : public QSharedData
{
public:
VSplineData()
:p1(VPointF()), p2(QPointF()), p3(QPointF()), p4(VPointF()), angle1(0), angle2(0), kAsm1(1), kAsm2(1), kCurve(1)
{}
VSplineData ( const VSplineData &spline )
:QSharedData(spline), p1(spline.p1), p2(spline.p2), p3(spline.p3), p4(spline.p4), angle1(spline.angle1),
angle2(spline.angle2), kAsm1(spline.kAsm1), kAsm2(spline.kAsm2), kCurve(spline.kCurve)
{}
VSplineData (VPointF p1, VPointF p4, qreal angle1, qreal angle2, qreal kAsm1, qreal kAsm2, qreal kCurve)
:p1(p1), p2(QPointF()), p3(QPointF()), p4(p4), angle1(angle1), angle2(angle2), kAsm1(kAsm1), kAsm2(kAsm2),
kCurve(kCurve)
{
qreal L = 0, radius = 0, angle = 90;
QPointF point1 = this->p1.toQPointF();
QPointF point4 = this->p4.toQPointF();
radius = QLineF(point1, point4).length()/M_SQRT2;
L = kCurve * radius * 4 / 3 * tan( angle * M_PI / 180.0 / 4 );
QLineF p1p2(this->p1.x(), this->p1.y(), this->p1.x() + L * kAsm1, this->p1.y());
p1p2.setAngle(angle1);
QLineF p4p3(this->p4.x(), this->p4.y(), this->p4.x() + L * kAsm2, this->p4.y());
p4p3.setAngle(angle2);
this->p2 = p1p2.p2();
this->p3 = p4p3.p2();
}
VSplineData (VPointF p1, QPointF p2, QPointF p3, VPointF p4, qreal kCurve)
:p1(p1), p2(p2), p3(p3), p4(p4), angle1(0), angle2(0), kAsm1(1), kAsm2(1), kCurve(1)
{
this->angle1 = QLineF ( this->p1.toQPointF(), this->p2 ).angle();
this->angle2 = QLineF ( this->p4.toQPointF(), this->p3 ).angle();
qreal L = 0, radius = 0, angle = 90;
QPointF point1 = this->p1.toQPointF();
QPointF point4 = this->p4.toQPointF();
radius = QLineF(point1, point4).length()/M_SQRT2;
L = kCurve * radius * 4 / 3 * tan( angle * M_PI / 180.0 / 4 );
this->kCurve = kCurve;
this->kAsm1 = QLineF ( this->p1.toQPointF(), this->p2 ).length()/L;
this->kAsm2 = QLineF ( this->p4.toQPointF(), this->p3 ).length()/L;
}
VSplineData();
VSplineData(const VSplineData &spline);
VSplineData(VPointF p1, VPointF p4, qreal angle1, qreal angle2, qreal kAsm1, qreal kAsm2, qreal kCurve);
VSplineData(VPointF p1, QPointF p2, QPointF p3, VPointF p4, qreal kCurve);
VSplineData(VPointF p1, VPointF p4, qreal angle1, const QString &angle1F, qreal angle2, const QString &angle2F,
qreal c1Length, const QString &c1LengthF, qreal c2Length, const QString &c2LengthF, qreal kCurve);
virtual ~VSplineData();
static qreal GetL(const QPointF &p1, const QPointF &p4, qreal kCurve);
/** @brief p1 first spline point. */
VPointF p1;
VPointF p1;
/** @brief p2 first control point. */
QPointF p2;
/** @brief p3 second control point. */
QPointF p3;
/** @brief p4 last spline point. */
VPointF p4;
/** @brief p4 fourth spline point. */
VPointF p4;
/** @brief angle1 first angle control line. */
qreal angle1;
qreal angle1;
/** @brief angle1F the first control point angle formula*/
QString angle1F;
/** @brief angle2 second angle control line. */
qreal angle2;
qreal angle2;
/** @brief kAsm1 coefficient of length first control line. */
qreal kAsm1;
/** @brief angle2F the second control point angle formula*/
QString angle2F;
/** @brief kAsm2 coefficient of length second control line. */
qreal kAsm2;
/** @brief c1Length the length from the first spline point to the first control point. */
qreal c1Length;
/** @brief c1LengthF the formula from the first spline point to the first control point. */
QString c1LengthF;
/** @brief c2Length the length from the fourth spline point to the second control point. */
qreal c2Length;
/** @brief c2LengthF the formula length from the fourth spline point to the second control point. */
QString c2LengthF;
/** @brief kCurve coefficient of curvature spline. */
qreal kCurve;
qreal kCurve;
private:
VSplineData &operator=(const VSplineData &) Q_DECL_EQ_DELETE;
};
//---------------------------------------------------------------------------------------------------------------------
VSplineData::VSplineData()
: p1(),
p4(),
angle1(0),
angle1F("0"),
angle2(0),
angle2F("0"),
c1Length(0),
c1LengthF("0"),
c2Length(0),
c2LengthF("0"),
kCurve(1)
{}
//---------------------------------------------------------------------------------------------------------------------
VSplineData::VSplineData(const VSplineData &spline)
: QSharedData(spline),
p1(spline.p1),
p4(spline.p4),
angle1(spline.angle1),
angle1F(spline.angle1F),
angle2(spline.angle2),
angle2F(spline.angle2F),
c1Length(spline.c1Length),
c1LengthF(spline.c1LengthF),
c2Length(spline.c2Length),
c2LengthF(spline.c2LengthF),
kCurve(spline.kCurve)
{}
//---------------------------------------------------------------------------------------------------------------------
VSplineData::VSplineData(VPointF p1, VPointF p4, qreal angle1, qreal angle2, qreal kAsm1, qreal kAsm2, qreal kCurve)
: p1(p1),
p4(p4),
angle1(angle1),
angle1F(QString().number(angle1)),
angle2(angle2),
angle2F(QString().number(angle2)),
c1Length(0),
c1LengthF("0"),
c2Length(0),
c2LengthF("0"),
kCurve(kCurve)
{
const qreal L = GetL(p1.toQPointF(), p4.toQPointF(), kCurve);
QLineF p1p2(p1.x(), p1.y(), p1.x() + L * kAsm1, p1.y());
p1p2.setAngle(angle1);
c1Length = p1p2.length();
c1LengthF = QString().number(c1Length);
QLineF p4p3(p4.x(), p4.y(), p4.x() + L * kAsm2, p4.y());
p4p3.setAngle(angle2);
c2Length = p4p3.length();
c2LengthF = QString().number(c2Length);
}
//---------------------------------------------------------------------------------------------------------------------
VSplineData::VSplineData(VPointF p1, QPointF p2, QPointF p3, VPointF p4, qreal kCurve)
: p1(p1),
p4(p4),
angle1(0),
angle1F("0"),
angle2(0),
angle2F("0"),
c1Length(0),
c1LengthF("0"),
c2Length(0),
c2LengthF("0"),
kCurve(kCurve)
{
QLineF p1p2(p1.toQPointF(), p2);
angle1 = p1p2.angle();
angle1F = QString().number(angle1);
c1Length = p1p2.length();
c1LengthF = QString().number(c1Length);
QLineF p4p3(p4.toQPointF(), p3);
angle2 = p4p3.angle();
angle2F = QString().number(angle2);
c2Length = p4p3.length();
c2LengthF = QString().number(c2Length);
}
//---------------------------------------------------------------------------------------------------------------------
VSplineData::VSplineData(VPointF p1, VPointF p4, qreal angle1, const QString &angle1F, qreal angle2,
const QString &angle2F, qreal c1Length, const QString &c1LengthF,
qreal c2Length, const QString &c2LengthF, qreal kCurve)
: p1(p1),
p4(p4),
angle1(angle1),
angle1F(angle1F),
angle2(angle2),
angle2F(angle2F),
c1Length(c1Length),
c1LengthF(c1LengthF),
c2Length(c2Length),
c2LengthF(c2LengthF),
kCurve(kCurve)
{}
//---------------------------------------------------------------------------------------------------------------------
VSplineData::~VSplineData()
{}
//---------------------------------------------------------------------------------------------------------------------
qreal VSplineData::GetL(const QPointF &p1, const QPointF &p4, qreal kCurve)
{
static const qreal angle = 90;
const qreal radius = QLineF(p1, p4).length()/M_SQRT2;
return kCurve * radius * 4 / 3 * qTan( angle * M_PI_4 / 180.0 );
}
#ifdef Q_CC_GNU
#pragma GCC diagnostic pop
#endif

View File

@ -179,3 +179,51 @@ void TST_VSpline::GetSegmentPoints_TestPuzzle()
// Begin comparison
Comparison(points, origPoints);
}
//---------------------------------------------------------------------------------------------------------------------
void TST_VSpline::CompareThreeWays()
{
// Input data taken from real case
// See the file <root>/src/app/share/collection/TestPuzzle.val
VPointF p1(1168.8582803149607, 39.999874015748034, "p1", 5.0000125984251973, 9.9999874015748045);
VPointF p4(681.33729132409951, 1815.7969526662778, "p4", 5.0000125984251973, 9.9999874015748045);
VSpline spl1(p1, p4, 229.381, 41.6325, 0.96294100000000005, 1.00054, 1);
VSpline spl2(spl1.GetP1(), spl1.GetP2(), spl1.GetP3(), spl1.GetP4(), 1);
VSpline spl3(spl1.GetP1(), spl1.GetP4(), spl1.GetStartAngle(), "", spl2.GetEndAngle(), "", spl2.GetC1Length(), "",
spl2.GetC2Length(), "", 1);
QWARN("Comparing first and second splines.");
CompareSplines(spl1, spl2);
QWARN("Comparing second and third splines.");
CompareSplines(spl2, spl3);
QWARN("Comparing third and first splines.");
CompareSplines(spl3, spl1);
}
//---------------------------------------------------------------------------------------------------------------------
void TST_VSpline::CompareSplines(const VSpline &spl1, const VSpline &spl2) const
{
QCOMPARE(spl1.GetP1().toQPointF().toPoint(), spl2.GetP1().toQPointF().toPoint());
QCOMPARE(spl1.GetP2().toPoint(), spl2.GetP2().toPoint());
QCOMPARE(spl1.GetP3().toPoint(), spl2.GetP3().toPoint());
QCOMPARE(spl1.GetP4().toQPointF().toPoint(), spl2.GetP4().toQPointF().toPoint());
QCOMPARE(spl1.GetStartAngle(), spl2.GetStartAngle());
QCOMPARE(spl1.GetEndAngle(), spl2.GetEndAngle());
QCOMPARE(spl1.GetC1Length(), spl2.GetC1Length());
QCOMPARE(spl1.GetC2Length(), spl2.GetC2Length());
QCOMPARE(spl1.GetLength(), spl2.GetLength());
QCOMPARE(spl1.GetKasm1(), spl2.GetKasm1());
QCOMPARE(spl1.GetKasm2(), spl2.GetKasm2());
QCOMPARE(spl1.GetKcurve(), spl2.GetKcurve());
// Compare points
Comparison(spl1.GetPoints(), spl2.GetPoints());
}

View File

@ -31,6 +31,8 @@
#include "abstracttest.h"
class VSpline;
class TST_VSpline : public AbstractTest
{
Q_OBJECT
@ -43,6 +45,11 @@ private slots:
void GetSegmentPoints();
void GetSegmentPoints_issue412();
void GetSegmentPoints_TestPuzzle();
void CompareThreeWays();
private:
Q_DISABLE_COPY(TST_VSpline)
void CompareSplines(const VSpline &spl1, const VSpline &spl2) const;
};
#endif // TST_VSPLINE_H