Improve cutting spline and curved path.
Loose cutting restrictions.
This commit is contained in:
parent
aee93b01b9
commit
c7379122a8
|
@ -32,14 +32,14 @@
|
||||||
#include <QLineF>
|
#include <QLineF>
|
||||||
#include <QMessageLogger>
|
#include <QMessageLogger>
|
||||||
#include <QPoint>
|
#include <QPoint>
|
||||||
#include <QtDebug>
|
|
||||||
#include <QtConcurrent>
|
#include <QtConcurrent>
|
||||||
|
#include <QtDebug>
|
||||||
|
|
||||||
#include "../vmisc/def.h"
|
|
||||||
#include "../vmisc/vmath.h"
|
|
||||||
#include "../vgeometry/vpointf.h"
|
|
||||||
#include "../vmisc/vabstractapplication.h"
|
|
||||||
#include "../ifc/exception/vexception.h"
|
#include "../ifc/exception/vexception.h"
|
||||||
|
#include "../vgeometry/vpointf.h"
|
||||||
|
#include "../vmisc/def.h"
|
||||||
|
#include "../vmisc/vabstractapplication.h"
|
||||||
|
#include "../vmisc/vmath.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -74,28 +74,31 @@ inline auto CalcSqDistance(qreal x1, qreal y1, qreal x2, qreal y2) -> qreal
|
||||||
* @param points spline points coordinates.
|
* @param points spline points coordinates.
|
||||||
* @param approximationScale curve approximation scale.
|
* @param approximationScale curve approximation scale.
|
||||||
*/
|
*/
|
||||||
auto PointBezier_r(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4,
|
auto PointBezier_r(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4, qint16 level,
|
||||||
qint16 level, QVector<QPointF> points, qreal approximationScale) -> QVector<QPointF>
|
QVector<QPointF> points, qreal approximationScale) -> QVector<QPointF>
|
||||||
{
|
{
|
||||||
if (points.size() >= 2)
|
if (points.size() >= 2)
|
||||||
{
|
{
|
||||||
for (int i=1; i < points.size(); ++i)
|
for (int i = 1; i < points.size(); ++i)
|
||||||
{
|
{
|
||||||
if (points.at(i-1) == points.at(i))
|
if (points.at(i - 1) == points.at(i))
|
||||||
{
|
{
|
||||||
qDebug("All neighbors points in path must be unique.");
|
qDebug("All neighbors points in path must be unique.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const double curve_collinearity_epsilon = 1e-30;
|
const double curve_collinearity_epsilon = 1e-30;
|
||||||
const double curve_angle_tolerance_epsilon = 0.01;
|
const double curve_angle_tolerance_epsilon = 0.01;
|
||||||
const double m_angle_tolerance = 0.0;
|
const double m_angle_tolerance = 0.0;
|
||||||
enum curve_recursion_limit_e { curve_recursion_limit = 32 };
|
enum curve_recursion_limit_e
|
||||||
|
{
|
||||||
|
curve_recursion_limit = 32
|
||||||
|
};
|
||||||
const double m_cusp_limit = 0.0;
|
const double m_cusp_limit = 0.0;
|
||||||
|
|
||||||
double m_approximation_scale = approximationScale;
|
double m_approximation_scale = approximationScale;
|
||||||
if(m_approximation_scale < minCurveApproximationScale || m_approximation_scale > maxCurveApproximationScale)
|
if (m_approximation_scale < minCurveApproximationScale || m_approximation_scale > maxCurveApproximationScale)
|
||||||
{
|
{
|
||||||
m_approximation_scale = VAbstractApplication::VApp()->Settings()->GetCurveApproximationScale();
|
m_approximation_scale = VAbstractApplication::VApp()->Settings()->GetCurveApproximationScale();
|
||||||
}
|
}
|
||||||
|
@ -112,35 +115,35 @@ auto PointBezier_r(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, q
|
||||||
|
|
||||||
// Calculate all the mid-points of the line segments
|
// Calculate all the mid-points of the line segments
|
||||||
//----------------------
|
//----------------------
|
||||||
const double x12 = (x1 + x2) / 2;
|
const double x12 = (x1 + x2) / 2;
|
||||||
const double y12 = (y1 + y2) / 2;
|
const double y12 = (y1 + y2) / 2;
|
||||||
const double x23 = (x2 + x3) / 2;
|
const double x23 = (x2 + x3) / 2;
|
||||||
const double y23 = (y2 + y3) / 2;
|
const double y23 = (y2 + y3) / 2;
|
||||||
const double x34 = (x3 + x4) / 2;
|
const double x34 = (x3 + x4) / 2;
|
||||||
const double y34 = (y3 + y4) / 2;
|
const double y34 = (y3 + y4) / 2;
|
||||||
const double x123 = (x12 + x23) / 2;
|
const double x123 = (x12 + x23) / 2;
|
||||||
const double y123 = (y12 + y23) / 2;
|
const double y123 = (y12 + y23) / 2;
|
||||||
const double x234 = (x23 + x34) / 2;
|
const double x234 = (x23 + x34) / 2;
|
||||||
const double y234 = (y23 + y34) / 2;
|
const double y234 = (y23 + y34) / 2;
|
||||||
const double x1234 = (x123 + x234) / 2;
|
const double x1234 = (x123 + x234) / 2;
|
||||||
const double y1234 = (y123 + y234) / 2;
|
const double y1234 = (y123 + y234) / 2;
|
||||||
|
|
||||||
// Try to approximate the full cubic curve by a single straight line
|
// Try to approximate the full cubic curve by a single straight line
|
||||||
//------------------
|
//------------------
|
||||||
const double dx = x4-x1;
|
const double dx = x4 - x1;
|
||||||
const double dy = y4-y1;
|
const double dy = y4 - y1;
|
||||||
|
|
||||||
double d2 = fabs((x2 - x4) * dy - (y2 - y4) * dx);
|
double d2 = fabs((x2 - x4) * dy - (y2 - y4) * dx);
|
||||||
double d3 = fabs((x3 - x4) * dy - (y3 - y4) * dx);
|
double d3 = fabs((x3 - x4) * dy - (y3 - y4) * dx);
|
||||||
|
|
||||||
switch ((static_cast<int>(d2 > curve_collinearity_epsilon) << 1) +
|
switch ((static_cast<int>(d2 > curve_collinearity_epsilon) << 1) +
|
||||||
static_cast<int>(d3 > curve_collinearity_epsilon))
|
static_cast<int>(d3 > curve_collinearity_epsilon))
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
// All collinear OR p1==p4
|
// All collinear OR p1==p4
|
||||||
//----------------------
|
//----------------------
|
||||||
double k = dx*dx + dy*dy;
|
double k = dx * dx + dy * dy;
|
||||||
if (k < 0.000000001)
|
if (k < 0.000000001)
|
||||||
{
|
{
|
||||||
d2 = CalcSqDistance(x1, y1, x2, y2);
|
d2 = CalcSqDistance(x1, y1, x2, y2);
|
||||||
|
@ -148,16 +151,16 @@ auto PointBezier_r(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, q
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
k = 1 / k;
|
k = 1 / k;
|
||||||
{
|
{
|
||||||
const double da1 = x2 - x1;
|
const double da1 = x2 - x1;
|
||||||
const double da2 = y2 - y1;
|
const double da2 = y2 - y1;
|
||||||
d2 = k * (da1*dx + da2*dy);
|
d2 = k * (da1 * dx + da2 * dy);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const double da1 = x3 - x1;
|
const double da1 = x3 - x1;
|
||||||
const double da2 = y3 - y1;
|
const double da2 = y3 - y1;
|
||||||
d3 = k * (da1*dx + da2*dy);
|
d3 = k * (da1 * dx + da2 * dy);
|
||||||
}
|
}
|
||||||
if (d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1)
|
if (d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1)
|
||||||
{
|
{
|
||||||
|
@ -175,7 +178,7 @@ auto PointBezier_r(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, q
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
d2 = CalcSqDistance(x2, y2, x1 + d2*dx, y1 + d2*dy);
|
d2 = CalcSqDistance(x2, y2, x1 + d2 * dx, y1 + d2 * dy);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d3 <= 0)
|
if (d3 <= 0)
|
||||||
|
@ -188,7 +191,7 @@ auto PointBezier_r(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, q
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
d3 = CalcSqDistance(x3, y3, x1 + d3*dx, y1 + d3*dy);
|
d3 = CalcSqDistance(x3, y3, x1 + d3 * dx, y1 + d3 * dy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (d2 > d3)
|
if (d2 > d3)
|
||||||
|
@ -213,7 +216,7 @@ auto PointBezier_r(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, q
|
||||||
{
|
{
|
||||||
// p1,p2,p4 are collinear, p3 is significant
|
// p1,p2,p4 are collinear, p3 is significant
|
||||||
//----------------------
|
//----------------------
|
||||||
if (d3 * d3 <= m_distance_tolerance_square * (dx*dx + dy*dy))
|
if (d3 * d3 <= m_distance_tolerance_square * (dx * dx + dy * dy))
|
||||||
{
|
{
|
||||||
if (m_angle_tolerance < curve_angle_tolerance_epsilon)
|
if (m_angle_tolerance < curve_angle_tolerance_epsilon)
|
||||||
{
|
{
|
||||||
|
@ -251,7 +254,7 @@ auto PointBezier_r(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, q
|
||||||
{
|
{
|
||||||
// p1,p3,p4 are collinear, p2 is significant
|
// p1,p3,p4 are collinear, p2 is significant
|
||||||
//----------------------
|
//----------------------
|
||||||
if (d2 * d2 <= m_distance_tolerance_square * (dx*dx + dy*dy))
|
if (d2 * d2 <= m_distance_tolerance_square * (dx * dx + dy * dy))
|
||||||
{
|
{
|
||||||
if (m_angle_tolerance < curve_angle_tolerance_epsilon)
|
if (m_angle_tolerance < curve_angle_tolerance_epsilon)
|
||||||
{
|
{
|
||||||
|
@ -290,7 +293,7 @@ auto PointBezier_r(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, q
|
||||||
{
|
{
|
||||||
// Regular case
|
// Regular case
|
||||||
//-----------------
|
//-----------------
|
||||||
if ((d2 + d3)*(d2 + d3) <= m_distance_tolerance_square * (dx*dx + dy*dy))
|
if ((d2 + d3) * (d2 + d3) <= m_distance_tolerance_square * (dx * dx + dy * dy))
|
||||||
{
|
{
|
||||||
// If the curvature doesn't exceed the distance_tolerance value
|
// If the curvature doesn't exceed the distance_tolerance value
|
||||||
// we tend to finish subdivisions.
|
// we tend to finish subdivisions.
|
||||||
|
@ -303,7 +306,7 @@ auto PointBezier_r(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, q
|
||||||
|
|
||||||
// Angle & Cusp Condition
|
// Angle & Cusp Condition
|
||||||
//----------------------
|
//----------------------
|
||||||
const double k = atan2(y3 - y2, x3 - x2);
|
const double k = atan2(y3 - y2, x3 - x2);
|
||||||
double da1 = fabs(k - atan2(y2 - y1, x2 - x1));
|
double da1 = fabs(k - atan2(y2 - y1, x2 - x1));
|
||||||
double da2 = fabs(atan2(y4 - y3, x4 - x3) - k);
|
double da2 = fabs(atan2(y4 - y3, x4 - x3) - k);
|
||||||
if (da1 >= M_PI)
|
if (da1 >= M_PI)
|
||||||
|
@ -368,17 +371,18 @@ auto PointBezier_r(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, q
|
||||||
}
|
}
|
||||||
return BezierPoints() + BezierTailPoints();
|
return BezierPoints() + BezierTailPoints();
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
VAbstractCubicBezier::VAbstractCubicBezier(const GOType &type, const quint32 &idObject, const Draw &mode)
|
VAbstractCubicBezier::VAbstractCubicBezier(const GOType &type, const quint32 &idObject, const Draw &mode)
|
||||||
: VAbstractBezier(type, idObject, mode)
|
: VAbstractBezier(type, idObject, mode)
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
auto VAbstractCubicBezier::operator=(const VAbstractCubicBezier &curve) -> VAbstractCubicBezier &
|
auto VAbstractCubicBezier::operator=(const VAbstractCubicBezier &curve) -> VAbstractCubicBezier &
|
||||||
{
|
{
|
||||||
if ( &curve == this )
|
if (&curve == this)
|
||||||
{
|
{
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -397,86 +401,86 @@ auto VAbstractCubicBezier::operator=(const VAbstractCubicBezier &curve) -> VAbst
|
||||||
* @param pointName cutting point name.
|
* @param pointName cutting point name.
|
||||||
* @return point of cutting. This point is forth point of first spline and first point of second spline.
|
* @return point of cutting. This point is forth point of first spline and first point of second spline.
|
||||||
*/
|
*/
|
||||||
auto VAbstractCubicBezier::CutSpline(qreal length, QPointF &spl1p2, QPointF &spl1p3, QPointF &spl2p2,
|
auto VAbstractCubicBezier::CutSpline(qreal length, QPointF &spl1p2, QPointF &spl1p3, QPointF &spl2p2, QPointF &spl2p3,
|
||||||
QPointF &spl2p3, const QString &pointName) const -> QPointF
|
const QString &pointName) const -> QPointF
|
||||||
{
|
{
|
||||||
//Always need return two splines, so we must correct wrong length.
|
// Always need return two splines, so we must correct wrong length.
|
||||||
const qreal fullLength = GetLength();
|
const qreal fullLength = GetLength();
|
||||||
|
|
||||||
if (fullLength <= minLength)
|
if (qFuzzyIsNull(fullLength))
|
||||||
{
|
{
|
||||||
spl1p2 = spl1p3 = spl2p2 = spl2p3 = QPointF();
|
spl1p2 = spl1p3 = spl2p2 = spl2p3 = static_cast<QPointF>(GetP1());
|
||||||
|
|
||||||
const QString errorMsg = QObject::tr("Unable to cut curve '%1'. The curve is too short.").arg(name());
|
return static_cast<QPointF>(GetP1());
|
||||||
VAbstractApplication::VApp()->IsPedantic() ? throw VException(errorMsg) :
|
|
||||||
qWarning() << VAbstractApplication::warningMessageSignature + errorMsg;
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const qreal maxLength = fullLength - minLength;
|
if (length < 0)
|
||||||
|
|
||||||
if (length < minLength)
|
|
||||||
{
|
{
|
||||||
length = minLength;
|
length = fullLength + length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length < 0)
|
||||||
|
{
|
||||||
QString errorMsg;
|
QString errorMsg;
|
||||||
if (not pointName.isEmpty())
|
if (not pointName.isEmpty())
|
||||||
{
|
{
|
||||||
errorMsg = QObject::tr("Curve '%1'. Length of a cut segment (%2) is too small. Optimize it to minimal "
|
errorMsg = QObject::tr("Curve '%1'. Length of a cut segment (%2) is too small. Optimize it to minimal "
|
||||||
"value.").arg(name(), pointName);
|
"value.")
|
||||||
|
.arg(name(), pointName);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
errorMsg = QObject::tr("Curve '%1'. Length of a cut segment is too small. Optimize it to minimal value.")
|
errorMsg = QObject::tr("Curve '%1'. Length of a cut segment is too small. Optimize it to minimal value.")
|
||||||
.arg(name());
|
.arg(name());
|
||||||
}
|
}
|
||||||
VAbstractApplication::VApp()->IsPedantic() ? throw VException(errorMsg) :
|
VAbstractApplication::VApp()->IsPedantic()
|
||||||
qWarning() << VAbstractApplication::warningMessageSignature + errorMsg;
|
? throw VException(errorMsg)
|
||||||
|
: qWarning() << VAbstractApplication::warningMessageSignature + errorMsg;
|
||||||
}
|
}
|
||||||
else if (length > maxLength)
|
else if (length > fullLength)
|
||||||
{
|
{
|
||||||
length = maxLength;
|
|
||||||
|
|
||||||
QString errorMsg;
|
QString errorMsg;
|
||||||
if (not pointName.isEmpty())
|
if (not pointName.isEmpty())
|
||||||
{
|
{
|
||||||
errorMsg = QObject::tr("Curve '%1'. Length of a cut segment (%2) is too big. Optimize it to maximal value.")
|
errorMsg = QObject::tr("Curve '%1'. Length of a cut segment (%2) is too big. Optimize it to maximal value.")
|
||||||
.arg(name(), pointName);
|
.arg(name(), pointName);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
errorMsg = QObject::tr("Curve '%1'. Length of a cut segment is too big. Optimize it to maximal value.")
|
errorMsg = QObject::tr("Curve '%1'. Length of a cut segment is too big. Optimize it to maximal value.")
|
||||||
.arg(name());
|
.arg(name());
|
||||||
}
|
}
|
||||||
VAbstractApplication::VApp()->IsPedantic() ? throw VException(errorMsg) :
|
VAbstractApplication::VApp()->IsPedantic()
|
||||||
qWarning() << VAbstractApplication::warningMessageSignature + errorMsg;
|
? throw VException(errorMsg)
|
||||||
|
: qWarning() << VAbstractApplication::warningMessageSignature + errorMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
length = qBound(0.0, length, fullLength);
|
||||||
|
|
||||||
const qreal parT = GetParmT(length);
|
const qreal parT = GetParmT(length);
|
||||||
|
|
||||||
QLineF seg1_2 ( static_cast<QPointF>(GetP1 ()), GetControlPoint1 () );
|
QLineF seg1_2(static_cast<QPointF>(GetP1()), GetControlPoint1());
|
||||||
seg1_2.setLength(seg1_2.length () * parT);
|
seg1_2.setLength(seg1_2.length() * parT);
|
||||||
const QPointF p12 = seg1_2.p2();
|
const QPointF p12 = seg1_2.p2();
|
||||||
|
|
||||||
QLineF seg2_3 ( GetControlPoint1(), GetControlPoint2 () );
|
QLineF seg2_3(GetControlPoint1(), GetControlPoint2());
|
||||||
seg2_3.setLength(seg2_3.length () * parT);
|
seg2_3.setLength(seg2_3.length() * parT);
|
||||||
const QPointF p23 = seg2_3.p2();
|
const QPointF p23 = seg2_3.p2();
|
||||||
|
|
||||||
QLineF seg12_23 ( p12, p23 );
|
QLineF seg12_23(p12, p23);
|
||||||
seg12_23.setLength(seg12_23.length () * parT);
|
seg12_23.setLength(seg12_23.length() * parT);
|
||||||
const QPointF p123 = seg12_23.p2();
|
const QPointF p123 = seg12_23.p2();
|
||||||
|
|
||||||
QLineF seg3_4 ( GetControlPoint2 (), static_cast<QPointF>(GetP4 ()) );
|
QLineF seg3_4(GetControlPoint2(), static_cast<QPointF>(GetP4()));
|
||||||
seg3_4.setLength(seg3_4.length () * parT);
|
seg3_4.setLength(seg3_4.length() * parT);
|
||||||
const QPointF p34 = seg3_4.p2();
|
const QPointF p34 = seg3_4.p2();
|
||||||
|
|
||||||
QLineF seg23_34 ( p23, p34 );
|
QLineF seg23_34(p23, p34);
|
||||||
seg23_34.setLength(seg23_34.length () * parT);
|
seg23_34.setLength(seg23_34.length() * parT);
|
||||||
const QPointF p234 = seg23_34.p2();
|
const QPointF p234 = seg23_34.p2();
|
||||||
|
|
||||||
QLineF seg123_234 ( p123, p234 );
|
QLineF seg123_234(p123, p234);
|
||||||
seg123_234.setLength(seg123_234.length () * parT);
|
seg123_234.setLength(seg123_234.length() * parT);
|
||||||
const QPointF p1234 = seg123_234.p2();
|
const QPointF p1234 = seg123_234.p2();
|
||||||
|
|
||||||
spl1p2 = p12;
|
spl1p2 = p12;
|
||||||
|
@ -535,8 +539,7 @@ auto VAbstractCubicBezier::GetParmT(qreal length) const -> qreal
|
||||||
}
|
}
|
||||||
|
|
||||||
splLength > length ? parT -= step : parT += step;
|
splLength > length ? parT -= step : parT += step;
|
||||||
}
|
} while (qAbs(splLength - length) > eps);
|
||||||
while (qAbs(splLength - length) > eps);
|
|
||||||
|
|
||||||
return parT;
|
return parT;
|
||||||
}
|
}
|
||||||
|
@ -581,8 +584,8 @@ auto VAbstractCubicBezier::GetCubicBezierPoints(const QPointF &p1, const QPointF
|
||||||
{
|
{
|
||||||
QVector<QPointF> pvector;
|
QVector<QPointF> pvector;
|
||||||
pvector.append(p1);
|
pvector.append(p1);
|
||||||
pvector = PointBezier_r(p1.x(), p1.y(), p2.x(), p2.y(), p3.x(), p3.y(), p4.x(), p4.y(), 0, pvector,
|
pvector =
|
||||||
approximationScale);
|
PointBezier_r(p1.x(), p1.y(), p2.x(), p2.y(), p3.x(), p3.y(), p4.x(), p4.y(), 0, pvector, approximationScale);
|
||||||
pvector.append(p4);
|
pvector.append(p4);
|
||||||
return pvector;
|
return pvector;
|
||||||
}
|
}
|
||||||
|
@ -608,32 +611,32 @@ auto VAbstractCubicBezier::RealLengthByT(qreal t) const -> qreal
|
||||||
{
|
{
|
||||||
if (t < 0 || t > 1)
|
if (t < 0 || t > 1)
|
||||||
{
|
{
|
||||||
qDebug()<<"Wrong value t.";
|
qDebug() << "Wrong value t.";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
QLineF seg1_2 ( static_cast<QPointF>(GetP1 ()), GetControlPoint1 () );
|
QLineF seg1_2(static_cast<QPointF>(GetP1()), GetControlPoint1());
|
||||||
seg1_2.setLength(seg1_2.length () * t);
|
seg1_2.setLength(seg1_2.length() * t);
|
||||||
const QPointF p12 = seg1_2.p2();
|
const QPointF p12 = seg1_2.p2();
|
||||||
|
|
||||||
QLineF seg2_3 ( GetControlPoint1 (), GetControlPoint2 () );
|
QLineF seg2_3(GetControlPoint1(), GetControlPoint2());
|
||||||
seg2_3.setLength(seg2_3.length () * t);
|
seg2_3.setLength(seg2_3.length() * t);
|
||||||
const QPointF p23 = seg2_3.p2();
|
const QPointF p23 = seg2_3.p2();
|
||||||
|
|
||||||
QLineF seg12_23 ( p12, p23 );
|
QLineF seg12_23(p12, p23);
|
||||||
seg12_23.setLength(seg12_23.length () * t);
|
seg12_23.setLength(seg12_23.length() * t);
|
||||||
const QPointF p123 = seg12_23.p2();
|
const QPointF p123 = seg12_23.p2();
|
||||||
|
|
||||||
QLineF seg3_4 ( GetControlPoint2 (), static_cast<QPointF>(GetP4 ()) );
|
QLineF seg3_4(GetControlPoint2(), static_cast<QPointF>(GetP4()));
|
||||||
seg3_4.setLength(seg3_4.length () * t);
|
seg3_4.setLength(seg3_4.length() * t);
|
||||||
const QPointF p34 = seg3_4.p2();
|
const QPointF p34 = seg3_4.p2();
|
||||||
|
|
||||||
QLineF seg23_34 ( p23, p34 );
|
QLineF seg23_34(p23, p34);
|
||||||
seg23_34.setLength(seg23_34.length () * t);
|
seg23_34.setLength(seg23_34.length() * t);
|
||||||
const QPointF p234 = seg23_34.p2();
|
const QPointF p234 = seg23_34.p2();
|
||||||
|
|
||||||
QLineF seg123_234 ( p123, p234 );
|
QLineF seg123_234(p123, p234);
|
||||||
seg123_234.setLength(seg123_234.length () * t);
|
seg123_234.setLength(seg123_234.length() * t);
|
||||||
const QPointF p1234 = seg123_234.p2();
|
const QPointF p1234 = seg123_234.p2();
|
||||||
|
|
||||||
return LengthBezier ( static_cast<QPointF>(GetP1()), p12, p123, p1234, maxCurveApproximationScale);
|
return LengthBezier(static_cast<QPointF>(GetP1()), p12, p123, p1234, maxCurveApproximationScale);
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,25 +179,20 @@ auto VAbstractCubicBezierPath::CutSplinePath(qreal length, qint32 &p1, qint32 &p
|
||||||
// Always need return two spline paths, so we must correct wrong length.
|
// Always need return two spline paths, so we must correct wrong length.
|
||||||
qreal fullLength = GetLength();
|
qreal fullLength = GetLength();
|
||||||
|
|
||||||
if (fullLength <= minLength)
|
if (qFuzzyIsNull(fullLength))
|
||||||
{
|
{
|
||||||
p1 = p2 = -1;
|
|
||||||
spl1p2 = spl1p3 = spl2p2 = spl2p3 = QPointF();
|
spl1p2 = spl1p3 = spl2p2 = spl2p3 = QPointF();
|
||||||
|
|
||||||
const QString errorMsg = tr("Unable to cut curve '%1'. The curve is too short.").arg(name());
|
|
||||||
VAbstractApplication::VApp()->IsPedantic()
|
|
||||||
? throw VException(errorMsg)
|
|
||||||
: qWarning() << VAbstractApplication::warningMessageSignature + errorMsg;
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const qreal maxLength = fullLength - minLength;
|
if (length < 0)
|
||||||
|
|
||||||
if (length < minLength)
|
|
||||||
{
|
{
|
||||||
length = minLength;
|
length = fullLength + length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length < 0)
|
||||||
|
{
|
||||||
QString errorMsg;
|
QString errorMsg;
|
||||||
if (not pointName.isEmpty())
|
if (not pointName.isEmpty())
|
||||||
{
|
{
|
||||||
|
@ -213,10 +208,8 @@ auto VAbstractCubicBezierPath::CutSplinePath(qreal length, qint32 &p1, qint32 &p
|
||||||
? throw VException(errorMsg)
|
? throw VException(errorMsg)
|
||||||
: qWarning() << VAbstractApplication::warningMessageSignature + errorMsg;
|
: qWarning() << VAbstractApplication::warningMessageSignature + errorMsg;
|
||||||
}
|
}
|
||||||
else if (length > maxLength)
|
else if (length > fullLength)
|
||||||
{
|
{
|
||||||
length = maxLength;
|
|
||||||
|
|
||||||
QString errorMsg;
|
QString errorMsg;
|
||||||
if (not pointName.isEmpty())
|
if (not pointName.isEmpty())
|
||||||
{
|
{
|
||||||
|
@ -232,13 +225,15 @@ auto VAbstractCubicBezierPath::CutSplinePath(qreal length, qint32 &p1, qint32 &p
|
||||||
: qWarning() << VAbstractApplication::warningMessageSignature + errorMsg;
|
: qWarning() << VAbstractApplication::warningMessageSignature + errorMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
length = qBound(0.0, length, fullLength);
|
||||||
|
|
||||||
fullLength = 0;
|
fullLength = 0;
|
||||||
for (qint32 i = 1; i <= CountSubSpl(); ++i)
|
for (qint32 i = 1; i <= CountSubSpl(); ++i)
|
||||||
{
|
{
|
||||||
const VSpline spl = GetSpline(i);
|
const VSpline spl = GetSpline(i);
|
||||||
const qreal splLength = spl.GetLength();
|
const qreal splLength = spl.GetLength();
|
||||||
fullLength += splLength;
|
fullLength += splLength;
|
||||||
if (fullLength > length)
|
if (fullLength >= length)
|
||||||
{
|
{
|
||||||
p1 = i - 1;
|
p1 = i - 1;
|
||||||
p2 = i;
|
p2 = i;
|
||||||
|
|
|
@ -112,8 +112,6 @@ public:
|
||||||
|
|
||||||
void SetAliasSuffix(const QString &aliasSuffix) override;
|
void SetAliasSuffix(const QString &aliasSuffix) override;
|
||||||
|
|
||||||
static constexpr qreal minLength = MmToPixel(1.);
|
|
||||||
|
|
||||||
static auto Curvature(const QVector<QPointF> &vertices) -> double;
|
static auto Curvature(const QVector<QPointF> &vertices) -> double;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -426,10 +426,7 @@ void DialogCutSpline::ShowDialog(bool click)
|
||||||
const QSharedPointer<VAbstractCubicBezier> spl = data->GeometricObject<VAbstractCubicBezier>(getSplineId());
|
const QSharedPointer<VAbstractCubicBezier> spl = data->GeometricObject<VAbstractCubicBezier>(getSplineId());
|
||||||
QPointF p = spl->ClosestPoint(scene->getScenePos());
|
QPointF p = spl->ClosestPoint(scene->getScenePos());
|
||||||
qreal len = spl->GetLengthByPoint(p);
|
qreal len = spl->GetLengthByPoint(p);
|
||||||
if (len > 0)
|
SetFormula(QString::number(FromPixel(len, *data->GetPatternUnit())));
|
||||||
{
|
|
||||||
SetFormula(QString::number(FromPixel(len, *data->GetPatternUnit())));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FinishCreating();
|
FinishCreating();
|
||||||
|
|
|
@ -427,10 +427,7 @@ void DialogCutSplinePath::ShowDialog(bool click)
|
||||||
data->GeometricObject<VAbstractCubicBezierPath>(getSplinePathId());
|
data->GeometricObject<VAbstractCubicBezierPath>(getSplinePathId());
|
||||||
QPointF p = curve->ClosestPoint(scene->getScenePos());
|
QPointF p = curve->ClosestPoint(scene->getScenePos());
|
||||||
qreal len = curve->GetLengthByPoint(p);
|
qreal len = curve->GetLengthByPoint(p);
|
||||||
if (len > 0)
|
SetFormula(QString::number(FromPixel(len, *data->GetPatternUnit())));
|
||||||
{
|
|
||||||
SetFormula(QString::number(FromPixel(len, *data->GetPatternUnit())));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FinishCreating();
|
FinishCreating();
|
||||||
|
|
|
@ -69,7 +69,7 @@ void VisToolCutSpline::RefreshGeometry()
|
||||||
const auto spl = GetData()->GeometricObject<VAbstractCubicBezier>(m_splineId);
|
const auto spl = GetData()->GeometricObject<VAbstractCubicBezier>(m_splineId);
|
||||||
DrawPath(this, spl->GetPath(), spl->DirectionArrows(), LineStyle(), Qt::RoundCap);
|
DrawPath(this, spl->GetPath(), spl->DirectionArrows(), LineStyle(), Qt::RoundCap);
|
||||||
|
|
||||||
if (not qFuzzyIsNull(m_length))
|
if (!qIsInf(m_length))
|
||||||
{
|
{
|
||||||
QPointF spl1p2;
|
QPointF spl1p2;
|
||||||
QPointF spl1p3;
|
QPointF spl1p3;
|
||||||
|
|
|
@ -29,12 +29,12 @@
|
||||||
#ifndef VISTOOLCUTSPLINE_H
|
#ifndef VISTOOLCUTSPLINE_H
|
||||||
#define VISTOOLCUTSPLINE_H
|
#define VISTOOLCUTSPLINE_H
|
||||||
|
|
||||||
|
|
||||||
#include <QGraphicsItem>
|
#include <QGraphicsItem>
|
||||||
#include <QMetaObject>
|
#include <QMetaObject>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include "../vmisc/def.h"
|
#include "../vmisc/def.h"
|
||||||
#include "vispath.h"
|
#include "vispath.h"
|
||||||
|
@ -42,6 +42,7 @@
|
||||||
class VisToolCutSpline final : public VisPath
|
class VisToolCutSpline final : public VisPath
|
||||||
{
|
{
|
||||||
Q_OBJECT // NOLINT
|
Q_OBJECT // NOLINT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit VisToolCutSpline(const VContainer *data, QGraphicsItem *parent = nullptr);
|
explicit VisToolCutSpline(const VContainer *data, QGraphicsItem *parent = nullptr);
|
||||||
~VisToolCutSpline() override = default;
|
~VisToolCutSpline() override = default;
|
||||||
|
@ -52,15 +53,19 @@ public:
|
||||||
void SetSplineId(quint32 id);
|
void SetSplineId(quint32 id);
|
||||||
void SetLength(const QString &expression);
|
void SetLength(const QString &expression);
|
||||||
|
|
||||||
auto type() const -> int override {return Type;}
|
auto type() const -> int override { return Type; }
|
||||||
enum {Type = UserType + static_cast<int>(Vis::ToolCutSpline)};
|
enum
|
||||||
|
{
|
||||||
|
Type = UserType + static_cast<int>(Vis::ToolCutSpline)
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Q_DISABLE_COPY_MOVE(VisToolCutSpline) // NOLINT
|
Q_DISABLE_COPY_MOVE(VisToolCutSpline) // NOLINT
|
||||||
VScaledEllipse *m_point{nullptr};
|
VScaledEllipse *m_point{nullptr};
|
||||||
VCurvePathItem *m_spl1{nullptr};
|
VCurvePathItem *m_spl1{nullptr};
|
||||||
VCurvePathItem *m_spl2{nullptr};
|
VCurvePathItem *m_spl2{nullptr};
|
||||||
qreal m_length{0};
|
qreal m_length{std::numeric_limits<qreal>::infinity()};
|
||||||
quint32 m_splineId{NULL_ID};
|
quint32 m_splineId{NULL_ID};
|
||||||
};
|
};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -68,7 +68,7 @@ void VisToolCutSplinePath::RefreshGeometry()
|
||||||
const auto splPath = GetData()->GeometricObject<VAbstractCubicBezierPath>(m_splinePathId);
|
const auto splPath = GetData()->GeometricObject<VAbstractCubicBezierPath>(m_splinePathId);
|
||||||
DrawPath(this, splPath->GetPath(), splPath->DirectionArrows(), LineStyle(), Qt::RoundCap);
|
DrawPath(this, splPath->GetPath(), splPath->DirectionArrows(), LineStyle(), Qt::RoundCap);
|
||||||
|
|
||||||
if (not qFuzzyIsNull(m_length))
|
if (!qIsInf(m_length))
|
||||||
{
|
{
|
||||||
VSplinePath *spPath1 = nullptr;
|
VSplinePath *spPath1 = nullptr;
|
||||||
VSplinePath *spPath2 = nullptr;
|
VSplinePath *spPath2 = nullptr;
|
||||||
|
|
|
@ -29,12 +29,12 @@
|
||||||
#ifndef VISTOOLCUTSPLINEPATH_H
|
#ifndef VISTOOLCUTSPLINEPATH_H
|
||||||
#define VISTOOLCUTSPLINEPATH_H
|
#define VISTOOLCUTSPLINEPATH_H
|
||||||
|
|
||||||
|
|
||||||
#include <QGraphicsItem>
|
#include <QGraphicsItem>
|
||||||
#include <QMetaObject>
|
#include <QMetaObject>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include "../vmisc/def.h"
|
#include "../vmisc/def.h"
|
||||||
#include "vispath.h"
|
#include "vispath.h"
|
||||||
|
@ -42,6 +42,7 @@
|
||||||
class VisToolCutSplinePath final : public VisPath
|
class VisToolCutSplinePath final : public VisPath
|
||||||
{
|
{
|
||||||
Q_OBJECT // NOLINT
|
Q_OBJECT // NOLINT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit VisToolCutSplinePath(const VContainer *data, QGraphicsItem *parent = nullptr);
|
explicit VisToolCutSplinePath(const VContainer *data, QGraphicsItem *parent = nullptr);
|
||||||
~VisToolCutSplinePath() override = default;
|
~VisToolCutSplinePath() override = default;
|
||||||
|
@ -52,15 +53,19 @@ public:
|
||||||
void SetSplinePathId(quint32 newSplineId);
|
void SetSplinePathId(quint32 newSplineId);
|
||||||
void SetLength(const QString &expression);
|
void SetLength(const QString &expression);
|
||||||
|
|
||||||
auto type() const -> int override {return Type;}
|
auto type() const -> int override { return Type; }
|
||||||
enum {Type = UserType + static_cast<int>(Vis::ToolCutSpline)};
|
enum
|
||||||
|
{
|
||||||
|
Type = UserType + static_cast<int>(Vis::ToolCutSpline)
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Q_DISABLE_COPY_MOVE(VisToolCutSplinePath) // NOLINT
|
Q_DISABLE_COPY_MOVE(VisToolCutSplinePath) // NOLINT
|
||||||
VScaledEllipse *m_point{nullptr};
|
VScaledEllipse *m_point{nullptr};
|
||||||
VCurvePathItem *m_splPath1{nullptr};
|
VCurvePathItem *m_splPath1{nullptr};
|
||||||
VCurvePathItem *m_splPath2{nullptr};
|
VCurvePathItem *m_splPath2{nullptr};
|
||||||
qreal m_length{0};
|
qreal m_length{std::numeric_limits<qreal>::infinity()};
|
||||||
quint32 m_splinePathId{NULL_ID};
|
quint32 m_splinePathId{NULL_ID};
|
||||||
};
|
};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue
Block a user