Optimization for method PointBezier_r().
--HG-- branch : develop
This commit is contained in:
parent
d099e441a4
commit
f44484a364
|
@ -28,16 +28,350 @@
|
||||||
|
|
||||||
#include "vabstractcubicbezier.h"
|
#include "vabstractcubicbezier.h"
|
||||||
|
|
||||||
|
#include <QFuture>
|
||||||
#include <QLineF>
|
#include <QLineF>
|
||||||
#include <QMessageLogger>
|
#include <QMessageLogger>
|
||||||
#include <QPoint>
|
#include <QPoint>
|
||||||
#include <QtDebug>
|
#include <QtDebug>
|
||||||
|
#include <QtConcurrent>
|
||||||
|
|
||||||
#include "../vmisc/def.h"
|
#include "../vmisc/def.h"
|
||||||
#include "../vmisc/vmath.h"
|
#include "../vmisc/vmath.h"
|
||||||
#include "../vgeometry/vpointf.h"
|
#include "../vgeometry/vpointf.h"
|
||||||
#include "../vmisc/vabstractapplication.h"
|
#include "../vmisc/vabstractapplication.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* @brief CalcSqDistance calculate squared distance.
|
||||||
|
* @param x1 х coordinate first point.
|
||||||
|
* @param y1 у coordinate first point.
|
||||||
|
* @param x2 х coordinate second point.
|
||||||
|
* @param y2 у coordinate second point.
|
||||||
|
* @return squared length.
|
||||||
|
*/
|
||||||
|
inline qreal CalcSqDistance(qreal x1, qreal y1, qreal x2, qreal y2)
|
||||||
|
{
|
||||||
|
const qreal dx = x2 - x1;
|
||||||
|
const qreal dy = y2 - y1;
|
||||||
|
return dx * dx + dy * dy;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* @brief PointBezier_r find spline point using four point of spline.
|
||||||
|
* @param x1 х coordinate first point.
|
||||||
|
* @param y1 у coordinate first point.
|
||||||
|
* @param x2 х coordinate first control point.
|
||||||
|
* @param y2 у coordinate first control point.
|
||||||
|
* @param x3 х coordinate second control point.
|
||||||
|
* @param y3 у coordinate second control point.
|
||||||
|
* @param x4 х coordinate last point.
|
||||||
|
* @param y4 у coordinate last point.
|
||||||
|
* @param level level of recursion. In the begin 0.
|
||||||
|
* @param points spline points coordinates.
|
||||||
|
* @param approximationScale curve approximation scale.
|
||||||
|
*/
|
||||||
|
QVector<QPointF> PointBezier_r(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4,
|
||||||
|
qint16 level, QVector<QPointF> points, qreal approximationScale)
|
||||||
|
{
|
||||||
|
if (points.size() >= 2)
|
||||||
|
{
|
||||||
|
for (int i=1; i < points.size(); ++i)
|
||||||
|
{
|
||||||
|
if (points.at(i-1) == points.at(i))
|
||||||
|
{
|
||||||
|
qDebug("All neighbors points in path must be unique.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const double curve_collinearity_epsilon = 1e-30;
|
||||||
|
const double curve_angle_tolerance_epsilon = 0.01;
|
||||||
|
const double m_angle_tolerance = 0.0;
|
||||||
|
enum curve_recursion_limit_e { curve_recursion_limit = 32 };
|
||||||
|
const double m_cusp_limit = 0.0;
|
||||||
|
|
||||||
|
double m_approximation_scale = approximationScale;
|
||||||
|
if(m_approximation_scale < minCurveApproximationScale || m_approximation_scale > maxCurveApproximationScale)
|
||||||
|
{
|
||||||
|
m_approximation_scale = qApp->Settings()->GetCurveApproximationScale();
|
||||||
|
}
|
||||||
|
|
||||||
|
double m_distance_tolerance_square;
|
||||||
|
|
||||||
|
m_distance_tolerance_square = 0.5 / m_approximation_scale;
|
||||||
|
m_distance_tolerance_square *= m_distance_tolerance_square;
|
||||||
|
|
||||||
|
if (level > curve_recursion_limit)
|
||||||
|
{
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate all the mid-points of the line segments
|
||||||
|
//----------------------
|
||||||
|
const double x12 = (x1 + x2) / 2;
|
||||||
|
const double y12 = (y1 + y2) / 2;
|
||||||
|
const double x23 = (x2 + x3) / 2;
|
||||||
|
const double y23 = (y2 + y3) / 2;
|
||||||
|
const double x34 = (x3 + x4) / 2;
|
||||||
|
const double y34 = (y3 + y4) / 2;
|
||||||
|
const double x123 = (x12 + x23) / 2;
|
||||||
|
const double y123 = (y12 + y23) / 2;
|
||||||
|
const double x234 = (x23 + x34) / 2;
|
||||||
|
const double y234 = (y23 + y34) / 2;
|
||||||
|
const double x1234 = (x123 + x234) / 2;
|
||||||
|
const double y1234 = (y123 + y234) / 2;
|
||||||
|
|
||||||
|
// Try to approximate the full cubic curve by a single straight line
|
||||||
|
//------------------
|
||||||
|
const double dx = x4-x1;
|
||||||
|
const double dy = y4-y1;
|
||||||
|
|
||||||
|
double d2 = fabs((x2 - x4) * dy - (y2 - y4) * dx);
|
||||||
|
double d3 = fabs((x3 - x4) * dy - (y3 - y4) * dx);
|
||||||
|
|
||||||
|
switch ((static_cast<int>(d2 > curve_collinearity_epsilon) << 1) +
|
||||||
|
static_cast<int>(d3 > curve_collinearity_epsilon))
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
// All collinear OR p1==p4
|
||||||
|
//----------------------
|
||||||
|
double k = dx*dx + dy*dy;
|
||||||
|
if (k < 0.000000001)
|
||||||
|
{
|
||||||
|
d2 = CalcSqDistance(x1, y1, x2, y2);
|
||||||
|
d3 = CalcSqDistance(x4, y4, x3, y3);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
k = 1 / k;
|
||||||
|
{
|
||||||
|
const double da1 = x2 - x1;
|
||||||
|
const double da2 = y2 - y1;
|
||||||
|
d2 = k * (da1*dx + da2*dy);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const double da1 = x3 - x1;
|
||||||
|
const double da2 = y3 - y1;
|
||||||
|
d3 = k * (da1*dx + da2*dy);
|
||||||
|
}
|
||||||
|
if (d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1)
|
||||||
|
{
|
||||||
|
// Simple collinear case, 1---2---3---4
|
||||||
|
// We can leave just two endpoints
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
if (d2 <= 0)
|
||||||
|
{
|
||||||
|
d2 = CalcSqDistance(x2, y2, x1, y1);
|
||||||
|
}
|
||||||
|
else if (d2 >= 1)
|
||||||
|
{
|
||||||
|
d2 = CalcSqDistance(x2, y2, x4, y4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d2 = CalcSqDistance(x2, y2, x1 + d2*dx, y1 + d2*dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d3 <= 0)
|
||||||
|
{
|
||||||
|
d3 = CalcSqDistance(x3, y3, x1, y1);
|
||||||
|
}
|
||||||
|
else if (d3 >= 1)
|
||||||
|
{
|
||||||
|
d3 = CalcSqDistance(x3, y3, x4, y4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d3 = CalcSqDistance(x3, y3, x1 + d3*dx, y1 + d3*dy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (d2 > d3)
|
||||||
|
{
|
||||||
|
if (d2 < m_distance_tolerance_square)
|
||||||
|
{
|
||||||
|
points.append(QPointF(x2, y2));
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (d3 < m_distance_tolerance_square)
|
||||||
|
{
|
||||||
|
points.append(QPointF(x3, y3));
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
// p1,p2,p4 are collinear, p3 is significant
|
||||||
|
//----------------------
|
||||||
|
if (d3 * d3 <= m_distance_tolerance_square * (dx*dx + dy*dy))
|
||||||
|
{
|
||||||
|
if (m_angle_tolerance < curve_angle_tolerance_epsilon)
|
||||||
|
{
|
||||||
|
points.append(QPointF(x23, y23));
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Angle Condition
|
||||||
|
//----------------------
|
||||||
|
double da1 = fabs(atan2(y4 - y3, x4 - x3) - atan2(y3 - y2, x3 - x2));
|
||||||
|
if (da1 >= M_PI)
|
||||||
|
{
|
||||||
|
da1 = M_2PI - da1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (da1 < m_angle_tolerance)
|
||||||
|
{
|
||||||
|
points.append(QPointF(x2, y2));
|
||||||
|
points.append(QPointF(x3, y3));
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_cusp_limit > 0.0 || m_cusp_limit < 0.0)
|
||||||
|
{
|
||||||
|
if (da1 > m_cusp_limit)
|
||||||
|
{
|
||||||
|
points.append(QPointF(x3, y3));
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
// p1,p3,p4 are collinear, p2 is significant
|
||||||
|
//----------------------
|
||||||
|
if (d2 * d2 <= m_distance_tolerance_square * (dx*dx + dy*dy))
|
||||||
|
{
|
||||||
|
if (m_angle_tolerance < curve_angle_tolerance_epsilon)
|
||||||
|
{
|
||||||
|
points.append(QPointF(x23, y23));
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Angle Condition
|
||||||
|
//----------------------
|
||||||
|
double da1 = fabs(atan2(y3 - y2, x3 - x2) - atan2(y2 - y1, x2 - x1));
|
||||||
|
if (da1 >= M_PI)
|
||||||
|
{
|
||||||
|
da1 = M_2PI - da1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (da1 < m_angle_tolerance)
|
||||||
|
{
|
||||||
|
points.append(QPointF(x2, y2));
|
||||||
|
|
||||||
|
points.append(QPointF(x3, y3));
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_cusp_limit > 0.0 || m_cusp_limit < 0.0)
|
||||||
|
{
|
||||||
|
if (da1 > m_cusp_limit)
|
||||||
|
{
|
||||||
|
points.append(QPointF(x2, y2));
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
// Regular case
|
||||||
|
//-----------------
|
||||||
|
if ((d2 + d3)*(d2 + d3) <= m_distance_tolerance_square * (dx*dx + dy*dy))
|
||||||
|
{
|
||||||
|
// If the curvature doesn't exceed the distance_tolerance value
|
||||||
|
// we tend to finish subdivisions.
|
||||||
|
//----------------------
|
||||||
|
if (m_angle_tolerance < curve_angle_tolerance_epsilon)
|
||||||
|
{
|
||||||
|
points.append(QPointF(x23, y23));
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Angle & Cusp Condition
|
||||||
|
//----------------------
|
||||||
|
const double k = atan2(y3 - y2, x3 - x2);
|
||||||
|
double da1 = fabs(k - atan2(y2 - y1, x2 - x1));
|
||||||
|
double da2 = fabs(atan2(y4 - y3, x4 - x3) - k);
|
||||||
|
if (da1 >= M_PI)
|
||||||
|
{
|
||||||
|
da1 = M_2PI - da1;
|
||||||
|
}
|
||||||
|
if (da2 >= M_PI)
|
||||||
|
{
|
||||||
|
da2 = M_2PI - da2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (da1 + da2 < m_angle_tolerance)
|
||||||
|
{
|
||||||
|
// Finally we can stop the recursion
|
||||||
|
//----------------------
|
||||||
|
|
||||||
|
points.append(QPointF(x23, y23));
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_cusp_limit > 0.0 || m_cusp_limit < 0.0)
|
||||||
|
{
|
||||||
|
if (da1 > m_cusp_limit)
|
||||||
|
{
|
||||||
|
points.append(QPointF(x2, y2));
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (da2 > m_cusp_limit)
|
||||||
|
{
|
||||||
|
points.append(QPointF(x3, y3));
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue subdivision
|
||||||
|
//----------------------
|
||||||
|
auto BezierTailPoints = [x1234, y1234, x234, y234, x34, y34, x4, y4, level, approximationScale]()
|
||||||
|
{
|
||||||
|
QVector<QPointF> tail;
|
||||||
|
return PointBezier_r(x1234, y1234, x234, y234, x34, y34, x4, y4, static_cast<qint16>(level + 1), tail,
|
||||||
|
approximationScale);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto BezierPoints = [x1, y1, x12, y12, x123, y123, x1234, y1234, level, points, approximationScale]()
|
||||||
|
{
|
||||||
|
return PointBezier_r(x1, y1, x12, y12, x123, y123, x1234, y1234, static_cast<qint16>(level + 1), points,
|
||||||
|
approximationScale);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (level < 1)
|
||||||
|
{
|
||||||
|
QFuture<QVector<QPointF>> futureBezier = QtConcurrent::run(BezierPoints);
|
||||||
|
const QVector<QPointF> tail = BezierTailPoints();
|
||||||
|
return futureBezier.result() + tail;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BezierPoints() + BezierTailPoints();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
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)
|
||||||
|
@ -182,333 +516,6 @@ void VAbstractCubicBezier::CreateName()
|
||||||
setName(name);
|
setName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* @brief CalcSqDistance calculate squared distance.
|
|
||||||
* @param x1 х coordinate first point.
|
|
||||||
* @param y1 у coordinate first point.
|
|
||||||
* @param x2 х coordinate second point.
|
|
||||||
* @param y2 у coordinate second point.
|
|
||||||
* @return squared length.
|
|
||||||
*/
|
|
||||||
qreal VAbstractCubicBezier::CalcSqDistance(qreal x1, qreal y1, qreal x2, qreal y2)
|
|
||||||
{
|
|
||||||
const qreal dx = x2 - x1;
|
|
||||||
const qreal dy = y2 - y1;
|
|
||||||
return dx * dx + dy * dy;
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* @brief PointBezier_r find spline point using four point of spline.
|
|
||||||
* @param x1 х coordinate first point.
|
|
||||||
* @param y1 у coordinate first point.
|
|
||||||
* @param x2 х coordinate first control point.
|
|
||||||
* @param y2 у coordinate first control point.
|
|
||||||
* @param x3 х coordinate second control point.
|
|
||||||
* @param y3 у coordinate second control point.
|
|
||||||
* @param x4 х coordinate last point.
|
|
||||||
* @param y4 у coordinate last point.
|
|
||||||
* @param level level of recursion. In the begin 0.
|
|
||||||
* @param px list х coordinat spline points.
|
|
||||||
* @param py list у coordinat spline points.
|
|
||||||
* @param approximationScale curve approximation scale.
|
|
||||||
*/
|
|
||||||
void VAbstractCubicBezier::PointBezier_r(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4,
|
|
||||||
qint16 level, QVector<qreal> &px, QVector<qreal> &py, qreal approximationScale)
|
|
||||||
{
|
|
||||||
if (px.size() >= 2)
|
|
||||||
{
|
|
||||||
for (int i=1; i < px.size(); ++i)
|
|
||||||
{
|
|
||||||
if (QPointF(px.at(i-1), py.at(i-1)) == QPointF(px.at(i), py.at(i)))
|
|
||||||
{
|
|
||||||
qDebug("All neighbors points in path must be unique.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const double curve_collinearity_epsilon = 1e-30;
|
|
||||||
const double curve_angle_tolerance_epsilon = 0.01;
|
|
||||||
const double m_angle_tolerance = 0.0;
|
|
||||||
enum curve_recursion_limit_e { curve_recursion_limit = 32 };
|
|
||||||
const double m_cusp_limit = 0.0;
|
|
||||||
|
|
||||||
double m_approximation_scale = approximationScale;
|
|
||||||
if(m_approximation_scale < minCurveApproximationScale || m_approximation_scale > maxCurveApproximationScale)
|
|
||||||
{
|
|
||||||
m_approximation_scale = qApp->Settings()->GetCurveApproximationScale();
|
|
||||||
}
|
|
||||||
|
|
||||||
double m_distance_tolerance_square;
|
|
||||||
|
|
||||||
m_distance_tolerance_square = 0.5 / m_approximation_scale;
|
|
||||||
m_distance_tolerance_square *= m_distance_tolerance_square;
|
|
||||||
|
|
||||||
if (level > curve_recursion_limit)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate all the mid-points of the line segments
|
|
||||||
//----------------------
|
|
||||||
const double x12 = (x1 + x2) / 2;
|
|
||||||
const double y12 = (y1 + y2) / 2;
|
|
||||||
const double x23 = (x2 + x3) / 2;
|
|
||||||
const double y23 = (y2 + y3) / 2;
|
|
||||||
const double x34 = (x3 + x4) / 2;
|
|
||||||
const double y34 = (y3 + y4) / 2;
|
|
||||||
const double x123 = (x12 + x23) / 2;
|
|
||||||
const double y123 = (y12 + y23) / 2;
|
|
||||||
const double x234 = (x23 + x34) / 2;
|
|
||||||
const double y234 = (y23 + y34) / 2;
|
|
||||||
const double x1234 = (x123 + x234) / 2;
|
|
||||||
const double y1234 = (y123 + y234) / 2;
|
|
||||||
|
|
||||||
|
|
||||||
// Try to approximate the full cubic curve by a single straight line
|
|
||||||
//------------------
|
|
||||||
const double dx = x4-x1;
|
|
||||||
const double dy = y4-y1;
|
|
||||||
|
|
||||||
double d2 = fabs((x2 - x4) * dy - (y2 - y4) * dx);
|
|
||||||
double d3 = fabs((x3 - x4) * dy - (y3 - y4) * dx);
|
|
||||||
|
|
||||||
switch ((static_cast<int>(d2 > curve_collinearity_epsilon) << 1) +
|
|
||||||
static_cast<int>(d3 > curve_collinearity_epsilon))
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
// All collinear OR p1==p4
|
|
||||||
//----------------------
|
|
||||||
double k = dx*dx + dy*dy;
|
|
||||||
if (k < 0.000000001)
|
|
||||||
{
|
|
||||||
d2 = CalcSqDistance(x1, y1, x2, y2);
|
|
||||||
d3 = CalcSqDistance(x4, y4, x3, y3);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
k = 1 / k;
|
|
||||||
{
|
|
||||||
const double da1 = x2 - x1;
|
|
||||||
const double da2 = y2 - y1;
|
|
||||||
d2 = k * (da1*dx + da2*dy);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const double da1 = x3 - x1;
|
|
||||||
const double da2 = y3 - y1;
|
|
||||||
d3 = k * (da1*dx + da2*dy);
|
|
||||||
}
|
|
||||||
if (d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1)
|
|
||||||
{
|
|
||||||
// Simple collinear case, 1---2---3---4
|
|
||||||
// We can leave just two endpoints
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (d2 <= 0)
|
|
||||||
{
|
|
||||||
d2 = CalcSqDistance(x2, y2, x1, y1);
|
|
||||||
}
|
|
||||||
else if (d2 >= 1)
|
|
||||||
{
|
|
||||||
d2 = CalcSqDistance(x2, y2, x4, y4);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
d2 = CalcSqDistance(x2, y2, x1 + d2*dx, y1 + d2*dy);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d3 <= 0)
|
|
||||||
{
|
|
||||||
d3 = CalcSqDistance(x3, y3, x1, y1);
|
|
||||||
}
|
|
||||||
else if (d3 >= 1)
|
|
||||||
{
|
|
||||||
d3 = CalcSqDistance(x3, y3, x4, y4);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
d3 = CalcSqDistance(x3, y3, x1 + d3*dx, y1 + d3*dy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (d2 > d3)
|
|
||||||
{
|
|
||||||
if (d2 < m_distance_tolerance_square)
|
|
||||||
{
|
|
||||||
px.append(x2);
|
|
||||||
py.append(y2);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (d3 < m_distance_tolerance_square)
|
|
||||||
{
|
|
||||||
px.append(x3);
|
|
||||||
py.append(y3);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
// p1,p2,p4 are collinear, p3 is significant
|
|
||||||
//----------------------
|
|
||||||
if (d3 * d3 <= m_distance_tolerance_square * (dx*dx + dy*dy))
|
|
||||||
{
|
|
||||||
if (m_angle_tolerance < curve_angle_tolerance_epsilon)
|
|
||||||
{
|
|
||||||
px.append(x23);
|
|
||||||
py.append(y23);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Angle Condition
|
|
||||||
//----------------------
|
|
||||||
double da1 = fabs(atan2(y4 - y3, x4 - x3) - atan2(y3 - y2, x3 - x2));
|
|
||||||
if (da1 >= M_PI)
|
|
||||||
{
|
|
||||||
da1 = M_2PI - da1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (da1 < m_angle_tolerance)
|
|
||||||
{
|
|
||||||
px.append(x2);
|
|
||||||
py.append(y2);
|
|
||||||
|
|
||||||
px.append(x3);
|
|
||||||
py.append(y3);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_cusp_limit > 0.0 || m_cusp_limit < 0.0)
|
|
||||||
{
|
|
||||||
if (da1 > m_cusp_limit)
|
|
||||||
{
|
|
||||||
px.append(x3);
|
|
||||||
py.append(y3);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
// p1,p3,p4 are collinear, p2 is significant
|
|
||||||
//----------------------
|
|
||||||
if (d2 * d2 <= m_distance_tolerance_square * (dx*dx + dy*dy))
|
|
||||||
{
|
|
||||||
if (m_angle_tolerance < curve_angle_tolerance_epsilon)
|
|
||||||
{
|
|
||||||
px.append(x23);
|
|
||||||
py.append(y23);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Angle Condition
|
|
||||||
//----------------------
|
|
||||||
double da1 = fabs(atan2(y3 - y2, x3 - x2) - atan2(y2 - y1, x2 - x1));
|
|
||||||
if (da1 >= M_PI)
|
|
||||||
{
|
|
||||||
da1 = M_2PI - da1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (da1 < m_angle_tolerance)
|
|
||||||
{
|
|
||||||
px.append(x2);
|
|
||||||
py.append(y2);
|
|
||||||
|
|
||||||
px.append(x3);
|
|
||||||
py.append(y3);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_cusp_limit > 0.0 || m_cusp_limit < 0.0)
|
|
||||||
{
|
|
||||||
if (da1 > m_cusp_limit)
|
|
||||||
{
|
|
||||||
px.append(x2);
|
|
||||||
py.append(y2);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 3:
|
|
||||||
{
|
|
||||||
// Regular case
|
|
||||||
//-----------------
|
|
||||||
if ((d2 + d3)*(d2 + d3) <= m_distance_tolerance_square * (dx*dx + dy*dy))
|
|
||||||
{
|
|
||||||
// If the curvature doesn't exceed the distance_tolerance value
|
|
||||||
// we tend to finish subdivisions.
|
|
||||||
//----------------------
|
|
||||||
if (m_angle_tolerance < curve_angle_tolerance_epsilon)
|
|
||||||
{
|
|
||||||
px.append(x23);
|
|
||||||
py.append(y23);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Angle & Cusp Condition
|
|
||||||
//----------------------
|
|
||||||
const double k = atan2(y3 - y2, x3 - x2);
|
|
||||||
double da1 = fabs(k - atan2(y2 - y1, x2 - x1));
|
|
||||||
double da2 = fabs(atan2(y4 - y3, x4 - x3) - k);
|
|
||||||
if (da1 >= M_PI)
|
|
||||||
{
|
|
||||||
da1 = M_2PI - da1;
|
|
||||||
}
|
|
||||||
if (da2 >= M_PI)
|
|
||||||
{
|
|
||||||
da2 = M_2PI - da2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (da1 + da2 < m_angle_tolerance)
|
|
||||||
{
|
|
||||||
// Finally we can stop the recursion
|
|
||||||
//----------------------
|
|
||||||
|
|
||||||
px.append(x23);
|
|
||||||
py.append(y23);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_cusp_limit > 0.0 || m_cusp_limit < 0.0)
|
|
||||||
{
|
|
||||||
if (da1 > m_cusp_limit)
|
|
||||||
{
|
|
||||||
px.append(x2);
|
|
||||||
py.append(y2);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (da2 > m_cusp_limit)
|
|
||||||
{
|
|
||||||
px.append(x3);
|
|
||||||
py.append(y3);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Continue subdivision
|
|
||||||
//----------------------
|
|
||||||
PointBezier_r(x1, y1, x12, y12, x123, y123, x1234, y1234, static_cast<qint16>(level + 1), px, py,
|
|
||||||
approximationScale);
|
|
||||||
PointBezier_r(x1234, y1234, x234, y234, x34, y34, x4, y4, static_cast<qint16>(level + 1), px, py,
|
|
||||||
approximationScale);
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* @brief GetCubicBezierPoints return list with cubic bezier curve points.
|
* @brief GetCubicBezierPoints return list with cubic bezier curve points.
|
||||||
|
@ -523,20 +530,10 @@ QVector<QPointF> VAbstractCubicBezier::GetCubicBezierPoints(const QPointF &p1, c
|
||||||
const QPointF &p4, qreal approximationScale)
|
const QPointF &p4, qreal approximationScale)
|
||||||
{
|
{
|
||||||
QVector<QPointF> pvector;
|
QVector<QPointF> pvector;
|
||||||
QVector<qreal> x;
|
pvector.append(p1);
|
||||||
QVector<qreal> y;
|
pvector = PointBezier_r(p1.x(), p1.y(), p2.x(), p2.y(), p3.x(), p3.y(), p4.x(), p4.y(), 0, pvector,
|
||||||
QVector<qreal>& wx = x;
|
approximationScale);
|
||||||
QVector<qreal>& wy = y;
|
pvector.append(p4);
|
||||||
x.append ( p1.x () );
|
|
||||||
y.append ( p1.y () );
|
|
||||||
PointBezier_r ( p1.x (), p1.y (), p2.x (), p2.y (),
|
|
||||||
p3.x (), p3.y (), p4.x (), p4.y (), 0, wx, wy, approximationScale );
|
|
||||||
x.append ( p4.x () );
|
|
||||||
y.append ( p4.y () );
|
|
||||||
for ( qint32 i = 0; i < x.count(); ++i )
|
|
||||||
{
|
|
||||||
pvector.append( QPointF ( x.at(i), y.at(i)) );
|
|
||||||
}
|
|
||||||
return pvector;
|
return pvector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,10 +64,6 @@ public:
|
||||||
protected:
|
protected:
|
||||||
virtual void CreateName() override;
|
virtual void CreateName() override;
|
||||||
|
|
||||||
static qreal CalcSqDistance(qreal x1, qreal y1, qreal x2, qreal y2);
|
|
||||||
static void PointBezier_r(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4,
|
|
||||||
qreal y4, qint16 level, QVector<qreal> &px, QVector<qreal> &py,
|
|
||||||
qreal approximationScale);
|
|
||||||
static QVector<QPointF> GetCubicBezierPoints(const QPointF &p1, const QPointF &p2, const QPointF &p3,
|
static QVector<QPointF> GetCubicBezierPoints(const QPointF &p1, const QPointF &p2, const QPointF &p3,
|
||||||
const QPointF &p4, qreal approximationScale);
|
const QPointF &p4, qreal approximationScale);
|
||||||
static qreal LengthBezier(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4,
|
static qreal LengthBezier(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4,
|
||||||
|
|
|
@ -971,6 +971,10 @@ QVector<QPointF> VAbstractPiece::CheckLoops(const QVector<QPointF> &points)
|
||||||
const bool pathClosed = (points.first() == points.last());
|
const bool pathClosed = (points.first() == points.last());
|
||||||
|
|
||||||
QVector<QPointF> ekvPoints;
|
QVector<QPointF> ekvPoints;
|
||||||
|
ekvPoints.reserve(points.size());
|
||||||
|
|
||||||
|
QVector<qint32> uniqueVertices;
|
||||||
|
uniqueVertices.reserve(4);
|
||||||
|
|
||||||
qint32 i, j, jNext = 0;
|
qint32 i, j, jNext = 0;
|
||||||
for (i = 0; i < count; ++i)
|
for (i = 0; i < count; ++i)
|
||||||
|
@ -1000,7 +1004,7 @@ QVector<QPointF> VAbstractPiece::CheckLoops(const QVector<QPointF> &points)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<qint32> uniqueVertices;
|
uniqueVertices.clear();
|
||||||
|
|
||||||
auto AddUniqueIndex = [&uniqueVertices](qint32 i)
|
auto AddUniqueIndex = [&uniqueVertices](qint32 i)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue
Block a user