1 /************************************************************************
2  **
3  **  @file   vspline.cpp
4  **  @author Roman Telezhynskyi <dismine(at)gmail.com>
5  **  @date   November 15, 2013
6  **
7  **  @brief
8  **  @copyright
9  **  This source code is part of the Valentina project, a pattern making
10  **  program, whose allow create and modeling patterns of clothing.
11  **  Copyright (C) 2013-2015 Valentina project
12  **  <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
13  **
14  **  Valentina is free software: you can redistribute it and/or modify
15  **  it under the terms of the GNU General Public License as published by
16  **  the Free Software Foundation, either version 3 of the License, or
17  **  (at your option) any later version.
18  **
19  **  Valentina is distributed in the hope that it will be useful,
20  **  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  **  GNU General Public License for more details.
23  **
24  **  You should have received a copy of the GNU General Public License
25  **  along with Valentina.  If not, see <http://www.gnu.org/licenses/>.
26  **
27  *************************************************************************/
28 
29 #include "vspline.h"
30 
31 #include <QJsonObject>
32 #include <QLineF>
33 
34 #include "vabstractcurve.h"
35 #include "vspline_p.h"
36 #include "../vmisc/vmath.h"
37 
38 //---------------------------------------------------------------------------------------------------------------------
39 /**
40  * @brief VSpline default constructor
41  */
VSpline()42 VSpline::VSpline()
43     :VAbstractCubicBezier(GOType::Spline), d(new VSplineData)
44 {}
45 
46 //---------------------------------------------------------------------------------------------------------------------
47 /**
48  * @brief VSpline constructor.
49  * @param spline spline from which the copy.
50  */
VSpline(const VSpline & spline)51 VSpline::VSpline ( const VSpline & spline )
52     :VAbstractCubicBezier(spline), d(spline.d)
53 {}
54 
55 //---------------------------------------------------------------------------------------------------------------------
56 /**
57  * @brief VSpline constructor.
58  * @param p1 first point spline.
59  * @param p4 last point spline.
60  * @param angle1 angle from first point to first control point.
61  * @param angle2 angle from second point to second control point.
62  * @param kCurve coefficient of curvature spline.
63  * @param kAsm1 coefficient of length first control line.
64  * @param kAsm2 coefficient of length second control line.
65  */
VSpline(const VPointF & p1,const VPointF & p4,qreal angle1,qreal angle2,qreal kAsm1,qreal kAsm2,qreal kCurve,quint32 idObject,Draw mode)66 VSpline::VSpline (const VPointF &p1, const VPointF &p4, qreal angle1, qreal angle2, qreal kAsm1, qreal kAsm2,
67                   qreal kCurve, quint32 idObject, Draw mode)
68     : VAbstractCubicBezier(GOType::Spline, idObject, mode),
69       d(new VSplineData(p1, p4, angle1, angle2, kAsm1, kAsm2, kCurve))
70 {
71     CreateName();
72 }
73 
74 //---------------------------------------------------------------------------------------------------------------------
75 /**
76  * @brief VSpline constructor.
77  * @param p1 first point spline.
78  * @param p2 first control point.
79  * @param p3 second control point.
80  * @param p4 second point spline.
81  */
VSpline(const VPointF & p1,const QPointF & p2,const QPointF & p3,const VPointF & p4,quint32 idObject,Draw mode)82 VSpline::VSpline (const VPointF &p1, const QPointF &p2, const QPointF &p3, const VPointF &p4, quint32 idObject,
83                   Draw mode)
84     :VAbstractCubicBezier(GOType::Spline, idObject, mode), d(new VSplineData(p1, p2, p3, p4))
85 {
86     CreateName();
87 }
88 
89 
90 //---------------------------------------------------------------------------------------------------------------------
91 /**
92  * @brief VSpline constructor
93  * @param p1 first point spline.
94  * @param p4 first control point.
95  * @param angle1 angle from first point to first control point.
96  * @param angle1Formula formula angle from first point to first control point.
97  * @param angle2 angle from second point to second control point.
98  * @param angle2Formula formula angle from second point to second control point.
99  * @param c1Length length from first point to first control point.
100  * @param c1LengthFormula formula length from first point to first control point.
101  * @param c2Length length from second point to first control point.
102  * @param c2LengthFormula formula length from second point to first control point.
103  */
VSpline(const VPointF & p1,const VPointF & p4,qreal angle1,const QString & angle1Formula,qreal angle2,const QString & angle2Formula,qreal c1Length,const QString & c1LengthFormula,qreal c2Length,const QString & c2LengthFormula,quint32 idObject,Draw mode)104 VSpline::VSpline(const VPointF &p1, const VPointF &p4, qreal angle1, const QString &angle1Formula, qreal angle2,
105                  const QString &angle2Formula, qreal c1Length, const QString &c1LengthFormula, qreal c2Length,
106                  const QString &c2LengthFormula, quint32 idObject, Draw mode)
107     : VAbstractCubicBezier(GOType::Spline, idObject, mode),
108       d(new VSplineData(p1, p4, angle1, angle1Formula, angle2, angle2Formula, c1Length, c1LengthFormula, c2Length,
109                         c2LengthFormula))
110 {
111     CreateName();
112 }
113 
114 //---------------------------------------------------------------------------------------------------------------------
Rotate(const QPointF & originPoint,qreal degrees,const QString & prefix) const115 VSpline VSpline::Rotate(const QPointF &originPoint, qreal degrees, const QString &prefix) const
116 {
117     const VPointF p1 = GetP1().Rotate(originPoint, degrees);
118     const VPointF p4 = GetP4().Rotate(originPoint, degrees);
119 
120     const QPointF p2 = VPointF::RotatePF(originPoint, static_cast<QPointF>(GetP2()), degrees);
121     const QPointF p3 = VPointF::RotatePF(originPoint, static_cast<QPointF>(GetP3()), degrees);
122 
123     VSpline spl(p1, p2, p3, p4);
124     spl.setName(name() + prefix);
125 
126     if (not GetAliasSuffix().isEmpty())
127     {
128         spl.SetAliasSuffix(GetAliasSuffix() + prefix);
129     }
130 
131     spl.SetColor(GetColor());
132     spl.SetPenStyle(GetPenStyle());
133     spl.SetApproximationScale(GetApproximationScale());
134     return spl;
135 }
136 
137 //---------------------------------------------------------------------------------------------------------------------
Flip(const QLineF & axis,const QString & prefix) const138 VSpline VSpline::Flip(const QLineF &axis, const QString &prefix) const
139 {
140     const VPointF p1 = GetP1().Flip(axis);
141     const VPointF p4 = GetP4().Flip(axis);
142 
143     const QPointF p2 = VPointF::FlipPF(axis, static_cast<QPointF>(GetP2()));
144     const QPointF p3 = VPointF::FlipPF(axis, static_cast<QPointF>(GetP3()));
145 
146     VSpline spl(p1, p2, p3, p4);
147     spl.setName(name() + prefix);
148 
149     if (not GetAliasSuffix().isEmpty())
150     {
151         spl.SetAliasSuffix(GetAliasSuffix() + prefix);
152     }
153 
154     spl.SetColor(GetColor());
155     spl.SetPenStyle(GetPenStyle());
156     spl.SetApproximationScale(GetApproximationScale());
157     return spl;
158 }
159 
160 //---------------------------------------------------------------------------------------------------------------------
Move(qreal length,qreal angle,const QString & prefix) const161 VSpline VSpline::Move(qreal length, qreal angle, const QString &prefix) const
162 {
163     const VPointF p1 = GetP1().Move(length, angle);
164     const VPointF p4 = GetP4().Move(length, angle);
165 
166     const QPointF p2 = VPointF::MovePF(static_cast<QPointF>(GetP2()), length, angle);
167     const QPointF p3 = VPointF::MovePF(static_cast<QPointF>(GetP3()), length, angle);
168 
169     VSpline spl(p1, p2, p3, p4);
170     spl.setName(name() + prefix);
171 
172     if (not GetAliasSuffix().isEmpty())
173     {
174         spl.SetAliasSuffix(GetAliasSuffix() + prefix);
175     }
176 
177     spl.SetColor(GetColor());
178     spl.SetPenStyle(GetPenStyle());
179     spl.SetApproximationScale(GetApproximationScale());
180     return spl;
181 }
182 
183 //---------------------------------------------------------------------------------------------------------------------
~VSpline()184 VSpline::~VSpline()
185 {}
186 
187 //---------------------------------------------------------------------------------------------------------------------
188 /**
189  * @brief GetLength return length of spline.
190  * @return length.
191  */
GetLength() const192 qreal VSpline::GetLength () const
193 {
194     return LengthBezier ( static_cast<QPointF>(GetP1()), static_cast<QPointF>(GetP2()), static_cast<QPointF>(GetP3()),
195                           static_cast<QPointF>(GetP4()), GetApproximationScale());
196 }
197 
198 //---------------------------------------------------------------------------------------------------------------------
CutSpline(qreal length,VSpline & spl1,VSpline & spl2) const199 QPointF VSpline::CutSpline(qreal length, VSpline &spl1, VSpline &spl2) const
200 {
201     QPointF spl1p2;
202     QPointF spl1p3;
203     QPointF spl2p2;
204     QPointF spl2p3;
205     const QPointF cutPoint = CutSpline (length, spl1p2, spl1p3, spl2p2, spl2p3 );
206 
207     spl1 = VSpline(GetP1(), spl1p2, spl1p3, VPointF(cutPoint));
208     spl1.SetApproximationScale(GetApproximationScale());
209 
210     spl2 = VSpline(VPointF(cutPoint), spl2p2, spl2p3, GetP4());
211     spl2.SetApproximationScale(GetApproximationScale());
212     return cutPoint;
213 }
214 
215 //---------------------------------------------------------------------------------------------------------------------
216 /**
217  * @brief GetPoints return list with spline points.
218  * @return list of points.
219  */
GetPoints() const220 QVector<QPointF> VSpline::GetPoints () const
221 {
222     return GetCubicBezierPoints(static_cast<QPointF>(GetP1()), static_cast<QPointF>(GetP2()),
223                                 static_cast<QPointF>(GetP3()), static_cast<QPointF>(GetP4()), GetApproximationScale());
224 }
225 
226 //---------------------------------------------------------------------------------------------------------------------
227 /**
228  * @brief SplinePoints return list with spline points.
229  * @param p1 first spline point.
230  * @param p4 last spline point.
231  * @param angle1 angle from first point to first control point.
232  * @param angle2 angle from second point to second control point.
233  * @param kAsm1 coefficient of length first control line.
234  * @param kAsm2 coefficient of length second control line.
235  * @param kCurve coefficient of curvature spline.
236  * @return list with spline points.
237  */
238 // cppcheck-suppress unusedFunction
SplinePoints(const QPointF & p1,const QPointF & p4,qreal angle1,qreal angle2,qreal kAsm1,qreal kAsm2,qreal kCurve,qreal approximationScale)239 QVector<QPointF> VSpline::SplinePoints(const QPointF &p1, const QPointF &p4, qreal angle1, qreal angle2, qreal kAsm1,
240                                        qreal kAsm2, qreal kCurve, qreal approximationScale)
241 {
242     QLineF p1pX(p1.x(), p1.y(), p1.x() + 100, p1.y());
243     p1pX.setAngle( angle1 );
244     qreal L = 0, radius = 0, angle = 90;
245     radius = QLineF(QPointF(p1.x(), p4.y()), p4).length();
246     L = kCurve * radius * 4 / 3 * tan( angle * M_PI_4 / 180.0 );
247     QLineF p1p2(p1.x(), p1.y(), p1.x() + L * kAsm1, p1.y());
248     p1p2.setAngle(angle1);
249     QLineF p4p3(p4.x(), p4.y(), p4.x() + L * kAsm2, p4.y());
250     p4p3.setAngle(angle2);
251     QPointF p2 = p1p2.p2();
252     QPointF p3 = p4p3.p2();
253     return GetCubicBezierPoints(p1, p2, p3, p4, approximationScale);
254 }
255 
256 //---------------------------------------------------------------------------------------------------------------------
operator =(const VSpline & spline)257 VSpline &VSpline::operator =(const VSpline &spline)
258 {
259     if ( &spline == this )
260     {
261         return *this;
262     }
263     VAbstractCubicBezier::operator=(spline);
264     d = spline.d;
265     return *this;
266 }
267 
268 #ifdef Q_COMPILER_RVALUE_REFS
269 //---------------------------------------------------------------------------------------------------------------------
VSpline(const VSpline && spline)270 VSpline::VSpline(const VSpline &&spline) Q_DECL_NOTHROW
271     :VAbstractCubicBezier(spline), d(spline.d)
272 {}
273 
274 //---------------------------------------------------------------------------------------------------------------------
operator =(VSpline && spline)275 VSpline &VSpline::operator=(VSpline &&spline) Q_DECL_NOTHROW
276 {
277     VAbstractCubicBezier::operator=(spline);
278     std::swap(d, spline.d);
279     return *this;
280 }
281 #endif
282 
283 //---------------------------------------------------------------------------------------------------------------------
284 /**
285  * @brief GetP1 return first spline point.
286  * @return first point.
287  */
GetP1() const288 VPointF VSpline::GetP1() const
289 {
290     return d->p1;
291 }
292 
293 //---------------------------------------------------------------------------------------------------------------------
SetP1(const VPointF & p)294 void VSpline::SetP1(const VPointF &p)
295 {
296     d->p1 = p;
297 }
298 
299 //---------------------------------------------------------------------------------------------------------------------
300 /**
301  * @brief GetP2 return first control point.
302  * @return first control point.
303  */
GetP2() const304 VPointF VSpline::GetP2() const
305 {
306     QLineF p1p2(d->p1.x(), d->p1.y(), d->p1.x() + d->c1Length, d->p1.y());
307     p1p2.setAngle(d->angle1);
308     return VPointF(p1p2.p2());
309 }
310 
311 //---------------------------------------------------------------------------------------------------------------------
312 /**
313  * @brief GetP3 return second control point.
314  * @return second control point.
315  */
GetP3() const316 VPointF VSpline::GetP3() const
317 {
318     QLineF p4p3(d->p4.x(), d->p4.y(), d->p4.x() + d->c2Length, d->p4.y());
319     p4p3.setAngle(d->angle2);
320     return VPointF(p4p3.p2());
321 }
322 
323 //---------------------------------------------------------------------------------------------------------------------
324 /**
325  * @brief GetP4 return last spline point.
326  * @return остання точка сплайну.
327  */
GetP4() const328 VPointF VSpline::GetP4() const
329 {
330     return d->p4;
331 }
332 
333 //---------------------------------------------------------------------------------------------------------------------
SetP4(const VPointF & p)334 void VSpline::SetP4(const VPointF &p)
335 {
336     d->p4 = p;
337 }
338 
339 //---------------------------------------------------------------------------------------------------------------------
340 /**
341  * @brief GetAngle1 return first angle control line.
342  * @return angle.
343  */
GetStartAngle() const344 qreal VSpline::GetStartAngle() const
345 {
346     return d->angle1;
347 }
348 
349 //---------------------------------------------------------------------------------------------------------------------
350 /**
351  * @brief GetAngle2 return second angle control line.
352  * @return angle.
353  */
GetEndAngle() const354 qreal VSpline::GetEndAngle() const
355 {
356     return d->angle2;
357 }
358 
359 //---------------------------------------------------------------------------------------------------------------------
GetStartAngleFormula() const360 QString VSpline::GetStartAngleFormula() const
361 {
362     return d->angle1F;
363 }
364 
365 //---------------------------------------------------------------------------------------------------------------------
GetEndAngleFormula() const366 QString VSpline::GetEndAngleFormula() const
367 {
368     return d->angle2F;
369 }
370 
371 //---------------------------------------------------------------------------------------------------------------------
SetStartAngle(qreal angle,const QString & formula)372 void VSpline::SetStartAngle(qreal angle, const QString &formula)
373 {
374     d->angle1 = angle;
375     d->angle1F = formula;
376 }
377 
378 //---------------------------------------------------------------------------------------------------------------------
SetEndAngle(qreal angle,const QString & formula)379 void VSpline::SetEndAngle(qreal angle, const QString &formula)
380 {
381     d->angle2 = angle;
382     d->angle2F = formula;
383 }
384 
385 //---------------------------------------------------------------------------------------------------------------------
GetC1Length() const386 qreal VSpline::GetC1Length() const
387 {
388     return d->c1Length;
389 }
390 
391 //---------------------------------------------------------------------------------------------------------------------
GetC2Length() const392 qreal VSpline::GetC2Length() const
393 {
394     return d->c2Length;
395 }
396 
397 //---------------------------------------------------------------------------------------------------------------------
GetC1LengthFormula() const398 QString VSpline::GetC1LengthFormula() const
399 {
400     return d->c1LengthF;
401 }
402 
403 //---------------------------------------------------------------------------------------------------------------------
GetC2LengthFormula() const404 QString VSpline::GetC2LengthFormula() const
405 {
406     return d->c2LengthF;
407 }
408 
409 //---------------------------------------------------------------------------------------------------------------------
SetC1Length(qreal length,const QString & formula)410 void VSpline::SetC1Length(qreal length, const QString &formula)
411 {
412     d->c1Length = length;
413     d->c1LengthF = formula;
414 }
415 
416 //---------------------------------------------------------------------------------------------------------------------
SetC2Length(qreal length,const QString & formula)417 void VSpline::SetC2Length(qreal length, const QString &formula)
418 {
419     d->c2Length = length;
420     d->c2LengthF = formula;
421 }
422 
423 //---------------------------------------------------------------------------------------------------------------------
424 /**
425  * @brief GetKasm1 return coefficient of length first control line.
426  * @return coefficient.
427  */
GetKasm1() const428 qreal VSpline::GetKasm1() const
429 {
430     return QLineF(static_cast<QPointF>(d->p1), static_cast<QPointF>(GetP2())).length() /
431             VSplineData::GetL(static_cast<QPointF>(d->p1), static_cast<QPointF>(d->p4), d->kCurve);
432 }
433 
434 //---------------------------------------------------------------------------------------------------------------------
435 /**
436  * @brief GetKasm2 return coefficient of length second control line.
437  * @return coefficient.
438  */
GetKasm2() const439 qreal VSpline::GetKasm2() const
440 {
441     return QLineF(static_cast<QPointF>(d->p4), static_cast<QPointF>(GetP3())).length() /
442             VSplineData::GetL(static_cast<QPointF>(d->p1), static_cast<QPointF>(d->p4), d->kCurve);
443 }
444 
445 //---------------------------------------------------------------------------------------------------------------------
446 /**
447  * @brief GetKcurve return coefficient of curvature spline.
448  * @return coefficient
449  */
GetKcurve() const450 qreal VSpline::GetKcurve() const
451 {
452     return d->kCurve;
453 }
454 
455 //---------------------------------------------------------------------------------------------------------------------
Sign(long double ld)456 int VSpline::Sign(long double ld)
457 {
458     if (qAbs(ld)<0.00000000001)
459     {
460         return 0;
461     }
462     return (ld>0) ? 1 : -1;
463 }
464 
465 //---------------------------------------------------------------------------------------------------------------------
466 /**
467  * @brief Cubic Cubic equation solution. Real coefficients case.
468  *
469  * This method use method Vieta-Cardano for eval cubic equations.
470  * Cubic equation write in form x3+a*x2+b*x+c=0.
471  *
472  * Output:
473  * 3 real roots -> then x is filled with them;
474  * 1 real + 2 complex -> x[0] is real, x[1] is real part of complex roots, x[2] - non-negative imaginary part.
475  *
476  * @param x solution array (size 3).
477  * @param a coefficient
478  * @param b coefficient
479  * @param c coefficient
480  * @return 3 - 3 real roots;
481  *         1 - 1 real root + 2 complex;
482  *         2 - 1 real root + complex roots imaginary part is zero (i.e. 2 real roots).
483  */
Cubic(QVector<qreal> & x,qreal a,qreal b,qreal c)484 qint32 VSpline::Cubic(QVector<qreal> &x, qreal a, qreal b, qreal c)
485 {
486     //To find cubic equation roots in the case of real coefficients, calculated at the beginning
487     const qreal q = (pow(a, 2) - 3*b)/9.;
488     const qreal r = (2*pow(a, 3) - 9*a*b + 27.*c)/54.;
489     if (pow(r, 2) < pow(q, 3))
490     { // equation has three real roots, use formula Vieta
491         const qreal t = acos(r/sqrt(pow(q, 3)))/3.;
492         x.insert(0, -2.*sqrt(q)*cos(t)-a/3);
493         x.insert(1, -2.*sqrt(q)*cos(t + (2*M_2PI/3.)) - a/3.);
494         x.insert(2, -2.*sqrt(q)*cos(t - (2*M_2PI/3.)) - a/3.);
495         return(3);
496     }
497     else
498     { // 1 real root + 2 complex
499         //Formula Cardano
500         const qreal aa = -Sign(r)*pow(fabs(r)+sqrt(pow(r, 2)-pow(q, 3)), 1./3.);
501         const qreal bb = Sign(aa) == 0 ? 0 : q/aa;
502 
503         x.insert(0, aa+bb-a/3.); // Real root
504         x.insert(1, (-0.5)*(aa+bb)-a/3.); //Complex root
505         x.insert(2, (sqrt(3.)*0.5)*fabs(aa-bb)); // Complex root
506         if (qFuzzyIsNull(x.at(2)))
507         {
508             return(2);
509         }
510         return(1);
511     }
512 }
513 
514 //---------------------------------------------------------------------------------------------------------------------
CalcT(qreal curveCoord1,qreal curveCoord2,qreal curveCoord3,qreal curveCoord4,qreal pointCoord) const515 QVector<qreal> VSpline::CalcT (qreal curveCoord1, qreal curveCoord2, qreal curveCoord3,
516                                qreal curveCoord4, qreal pointCoord) const
517 {
518     const qreal a = -curveCoord1 + 3*curveCoord2 - 3*curveCoord3 + curveCoord4;
519     const qreal b = 3*curveCoord1 - 6*curveCoord2 + 3*curveCoord3;
520     const qreal c = -3*curveCoord1 + 3*curveCoord2;
521     const qreal d = -pointCoord + curveCoord1;
522 
523     QVector<qreal> t = QVector<qreal>(3, -1);
524     Cubic(t, b/a, c/a, d/a);
525 
526     QVector<qreal> retT;
527     for (int i=0; i < t.size(); ++i)
528     {
529         if ( t.at(i) >= 0 && t.at(i) <= 1 )
530         {
531             retT.append(t.at(i));
532         }
533     }
534 
535     return retT;
536 }
537 
538 //---------------------------------------------------------------------------------------------------------------------
539 /**
540  * @brief VSpline::ParamT calculate t coeffient that reprezent point on curve.
541  *
542  * Each point that belongs to Cubic Bézier curve can be shown by coefficient in interval [0; 1].
543  *
544  * @param pBt point on curve
545  * @return t coeffient that reprezent this point on curve. Return -1 if point doesn't belongs to curve.
546  */
ParamT(const QPointF & pBt) const547 qreal VSpline::ParamT (const QPointF &pBt) const
548 {
549     QVector<qreal> ts;
550     // Calculate t coefficient for each axis
551     ts += CalcT (GetP1().x(), GetP2().x(), GetP3().x(), GetP4().x(), pBt.x());
552     ts += CalcT (GetP1().y(), GetP2().y(), GetP3().y(), GetP4().y(), pBt.y());
553 
554     if (ts.isEmpty())
555     {
556         return -1; // We don't have candidates
557     }
558 
559     qreal tx = -1;
560     qreal eps = 3; // Error calculation
561 
562     // In morst case we will have 6 result in interval [0; 1].
563     // Here we try find closest to our point.
564     for (auto t : qAsConst(ts))
565     {
566         const QPointF p0 = static_cast<QPointF>(GetP1());
567         const QPointF p1 = static_cast<QPointF>(GetP2());
568         const QPointF p2 = static_cast<QPointF>(GetP3());
569         const QPointF p3 = static_cast<QPointF>(GetP4());
570         //The explicit form of the Cubic Bézier curve
571         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();
572         const qreal pointY = pow(1-t, 3)*p0.y() + 3*pow(1-t, 2)*t*p1.y() + 3*(1-t)*pow(t, 2)*p2.y() + pow(t, 3)*p3.y();
573 
574         const QLineF line(pBt, QPointF(pointX, pointY));
575         if (line.length() <= eps)
576         {
577             tx = t;
578             eps = line.length(); //Next point should be even closest
579         }
580     }
581 
582     return tx;
583 }
584 
585 //---------------------------------------------------------------------------------------------------------------------
ToJson() const586 QJsonObject VSpline::ToJson() const
587 {
588     QJsonObject object = VAbstractCubicBezier::ToJson();
589     object[QLatin1String("aScale")] = GetApproximationScale();
590     object[QLatin1String("p1")] = GetP1().ToJson();
591     object[QLatin1String("p4")] = GetP4().ToJson();
592     object[QLatin1String("angle1")] = GetStartAngle();
593     object[QLatin1String("angle1Formula")] = GetStartAngleFormula();
594     object[QLatin1String("angle2")] = GetEndAngle();
595     object[QLatin1String("angle2Formula")] = GetEndAngleFormula();
596     object[QLatin1String("c1Length")] = GetC1Length();
597     object[QLatin1String("c1LengthFormula")] = GetC1LengthFormula();
598     object[QLatin1String("c2Length")] = GetC2Length();
599     object[QLatin1String("c2LengthFormula")] = GetC2LengthFormula();
600     return object;
601 }
602 
603 //---------------------------------------------------------------------------------------------------------------------
GetControlPoint1() const604 QPointF VSpline::GetControlPoint1() const
605 {
606     return static_cast<QPointF>(GetP2 ());
607 }
608 
609 //---------------------------------------------------------------------------------------------------------------------
GetControlPoint2() const610 QPointF VSpline::GetControlPoint2() const
611 {
612     return static_cast<QPointF>(GetP3 ());
613 }
614