2013-11-15 13:41:26 +01:00
|
|
|
|
/************************************************************************
|
2013-09-18 21:16:19 +02:00
|
|
|
|
**
|
2013-11-15 13:50:05 +01:00
|
|
|
|
** @file vspline.cpp
|
2014-04-30 07:38:52 +02:00
|
|
|
|
** @author Roman Telezhynskyi <dismine(at)gmail.com>
|
2013-11-15 13:50:05 +01:00
|
|
|
|
** @date November 15, 2013
|
2013-09-18 21:16:19 +02:00
|
|
|
|
**
|
2013-11-15 13:41:26 +01:00
|
|
|
|
** @brief
|
|
|
|
|
** @copyright
|
2017-10-05 11:20:01 +02:00
|
|
|
|
** This source code is part of the Valentina project, a pattern making
|
2013-11-15 13:41:26 +01:00
|
|
|
|
** program, whose allow create and modeling patterns of clothing.
|
2015-02-27 11:27:48 +01:00
|
|
|
|
** Copyright (C) 2013-2015 Valentina project
|
2020-01-31 07:00:05 +01:00
|
|
|
|
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
|
2013-09-18 21:16:19 +02:00
|
|
|
|
**
|
2013-11-15 13:41:26 +01:00
|
|
|
|
** Valentina is free software: you can redistribute it and/or modify
|
2013-09-18 21:16:19 +02:00
|
|
|
|
** it under the terms of the GNU General Public License as published by
|
|
|
|
|
** the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
** (at your option) any later version.
|
|
|
|
|
**
|
2013-10-27 13:36:29 +01:00
|
|
|
|
** Valentina is distributed in the hope that it will be useful,
|
2013-09-18 21:16:19 +02:00
|
|
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
** GNU General Public License for more details.
|
|
|
|
|
**
|
|
|
|
|
** You should have received a copy of the GNU General Public License
|
|
|
|
|
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
**
|
2013-11-15 13:41:26 +01:00
|
|
|
|
*************************************************************************/
|
2013-09-18 21:16:19 +02:00
|
|
|
|
|
2013-08-05 10:37:56 +02:00
|
|
|
|
#include "vspline.h"
|
2016-08-08 13:44:49 +02:00
|
|
|
|
|
2019-08-29 14:01:27 +02:00
|
|
|
|
#include <QJsonObject>
|
2016-08-08 13:44:49 +02:00
|
|
|
|
#include <QLineF>
|
|
|
|
|
|
|
|
|
|
#include "vabstractcurve.h"
|
2014-08-20 15:02:41 +02:00
|
|
|
|
#include "vspline_p.h"
|
2016-08-16 18:57:32 +02:00
|
|
|
|
#include "../vmisc/vmath.h"
|
2016-08-08 13:44:49 +02:00
|
|
|
|
|
2014-05-02 13:11:30 +02:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2014-06-01 10:32:39 +02:00
|
|
|
|
/**
|
|
|
|
|
* @brief VSpline default constructor
|
|
|
|
|
*/
|
2013-11-04 21:35:15 +01:00
|
|
|
|
VSpline::VSpline()
|
2016-03-08 18:48:10 +01:00
|
|
|
|
:VAbstractCubicBezier(GOType::Spline), d(new VSplineData)
|
2014-05-02 13:11:30 +02:00
|
|
|
|
{}
|
2013-08-05 10:37:56 +02:00
|
|
|
|
|
2014-05-02 13:11:30 +02:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2014-06-01 10:32:39 +02:00
|
|
|
|
/**
|
|
|
|
|
* @brief VSpline constructor.
|
|
|
|
|
* @param spline spline from which the copy.
|
|
|
|
|
*/
|
2013-11-04 21:35:15 +01:00
|
|
|
|
VSpline::VSpline ( const VSpline & spline )
|
2016-03-08 18:48:10 +01:00
|
|
|
|
:VAbstractCubicBezier(spline), d(spline.d)
|
2014-05-02 13:11:30 +02:00
|
|
|
|
{}
|
2013-12-29 17:48:57 +01:00
|
|
|
|
|
2014-05-02 13:11:30 +02:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2014-06-01 10:32:39 +02:00
|
|
|
|
/**
|
|
|
|
|
* @brief VSpline constructor.
|
|
|
|
|
* @param p1 first point spline.
|
|
|
|
|
* @param p4 last point spline.
|
|
|
|
|
* @param angle1 angle from first point to first control point.
|
|
|
|
|
* @param angle2 angle from second point to second control point.
|
|
|
|
|
* @param kCurve coefficient of curvature spline.
|
|
|
|
|
* @param kAsm1 coefficient of length first control line.
|
|
|
|
|
* @param kAsm2 coefficient of length second control line.
|
|
|
|
|
*/
|
2016-08-21 18:45:16 +02:00
|
|
|
|
VSpline::VSpline (const VPointF &p1, const VPointF &p4, qreal angle1, qreal angle2, qreal kAsm1, qreal kAsm2,
|
|
|
|
|
qreal kCurve, quint32 idObject, Draw mode)
|
2016-03-08 18:48:10 +01:00
|
|
|
|
: VAbstractCubicBezier(GOType::Spline, idObject, mode),
|
|
|
|
|
d(new VSplineData(p1, p4, angle1, angle2, kAsm1, kAsm2, kCurve))
|
2013-11-04 21:35:15 +01:00
|
|
|
|
{
|
2013-12-29 17:48:57 +01:00
|
|
|
|
CreateName();
|
2013-08-05 10:37:56 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-02 13:11:30 +02:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2014-06-01 10:32:39 +02:00
|
|
|
|
/**
|
|
|
|
|
* @brief VSpline constructor.
|
|
|
|
|
* @param p1 first point spline.
|
|
|
|
|
* @param p2 first control point.
|
|
|
|
|
* @param p3 second control point.
|
|
|
|
|
* @param p4 second point spline.
|
|
|
|
|
*/
|
2016-08-21 18:45:16 +02:00
|
|
|
|
VSpline::VSpline (const VPointF &p1, const QPointF &p2, const QPointF &p3, const VPointF &p4, quint32 idObject,
|
|
|
|
|
Draw mode)
|
2016-03-08 18:48:10 +01:00
|
|
|
|
:VAbstractCubicBezier(GOType::Spline, idObject, mode), d(new VSplineData(p1, p2, p3, p4))
|
2013-11-04 21:35:15 +01:00
|
|
|
|
{
|
2013-12-29 17:48:57 +01:00
|
|
|
|
CreateName();
|
2014-08-20 15:02:41 +02:00
|
|
|
|
}
|
2013-12-29 17:48:57 +01:00
|
|
|
|
|
2013-08-05 10:37:56 +02:00
|
|
|
|
|
2016-02-24 20:47:39 +01:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
/**
|
|
|
|
|
* @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.
|
|
|
|
|
*/
|
2016-08-21 18:45:16 +02:00
|
|
|
|
VSpline::VSpline(const VPointF &p1, const VPointF &p4, qreal angle1, const QString &angle1Formula, qreal angle2,
|
2016-02-24 20:47:39 +01:00
|
|
|
|
const QString &angle2Formula, qreal c1Length, const QString &c1LengthFormula, qreal c2Length,
|
2016-02-27 15:49:10 +01:00
|
|
|
|
const QString &c2LengthFormula, quint32 idObject, Draw mode)
|
2016-03-08 18:48:10 +01:00
|
|
|
|
: VAbstractCubicBezier(GOType::Spline, idObject, mode),
|
2016-04-10 17:03:15 +02:00
|
|
|
|
d(new VSplineData(p1, p4, angle1, angle1Formula, angle2, angle2Formula, c1Length, c1LengthFormula, c2Length,
|
2016-02-27 15:49:10 +01:00
|
|
|
|
c2LengthFormula))
|
2016-02-24 20:47:39 +01:00
|
|
|
|
{
|
|
|
|
|
CreateName();
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-10 17:03:15 +02:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
VSpline VSpline::Rotate(const QPointF &originPoint, qreal degrees, const QString &prefix) const
|
|
|
|
|
{
|
|
|
|
|
const VPointF p1 = GetP1().Rotate(originPoint, degrees);
|
|
|
|
|
const VPointF p4 = GetP4().Rotate(originPoint, degrees);
|
|
|
|
|
|
2017-03-31 16:04:11 +02:00
|
|
|
|
const QPointF p2 = VPointF::RotatePF(originPoint, static_cast<QPointF>(GetP2()), degrees);
|
|
|
|
|
const QPointF p3 = VPointF::RotatePF(originPoint, static_cast<QPointF>(GetP3()), degrees);
|
2016-04-10 17:03:15 +02:00
|
|
|
|
|
|
|
|
|
VSpline spl(p1, p2, p3, p4);
|
|
|
|
|
spl.setName(name() + prefix);
|
2020-11-07 14:02:30 +01:00
|
|
|
|
|
|
|
|
|
if (not GetAliasSuffix().isEmpty())
|
|
|
|
|
{
|
|
|
|
|
spl.SetAliasSuffix(GetAliasSuffix() + prefix);
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-16 12:07:53 +02:00
|
|
|
|
spl.SetColor(GetColor());
|
|
|
|
|
spl.SetPenStyle(GetPenStyle());
|
2017-10-11 12:51:06 +02:00
|
|
|
|
spl.SetApproximationScale(GetApproximationScale());
|
2016-09-10 20:40:30 +02:00
|
|
|
|
return spl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
VSpline VSpline::Flip(const QLineF &axis, const QString &prefix) const
|
|
|
|
|
{
|
|
|
|
|
const VPointF p1 = GetP1().Flip(axis);
|
|
|
|
|
const VPointF p4 = GetP4().Flip(axis);
|
|
|
|
|
|
2017-03-31 16:04:11 +02:00
|
|
|
|
const QPointF p2 = VPointF::FlipPF(axis, static_cast<QPointF>(GetP2()));
|
|
|
|
|
const QPointF p3 = VPointF::FlipPF(axis, static_cast<QPointF>(GetP3()));
|
2016-09-10 20:40:30 +02:00
|
|
|
|
|
|
|
|
|
VSpline spl(p1, p2, p3, p4);
|
|
|
|
|
spl.setName(name() + prefix);
|
2020-11-07 14:02:30 +01:00
|
|
|
|
|
|
|
|
|
if (not GetAliasSuffix().isEmpty())
|
|
|
|
|
{
|
|
|
|
|
spl.SetAliasSuffix(GetAliasSuffix() + prefix);
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-16 12:07:53 +02:00
|
|
|
|
spl.SetColor(GetColor());
|
|
|
|
|
spl.SetPenStyle(GetPenStyle());
|
2017-10-11 12:51:06 +02:00
|
|
|
|
spl.SetApproximationScale(GetApproximationScale());
|
2016-10-04 16:34:37 +02:00
|
|
|
|
return spl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
VSpline VSpline::Move(qreal length, qreal angle, const QString &prefix) const
|
|
|
|
|
{
|
|
|
|
|
const VPointF p1 = GetP1().Move(length, angle);
|
|
|
|
|
const VPointF p4 = GetP4().Move(length, angle);
|
|
|
|
|
|
2017-03-31 16:04:11 +02:00
|
|
|
|
const QPointF p2 = VPointF::MovePF(static_cast<QPointF>(GetP2()), length, angle);
|
|
|
|
|
const QPointF p3 = VPointF::MovePF(static_cast<QPointF>(GetP3()), length, angle);
|
2016-10-04 16:34:37 +02:00
|
|
|
|
|
|
|
|
|
VSpline spl(p1, p2, p3, p4);
|
|
|
|
|
spl.setName(name() + prefix);
|
2020-11-07 14:02:30 +01:00
|
|
|
|
|
|
|
|
|
if (not GetAliasSuffix().isEmpty())
|
|
|
|
|
{
|
|
|
|
|
spl.SetAliasSuffix(GetAliasSuffix() + prefix);
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-16 12:07:53 +02:00
|
|
|
|
spl.SetColor(GetColor());
|
|
|
|
|
spl.SetPenStyle(GetPenStyle());
|
2017-10-11 12:51:06 +02:00
|
|
|
|
spl.SetApproximationScale(GetApproximationScale());
|
2016-04-10 17:03:15 +02:00
|
|
|
|
return spl;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-20 15:02:41 +02:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
VSpline::~VSpline()
|
|
|
|
|
{}
|
2013-08-05 10:37:56 +02:00
|
|
|
|
|
2014-05-02 13:11:30 +02:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2014-06-01 10:32:39 +02:00
|
|
|
|
/**
|
|
|
|
|
* @brief GetLength return length of spline.
|
|
|
|
|
* @return length.
|
|
|
|
|
*/
|
2013-11-04 21:35:15 +01:00
|
|
|
|
qreal VSpline::GetLength () const
|
|
|
|
|
{
|
2017-03-31 16:04:11 +02:00
|
|
|
|
return LengthBezier ( static_cast<QPointF>(GetP1()), static_cast<QPointF>(GetP2()), static_cast<QPointF>(GetP3()),
|
2017-10-11 12:51:06 +02:00
|
|
|
|
static_cast<QPointF>(GetP4()), GetApproximationScale());
|
2013-08-05 10:37:56 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-09-06 14:47:25 +02:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2022-05-20 14:49:15 +02:00
|
|
|
|
QPointF VSpline::CutSpline(qreal length, VSpline &spl1, VSpline &spl2, const QString &pointName) const
|
2014-09-06 14:47:25 +02:00
|
|
|
|
{
|
|
|
|
|
QPointF spl1p2;
|
|
|
|
|
QPointF spl1p3;
|
|
|
|
|
QPointF spl2p2;
|
|
|
|
|
QPointF spl2p3;
|
2022-05-20 14:49:15 +02:00
|
|
|
|
const QPointF cutPoint = CutSpline(length, spl1p2, spl1p3, spl2p2, spl2p3, pointName);
|
2014-09-06 14:47:25 +02:00
|
|
|
|
|
2017-03-31 16:04:11 +02:00
|
|
|
|
spl1 = VSpline(GetP1(), spl1p2, spl1p3, VPointF(cutPoint));
|
2017-10-11 12:51:06 +02:00
|
|
|
|
spl1.SetApproximationScale(GetApproximationScale());
|
|
|
|
|
|
2017-03-31 16:04:11 +02:00
|
|
|
|
spl2 = VSpline(VPointF(cutPoint), spl2p2, spl2p3, GetP4());
|
2017-10-11 12:51:06 +02:00
|
|
|
|
spl2.SetApproximationScale(GetApproximationScale());
|
2014-09-06 14:47:25 +02:00
|
|
|
|
return cutPoint;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-02 13:11:30 +02:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2014-06-01 10:32:39 +02:00
|
|
|
|
/**
|
|
|
|
|
* @brief GetPoints return list with spline points.
|
|
|
|
|
* @return list of points.
|
|
|
|
|
*/
|
2013-11-04 21:35:15 +01:00
|
|
|
|
QVector<QPointF> VSpline::GetPoints () const
|
|
|
|
|
{
|
2017-03-31 16:04:11 +02:00
|
|
|
|
return GetCubicBezierPoints(static_cast<QPointF>(GetP1()), static_cast<QPointF>(GetP2()),
|
2017-10-11 12:51:06 +02:00
|
|
|
|
static_cast<QPointF>(GetP3()), static_cast<QPointF>(GetP4()), GetApproximationScale());
|
2013-12-29 17:48:57 +01:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-02 13:11:30 +02:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2014-06-01 10:32:39 +02:00
|
|
|
|
/**
|
|
|
|
|
* @brief SplinePoints return list with spline points.
|
|
|
|
|
* @param p1 first spline point.
|
|
|
|
|
* @param p4 last spline point.
|
|
|
|
|
* @param angle1 angle from first point to first control point.
|
|
|
|
|
* @param angle2 angle from second point to second control point.
|
|
|
|
|
* @param kAsm1 coefficient of length first control line.
|
|
|
|
|
* @param kAsm2 coefficient of length second control line.
|
|
|
|
|
* @param kCurve coefficient of curvature spline.
|
|
|
|
|
* @return list with spline points.
|
|
|
|
|
*/
|
2014-05-11 20:15:32 +02:00
|
|
|
|
// cppcheck-suppress unusedFunction
|
2013-11-07 15:40:39 +01:00
|
|
|
|
QVector<QPointF> VSpline::SplinePoints(const QPointF &p1, const QPointF &p4, qreal angle1, qreal angle2, qreal kAsm1,
|
2017-10-11 12:51:06 +02:00
|
|
|
|
qreal kAsm2, qreal kCurve, qreal approximationScale)
|
2013-11-04 21:35:15 +01:00
|
|
|
|
{
|
2013-08-28 10:55:11 +02:00
|
|
|
|
QLineF p1pX(p1.x(), p1.y(), p1.x() + 100, p1.y());
|
|
|
|
|
p1pX.setAngle( angle1 );
|
|
|
|
|
qreal L = 0, radius = 0, angle = 90;
|
2013-11-04 21:35:15 +01:00
|
|
|
|
radius = QLineF(QPointF(p1.x(), p4.y()), p4).length();
|
2016-03-23 12:52:55 +01:00
|
|
|
|
L = kCurve * radius * 4 / 3 * tan( angle * M_PI_4 / 180.0 );
|
2013-08-28 10:55:11 +02:00
|
|
|
|
QLineF p1p2(p1.x(), p1.y(), p1.x() + L * kAsm1, p1.y());
|
|
|
|
|
p1p2.setAngle(angle1);
|
|
|
|
|
QLineF p4p3(p4.x(), p4.y(), p4.x() + L * kAsm2, p4.y());
|
|
|
|
|
p4p3.setAngle(angle2);
|
|
|
|
|
QPointF p2 = p1p2.p2();
|
|
|
|
|
QPointF p3 = p4p3.p2();
|
2017-10-11 12:51:06 +02:00
|
|
|
|
return GetCubicBezierPoints(p1, p2, p3, p4, approximationScale);
|
2013-08-28 10:55:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-02 13:11:30 +02:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2013-11-04 21:35:15 +01:00
|
|
|
|
VSpline &VSpline::operator =(const VSpline &spline)
|
|
|
|
|
{
|
2014-07-27 14:30:28 +02:00
|
|
|
|
if ( &spline == this )
|
|
|
|
|
{
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
2016-03-08 18:48:10 +01:00
|
|
|
|
VAbstractCubicBezier::operator=(spline);
|
2014-08-20 15:02:41 +02:00
|
|
|
|
d = spline.d;
|
2013-09-11 16:14:21 +02:00
|
|
|
|
return *this;
|
|
|
|
|
}
|
2014-08-20 15:02:41 +02:00
|
|
|
|
|
2019-12-30 12:00:57 +01:00
|
|
|
|
#ifdef Q_COMPILER_RVALUE_REFS
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2019-12-30 16:13:18 +01:00
|
|
|
|
VSpline::VSpline(const VSpline &&spline) Q_DECL_NOTHROW
|
|
|
|
|
:VAbstractCubicBezier(spline), d(spline.d)
|
|
|
|
|
{}
|
2019-12-30 12:00:57 +01:00
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2019-12-30 16:13:18 +01:00
|
|
|
|
VSpline &VSpline::operator=(VSpline &&spline) Q_DECL_NOTHROW
|
2019-12-30 12:00:57 +01:00
|
|
|
|
{
|
2019-12-30 16:13:18 +01:00
|
|
|
|
VAbstractCubicBezier::operator=(spline);
|
2019-12-30 12:00:57 +01:00
|
|
|
|
std::swap(d, spline.d);
|
2019-12-30 16:13:18 +01:00
|
|
|
|
return *this;
|
2019-12-30 12:00:57 +01:00
|
|
|
|
}
|
2019-12-30 16:13:18 +01:00
|
|
|
|
#endif
|
2019-12-30 12:00:57 +01:00
|
|
|
|
|
2014-08-20 15:02:41 +02:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
/**
|
|
|
|
|
* @brief GetP1 return first spline point.
|
|
|
|
|
* @return first point.
|
|
|
|
|
*/
|
|
|
|
|
VPointF VSpline::GetP1() const
|
|
|
|
|
{
|
|
|
|
|
return d->p1;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-27 11:28:15 +01:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
void VSpline::SetP1(const VPointF &p)
|
|
|
|
|
{
|
|
|
|
|
d->p1 = p;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-20 15:02:41 +02:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
/**
|
|
|
|
|
* @brief GetP2 return first control point.
|
|
|
|
|
* @return first control point.
|
|
|
|
|
*/
|
2016-06-30 15:02:59 +02:00
|
|
|
|
VPointF VSpline::GetP2() const
|
2014-08-20 15:02:41 +02:00
|
|
|
|
{
|
2016-02-24 20:47:39 +01:00
|
|
|
|
QLineF p1p2(d->p1.x(), d->p1.y(), d->p1.x() + d->c1Length, d->p1.y());
|
|
|
|
|
p1p2.setAngle(d->angle1);
|
2016-06-30 15:02:59 +02:00
|
|
|
|
return VPointF(p1p2.p2());
|
2014-08-20 15:02:41 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
/**
|
|
|
|
|
* @brief GetP3 return second control point.
|
|
|
|
|
* @return second control point.
|
|
|
|
|
*/
|
2016-06-30 15:02:59 +02:00
|
|
|
|
VPointF VSpline::GetP3() const
|
2014-08-20 15:02:41 +02:00
|
|
|
|
{
|
2016-02-24 20:47:39 +01:00
|
|
|
|
QLineF p4p3(d->p4.x(), d->p4.y(), d->p4.x() + d->c2Length, d->p4.y());
|
|
|
|
|
p4p3.setAngle(d->angle2);
|
2016-06-30 15:02:59 +02:00
|
|
|
|
return VPointF(p4p3.p2());
|
2014-08-20 15:02:41 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
/**
|
|
|
|
|
* @brief GetP4 return last spline point.
|
|
|
|
|
* @return остання точка сплайну.
|
|
|
|
|
*/
|
|
|
|
|
VPointF VSpline::GetP4() const
|
|
|
|
|
{
|
|
|
|
|
return d->p4;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-27 11:28:15 +01:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
void VSpline::SetP4(const VPointF &p)
|
|
|
|
|
{
|
|
|
|
|
d->p4 = p;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-20 15:02:41 +02:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
/**
|
|
|
|
|
* @brief GetAngle1 return first angle control line.
|
|
|
|
|
* @return angle.
|
|
|
|
|
*/
|
2015-06-02 15:53:19 +02:00
|
|
|
|
qreal VSpline::GetStartAngle() const
|
2014-08-20 15:02:41 +02:00
|
|
|
|
{
|
|
|
|
|
return d->angle1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
/**
|
|
|
|
|
* @brief GetAngle2 return second angle control line.
|
|
|
|
|
* @return angle.
|
|
|
|
|
*/
|
2015-06-02 15:53:19 +02:00
|
|
|
|
qreal VSpline::GetEndAngle() const
|
2014-08-20 15:02:41 +02:00
|
|
|
|
{
|
|
|
|
|
return d->angle2;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-24 20:47:39 +01:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
QString VSpline::GetStartAngleFormula() const
|
|
|
|
|
{
|
|
|
|
|
return d->angle1F;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
QString VSpline::GetEndAngleFormula() const
|
|
|
|
|
{
|
|
|
|
|
return d->angle2F;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-27 11:28:15 +01:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
void VSpline::SetStartAngle(qreal angle, const QString &formula)
|
|
|
|
|
{
|
|
|
|
|
d->angle1 = angle;
|
|
|
|
|
d->angle1F = formula;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
void VSpline::SetEndAngle(qreal angle, const QString &formula)
|
|
|
|
|
{
|
|
|
|
|
d->angle2 = angle;
|
|
|
|
|
d->angle2F = formula;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-24 20:47:39 +01:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
qreal VSpline::GetC1Length() const
|
|
|
|
|
{
|
|
|
|
|
return d->c1Length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
qreal VSpline::GetC2Length() const
|
|
|
|
|
{
|
|
|
|
|
return d->c2Length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2016-02-25 20:23:16 +01:00
|
|
|
|
QString VSpline::GetC1LengthFormula() const
|
2016-02-24 20:47:39 +01:00
|
|
|
|
{
|
|
|
|
|
return d->c1LengthF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2016-02-25 20:23:16 +01:00
|
|
|
|
QString VSpline::GetC2LengthFormula() const
|
2016-02-24 20:47:39 +01:00
|
|
|
|
{
|
|
|
|
|
return d->c2LengthF;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-27 11:28:15 +01:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
void VSpline::SetC1Length(qreal length, const QString &formula)
|
|
|
|
|
{
|
|
|
|
|
d->c1Length = length;
|
|
|
|
|
d->c1LengthF = formula;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
void VSpline::SetC2Length(qreal length, const QString &formula)
|
|
|
|
|
{
|
|
|
|
|
d->c2Length = length;
|
|
|
|
|
d->c2LengthF = formula;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-20 15:02:41 +02:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
/**
|
|
|
|
|
* @brief GetKasm1 return coefficient of length first control line.
|
|
|
|
|
* @return coefficient.
|
|
|
|
|
*/
|
|
|
|
|
qreal VSpline::GetKasm1() const
|
|
|
|
|
{
|
2017-03-31 16:04:11 +02:00
|
|
|
|
return QLineF(static_cast<QPointF>(d->p1), static_cast<QPointF>(GetP2())).length() /
|
|
|
|
|
VSplineData::GetL(static_cast<QPointF>(d->p1), static_cast<QPointF>(d->p4), d->kCurve);
|
2014-08-20 15:02:41 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
/**
|
|
|
|
|
* @brief GetKasm2 return coefficient of length second control line.
|
|
|
|
|
* @return coefficient.
|
|
|
|
|
*/
|
|
|
|
|
qreal VSpline::GetKasm2() const
|
|
|
|
|
{
|
2017-03-31 16:04:11 +02:00
|
|
|
|
return QLineF(static_cast<QPointF>(d->p4), static_cast<QPointF>(GetP3())).length() /
|
|
|
|
|
VSplineData::GetL(static_cast<QPointF>(d->p1), static_cast<QPointF>(d->p4), d->kCurve);
|
2014-08-20 15:02:41 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
/**
|
|
|
|
|
* @brief GetKcurve return coefficient of curvature spline.
|
|
|
|
|
* @return coefficient
|
|
|
|
|
*/
|
|
|
|
|
qreal VSpline::GetKcurve() const
|
|
|
|
|
{
|
|
|
|
|
return d->kCurve;
|
|
|
|
|
}
|
2014-09-03 13:10:51 +02:00
|
|
|
|
|
2015-02-12 11:55:09 +01:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2015-03-02 18:54:33 +01:00
|
|
|
|
int VSpline::Sign(long double ld)
|
2015-02-12 11:55:09 +01:00
|
|
|
|
{
|
2015-03-02 18:11:43 +01:00
|
|
|
|
if (qAbs(ld)<0.00000000001)
|
2015-02-12 11:55:09 +01:00
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return (ld>0) ? 1 : -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
/**
|
|
|
|
|
* @brief Cubic Cubic equation solution. Real coefficients case.
|
|
|
|
|
*
|
|
|
|
|
* This method use method Vieta-Cardano for eval cubic equations.
|
|
|
|
|
* Cubic equation write in form x3+a*x2+b*x+c=0.
|
|
|
|
|
*
|
|
|
|
|
* Output:
|
|
|
|
|
* 3 real roots -> then x is filled with them;
|
|
|
|
|
* 1 real + 2 complex -> x[0] is real, x[1] is real part of complex roots, x[2] - non-negative imaginary part.
|
|
|
|
|
*
|
|
|
|
|
* @param x solution array (size 3).
|
|
|
|
|
* @param a coefficient
|
|
|
|
|
* @param b coefficient
|
|
|
|
|
* @param c coefficient
|
|
|
|
|
* @return 3 - 3 real roots;
|
|
|
|
|
* 1 - 1 real root + 2 complex;
|
|
|
|
|
* 2 - 1 real root + complex roots imaginary part is zero (i.e. 2 real roots).
|
|
|
|
|
*/
|
2015-03-02 18:54:33 +01:00
|
|
|
|
qint32 VSpline::Cubic(QVector<qreal> &x, qreal a, qreal b, qreal c)
|
2015-02-12 11:55:09 +01:00
|
|
|
|
{
|
|
|
|
|
//To find cubic equation roots in the case of real coefficients, calculated at the beginning
|
|
|
|
|
const qreal q = (pow(a, 2) - 3*b)/9.;
|
|
|
|
|
const qreal r = (2*pow(a, 3) - 9*a*b + 27.*c)/54.;
|
|
|
|
|
if (pow(r, 2) < pow(q, 3))
|
|
|
|
|
{ // equation has three real roots, use formula Vieta
|
|
|
|
|
const qreal t = acos(r/sqrt(pow(q, 3)))/3.;
|
|
|
|
|
x.insert(0, -2.*sqrt(q)*cos(t)-a/3);
|
|
|
|
|
x.insert(1, -2.*sqrt(q)*cos(t + (2*M_2PI/3.)) - a/3.);
|
|
|
|
|
x.insert(2, -2.*sqrt(q)*cos(t - (2*M_2PI/3.)) - a/3.);
|
|
|
|
|
return(3);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{ // 1 real root + 2 complex
|
|
|
|
|
//Formula Cardano
|
|
|
|
|
const qreal aa = -Sign(r)*pow(fabs(r)+sqrt(pow(r, 2)-pow(q, 3)), 1./3.);
|
|
|
|
|
const qreal bb = Sign(aa) == 0 ? 0 : q/aa;
|
|
|
|
|
|
|
|
|
|
x.insert(0, aa+bb-a/3.); // Real root
|
|
|
|
|
x.insert(1, (-0.5)*(aa+bb)-a/3.); //Complex root
|
|
|
|
|
x.insert(2, (sqrt(3.)*0.5)*fabs(aa-bb)); // Complex root
|
2016-03-23 15:09:30 +01:00
|
|
|
|
if (qFuzzyIsNull(x.at(2)))
|
2015-02-12 11:55:09 +01:00
|
|
|
|
{
|
|
|
|
|
return(2);
|
|
|
|
|
}
|
|
|
|
|
return(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
QVector<qreal> VSpline::CalcT (qreal curveCoord1, qreal curveCoord2, qreal curveCoord3,
|
|
|
|
|
qreal curveCoord4, qreal pointCoord) const
|
|
|
|
|
{
|
|
|
|
|
const qreal a = -curveCoord1 + 3*curveCoord2 - 3*curveCoord3 + curveCoord4;
|
|
|
|
|
const qreal b = 3*curveCoord1 - 6*curveCoord2 + 3*curveCoord3;
|
|
|
|
|
const qreal c = -3*curveCoord1 + 3*curveCoord2;
|
|
|
|
|
const qreal d = -pointCoord + curveCoord1;
|
|
|
|
|
|
|
|
|
|
QVector<qreal> t = QVector<qreal>(3, -1);
|
|
|
|
|
Cubic(t, b/a, c/a, d/a);
|
|
|
|
|
|
|
|
|
|
QVector<qreal> retT;
|
|
|
|
|
for (int i=0; i < t.size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
if ( t.at(i) >= 0 && t.at(i) <= 1 )
|
|
|
|
|
{
|
|
|
|
|
retT.append(t.at(i));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return retT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
/**
|
|
|
|
|
* @brief VSpline::ParamT calculate t coeffient that reprezent point on curve.
|
|
|
|
|
*
|
|
|
|
|
* Each point that belongs to Cubic Bézier curve can be shown by coefficient in interval [0; 1].
|
|
|
|
|
*
|
|
|
|
|
* @param pBt point on curve
|
|
|
|
|
* @return t coeffient that reprezent this point on curve. Return -1 if point doesn't belongs to curve.
|
|
|
|
|
*/
|
|
|
|
|
qreal VSpline::ParamT (const QPointF &pBt) const
|
|
|
|
|
{
|
|
|
|
|
QVector<qreal> ts;
|
|
|
|
|
// Calculate t coefficient for each axis
|
2016-05-14 21:28:09 +02:00
|
|
|
|
ts += CalcT (GetP1().x(), GetP2().x(), GetP3().x(), GetP4().x(), pBt.x());
|
|
|
|
|
ts += CalcT (GetP1().y(), GetP2().y(), GetP3().y(), GetP4().y(), pBt.y());
|
2015-02-12 11:55:09 +01:00
|
|
|
|
|
2015-03-02 18:11:43 +01:00
|
|
|
|
if (ts.isEmpty())
|
2015-02-12 11:55:09 +01:00
|
|
|
|
{
|
|
|
|
|
return -1; // We don't have candidates
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qreal tx = -1;
|
|
|
|
|
qreal eps = 3; // Error calculation
|
|
|
|
|
|
|
|
|
|
// In morst case we will have 6 result in interval [0; 1].
|
|
|
|
|
// Here we try find closest to our point.
|
2018-04-03 13:36:38 +02:00
|
|
|
|
for (auto t : qAsConst(ts))
|
2015-02-12 11:55:09 +01:00
|
|
|
|
{
|
2017-03-31 16:04:11 +02:00
|
|
|
|
const QPointF p0 = static_cast<QPointF>(GetP1());
|
|
|
|
|
const QPointF p1 = static_cast<QPointF>(GetP2());
|
|
|
|
|
const QPointF p2 = static_cast<QPointF>(GetP3());
|
|
|
|
|
const QPointF p3 = static_cast<QPointF>(GetP4());
|
2015-02-12 11:55:09 +01:00
|
|
|
|
//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();
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
|
|
const QLineF line(pBt, QPointF(pointX, pointY));
|
|
|
|
|
if (line.length() <= eps)
|
|
|
|
|
{
|
|
|
|
|
tx = t;
|
|
|
|
|
eps = line.length(); //Next point should be even closest
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return tx;
|
|
|
|
|
}
|
2016-03-10 17:09:38 +01:00
|
|
|
|
|
2019-08-29 14:01:27 +02:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
QJsonObject VSpline::ToJson() const
|
|
|
|
|
{
|
|
|
|
|
QJsonObject object = VAbstractCubicBezier::ToJson();
|
|
|
|
|
object[QLatin1String("aScale")] = GetApproximationScale();
|
|
|
|
|
object[QLatin1String("p1")] = GetP1().ToJson();
|
|
|
|
|
object[QLatin1String("p4")] = GetP4().ToJson();
|
|
|
|
|
object[QLatin1String("angle1")] = GetStartAngle();
|
|
|
|
|
object[QLatin1String("angle1Formula")] = GetStartAngleFormula();
|
|
|
|
|
object[QLatin1String("angle2")] = GetEndAngle();
|
|
|
|
|
object[QLatin1String("angle2Formula")] = GetEndAngleFormula();
|
|
|
|
|
object[QLatin1String("c1Length")] = GetC1Length();
|
|
|
|
|
object[QLatin1String("c1LengthFormula")] = GetC1LengthFormula();
|
|
|
|
|
object[QLatin1String("c2Length")] = GetC2Length();
|
|
|
|
|
object[QLatin1String("c2LengthFormula")] = GetC2LengthFormula();
|
|
|
|
|
return object;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-10 17:09:38 +01:00
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
QPointF VSpline::GetControlPoint1() const
|
|
|
|
|
{
|
2017-03-31 16:04:11 +02:00
|
|
|
|
return static_cast<QPointF>(GetP2 ());
|
2016-03-10 17:09:38 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
QPointF VSpline::GetControlPoint2() const
|
|
|
|
|
{
|
2017-03-31 16:04:11 +02:00
|
|
|
|
return static_cast<QPointF>(GetP3 ());
|
2016-03-10 17:09:38 +01:00
|
|
|
|
}
|
2022-02-03 14:48:52 +01:00
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
auto VSpline::GetRealLength() const -> qreal
|
|
|
|
|
{
|
|
|
|
|
return LengthBezier(static_cast<QPointF>(GetP1()), static_cast<QPointF>(GetP2()), static_cast<QPointF>(GetP3()),
|
|
|
|
|
static_cast<QPointF>(GetP4()), maxCurveApproximationScale);
|
|
|
|
|
}
|