18#include <config-gsl.h>
21#include <gsl/gsl_multimin.h>
38 stackedPoints.push(std::make_tuple(
p3, 3 * (
p3 -
p2), 1.0));
41 QPointF lastD = 3 * (
p1 -
p0);
44 while (!stackedPoints.isEmpty()) {
45 QPointF
p = std::get<0>(stackedPoints.top());
46 QPointF d = std::get<1>(stackedPoints.top());
47 qreal t = std::get<2>(stackedPoints.top());
49 if (t - lastT < minStepSize ||
58 t = 0.5 * (lastT + t);
62 stackedPoints.push(std::make_tuple(
p, d, t));
73 std::merge(a.constBegin(), a.constEnd(),
74 b.constBegin(), b.constEnd(),
75 std::back_inserter(result));
77 std::unique(result.begin(), result.end(),
78 [] (qreal x, qreal y) { return qFuzzyCompare(x, y); }),
96 for (
int i = 0; i <=
degree; ++i)
105 for (
int i = 0; i <=
degree; ++i)
112 return points.count() - 1;
117 if (
static_cast<int>(index) >
degree())
125 if (
static_cast<int>(index) >
degree())
138 for (
int i = 0; i <= deg; ++i)
139 Vtemp[i].resize(deg + 1);
142 for (
int j = 0; j <= deg; j++) {
147 for (
int i = 1; i <= deg; i++) {
148 for (
int j =0 ; j <= deg - i; j++) {
149 Vtemp[i][j].rx() = (1.0 - t) * Vtemp[i-1][j].x() + t * Vtemp[i-1][j+1].x();
150 Vtemp[i][j].ry() = (1.0 - t) * Vtemp[i-1][j].y() + t * Vtemp[i-1][j+1].y();
156 for (
int j = 0; j <= deg; j++) {
162 for (
int j = 0; j <= deg; j++) {
163 right->
setPoint(j, Vtemp[deg-j][j]);
167 return (Vtemp[deg][0]);
181 if (! xAxisCrossings) {
185 else if (xAxisCrossings == 1) {
191 rootParams.append((
points.first().x() +
points.last().x()) / 2.0);
197 QPointF segStart =
points.first();
198 rootParams.append((chord.x() * segStart.y() - chord.y() * segStart.x()) / - chord.y());
206 rootParams += left.
roots(depth+1);
207 rootParams += right.
roots(depth+1);
214 int controlPointCount = controlPoints.count();
215 if (controlPointCount < 2)
220 int currSign = controlPoints[0].y() < 0.0 ? -1 : 1;
223 for (
short i = 1; i < controlPointCount; ++i) {
225 currSign = controlPoints[i].y() < 0.0 ? -1 : 1;
227 if (currSign != oldSign) {
242 qreal *
distance =
new qreal[deg + 1];
249 qreal abSquared = (a * a) + (b * b);
251 for (
int i = 1; i < deg; i++) {
264 qreal max_distance_above = 0.0;
265 qreal max_distance_below = 0.0;
266 for (
int i = 1; i < deg; i++) {
268 max_distance_below = qMin(max_distance_below,
distance[i]);
271 max_distance_above = qMax(max_distance_above,
distance[i]);
284 qreal c2 = c + max_distance_above;
286 qreal det = a1 * b2 - a2 * b1;
287 qreal dInv = 1.0/det;
289 qreal intercept_1 = (b1 * c2 - b2 * c1) * dInv;
294 c2 = c + max_distance_below;
296 det = a1 * b2 - a2 * b1;
299 qreal intercept_2 = (b1 * c2 - b2 * c1) * dInv;
302 qreal left_intercept = qMin(intercept_1, intercept_2);
303 qreal right_intercept = qMax(intercept_1, intercept_2);
305 qreal error = 0.5 * (right_intercept-left_intercept);
307 return (error < tolerance);
314 Q_FOREACH (
const QPointF &
p,
points) {
315 qDebug() << QString(
"P%1 ").arg(index++) <<
p;
326 const int deg = controlPoints.size() - 1;
331 QPointF chord = controlPoints.last() - controlPoints.first();
333 QPointF relPoint = point - controlPoints.first();
335 qreal scale = chord.x() * relPoint.x() + chord.y() * relPoint.y();
337 scale /= chord.x() * chord.x() + chord.y() * chord.y();
341 }
else if (scale > 1.0) {
384 QPointF * c_i =
new QPointF[ deg + 1 ];
386 for (
int i = 0; i <= deg; ++i) {
387 c_i[ i ] = ctlPoints[ i ] - point;
391 QPointF *d_j =
new QPointF[deg];
393 for (
int j = 0; j <= deg - 1; ++j) {
394 d_j[j] = 3.0 * (ctlPoints[j+1] - ctlPoints[j]);
398 qreal *products =
new qreal[deg * (deg + 1)];
400 for (
int j = 0; j <= deg - 1; ++j) {
401 for (
int i = 0; i <= deg; ++i) {
402 products[j * (deg + 1) + i] = d_j[j].x() * c_i[i].x() + d_j[j].y() * c_i[i].y();
414 for (
unsigned short u = 0;
u <= 2 * deg - 1; ++
u) {
415 newCurve.
setPoint(
u, QPointF(
static_cast<qreal
>(
u) /
static_cast<qreal
>(2 * deg - 1), 0.0));
419 static const qreal z3[3*4] = {1.0, 0.6, 0.3, 0.1, 0.4, 0.6, 0.6, 0.4, 0.1, 0.3, 0.6, 1.0};
421 static const qreal z2[2*3] = {1.0, 2./3., 1./3., 1./3., 2./3., 1.0};
423 const qreal *z = deg == 3 ? z3 : z2;
426 for (
int k = 0; k <= 2 * deg - 1; ++k) {
427 int min = qMin(k, deg);
429 for (
unsigned short i = qMax(0, k - (deg - 1)); i <= min; ++i) {
430 unsigned short j = k - i;
433 QPointF currentPoint = newCurve.
point(k);
434 currentPoint.ry() += products[j * (deg + 1) + i] * z[j * (deg + 1) + i];
449 qreal minDistanceSquared = distanceSquared;
450 qreal resultParam = 0.0;
451 if (resultDistance) {
452 *resultDistance = std::sqrt(distanceSquared);
455 *resultPoint = controlPoints.first();
459 Q_FOREACH (qreal root, rootParams) {
460 const QPointF rootPoint =
bezierCurve(controlPoints, root);
463 if (distanceSquared < minDistanceSquared) {
464 minDistanceSquared = distanceSquared;
466 if (resultDistance) {
467 *resultDistance = std::sqrt(distanceSquared);
470 *resultPoint = rootPoint;
477 if (distanceSquared < minDistanceSquared) {
478 minDistanceSquared = distanceSquared;
480 if (resultDistance) {
481 *resultDistance = std::sqrt(distanceSquared);
484 *resultPoint = controlPoints.last();
507struct LevelBasedPatchMethod
509 LevelBasedPatchMethod(qreal
u, qreal
v,
const Params2D &
p)
544 R <<
p.r0.x(),
p.r0.y(),
549 S <<
p.s0.x(),
p.s0.y(),
554 P <<
p.p0.x(),
p.p0.y(),
559 Q <<
p.q0.x(),
p.q0.y(),
577 Eigen::Matrix<double, 2, 4>
M_1;
585 Eigen::Matrix<double, 4, 2>
R;
586 Eigen::Matrix<double, 4, 2>
S;
587 Eigen::Matrix<double, 4, 2>
P;
588 Eigen::Matrix<double, 4, 2>
Q;
590 Eigen::Matrix<double, 1, 4>
T_u3;
591 Eigen::Matrix<double, 1, 4>
T_v3;
595 Eigen::Matrix<double, 1, 2>
T_u1;
596 Eigen::Matrix<double, 1, 2>
T_v1;
600 QPointF
value()
const {
601 Eigen::Matrix<double, 1, 2> L_1 =
T_v3 *
M_3 *
R;
604 Eigen::Matrix<double, 1, 2> L_4 =
T_v3 *
M_3 *
S;
606 Eigen::Matrix<double, 4, 2> L_controls;
607 L_controls << L_1, L_2, L_3, L_4;
612 Eigen::Matrix<double, 1, 2> H_1 =
T_u3 *
M_3 *
P;
615 Eigen::Matrix<double, 1, 2> H_4 =
T_u3 *
M_3 *
Q;
617 Eigen::Matrix<double, 4, 2> H_controls;
618 H_controls << H_1, H_2, H_3, H_4;
622 Eigen::Matrix<double, 1, 2> result = 0.5 * (L + H);
624 return QPointF(result(0,0), result(0,1));
627 QPointF diffU()
const {
628 Eigen::Matrix<double, 1, 2> L_1 =
T_v3 *
M_3 *
R;
631 Eigen::Matrix<double, 1, 2> L_4 =
T_v3 *
M_3 *
S;
633 Eigen::Matrix<double, 4, 2> L_controls;
634 L_controls << L_1, L_2, L_3, L_4;
644 Eigen::Matrix<double, 4, 2> H_controls;
645 H_controls << H_1, H_2, H_3, H_4;
649 Eigen::Matrix<double, 1, 2> result = 0.5 * (L + H);
650 return QPointF(result(0,0), result(0,1));
653 QPointF diffV()
const {
659 Eigen::Matrix<double, 4, 2> L_controls;
660 L_controls << L_1, L_2, L_3, L_4;
664 Eigen::Matrix<double, 1, 2> H_1 =
T_u3 *
M_3 *
P;
667 Eigen::Matrix<double, 1, 2> H_4 =
T_u3 *
M_3 *
Q;
669 Eigen::Matrix<double, 4, 2> H_controls;
670 H_controls << H_1, H_2, H_3, H_4;
674 Eigen::Matrix<double, 1, 2> result = 0.5 * (L + H);
676 return QPointF(result(0,0), result(0,1));
689 static QPointF meshForwardMapping(qreal u, qreal v,
const Params2D &p) {
690 return p.r0 +
pow3(u)*
v*(
p.p0 - 3*
p.p1 + 3*
p.p2 -
p.p3 -
p.q0 + 3*
p.q1 - 3*
p.q2 +
p.q3) +
pow3(u)*(-
p.p0 + 3*
p.p1 - 3*
p.p2 +
p.p3) +
pow2(u)*
v*(-3*
p.p0 + 6*
p.p1 - 3*
p.p2 + 3*
p.q0 - 6*
p.q1 + 3*
p.q2) +
pow2(u)*(3*
p.p0 - 6*
p.p1 + 3*
p.p2) + u*
pow3(v)*(
p.r0 - 3*
p.r1 + 3*
p.r2 -
p.r3 -
p.s0 + 3*
p.s1 - 3*
p.s2 +
p.s3) + u*
pow2(v)*(-3*
p.r0 + 6*
p.r1 - 3*
p.r2 + 3*
p.s0 - 6*
p.s1+ 3*
p.s2) + u*v*(2*
p.p0 - 3*
p.p1 +
p.p3 - 2*
p.q0 + 3*
p.q1 -
p.q3 + 3*
p.r0 - 3*
p.r1 - 3*
p.s0 + 3*
p.s1) +
u*(-2*
p.p0 + 3*
p.p1 -
p.p3 -
p.r0 +
p.s0) +
pow3(v)*(-
p.r0 + 3*
p.r1 - 3*
p.r2 +
p.r3) +
pow2(v)*(3*
p.r0 - 6*
p.r1 + 3*
p.r2) + v*(-3*
p.r0 + 3*
p.r1);
693 static QPointF meshForwardMappingDiffU(qreal u, qreal v,
const Params2D &p) {
694 return -2*
p.p0 + 3*
p.p1 -
p.p3 -
p.r0 +
p.s0 +
pow2(u)*
v*(3*
p.p0 - 9*
p.p1 + 9*
p.p2 - 3*
p.p3 - 3*
p.q0 + 9*
p.q1 - 9*
p.q2 + 3*
p.q3) +
pow2(u)*(-3*
p.p0 + 9*
p.p1 - 9*
p.p2 + 3*
p.p3) + u*v*(-6*
p.p0 + 12*
p.p1 - 6*
p.p2 + 6*
p.q0 - 12*
p.q1 + 6*
p.q2) +
u*(6*
p.p0 - 12*
p.p1 + 6*
p.p2) +
pow3(v)*(
p.r0 - 3*
p.r1 + 3*
p.r2 -
p.r3 -
p.s0 + 3*
p.s1 - 3*
p.s2 +
p.s3) +
pow2(v)*(-3*
p.r0 + 6*
p.r1 - 3*
p.r2 + 3*
p.s0 - 6*
p.s1 + 3*
p.s2) + v*(2*
p.p0 - 3*
p.p1 +
p.p3 - 2*
p.q0 + 3*
p.q1 -
p.q3 + 3*
p.r0 - 3*
p.r1 - 3*
p.s0 + 3*
p.s1);
697 static QPointF meshForwardMappingDiffV(qreal u, qreal v,
const Params2D &p) {
698 return -3*
p.r0 + 3*
p.r1 +
pow3(u)*(
p.p0 - 3*
p.p1 + 3*
p.p2 -
p.p3 -
p.q0 + 3*
p.q1 - 3*
p.q2 +
p.q3) +
pow2(u)*(-3*
p.p0 + 6*
p.p1 - 3*
p.p2 + 3*
p.q0 - 6*
p.q1 + 3*
p.q2) + u*
pow2(v)*(3*
p.r0 - 9*
p.r1 + 9*
p.r2 - 3*
p.r3 - 3*
p.s0 + 9*
p.s1 - 9*
p.s2 + 3*
p.s3) + u*v*(-6*
p.r0 + 12*
p.r1 - 6*
p.r2 + 6*
p.s0 - 12*
p.s1 + 6*
p.s2) +
u*(2*
p.p0 - 3*
p.p1 +
p.p3 - 2*
p.q0 + 3*
p.q1 -
p.q3 + 3*
p.r0 - 3*
p.r1 - 3*
p.s0 + 3*
p.s1) +
pow2(v)*(-3*
p.r0 + 9*
p.r1 - 9*
p.r2 + 3*
p.r3) + v*(6*
p.r0 - 12*
p.r1 + 6*
p.r2);
706 SvgPatchMethod(qreal _u, qreal _v,
const Params2D &_p)
707 :
u(_u),
v(_v),
p(_p)
711 QPointF
value()
const {
712 return meshForwardMapping(u, v, p);
715 QPointF diffU()
const {
716 return meshForwardMappingDiffU(u, v, p);
719 QPointF diffV()
const {
720 return meshForwardMappingDiffV(u, v, p);
725template <
class PatchMethod>
726double my_f(
const gsl_vector * x,
void *paramsPtr)
728 const Params2D *params =
static_cast<const Params2D*
>(paramsPtr);
729 const QPointF pos(gsl_vector_get(x, 0), gsl_vector_get(x, 1));
731 PatchMethod mat(pos.x(), pos.y(), *params);
732 const QPointF
S = mat.value();
737template <
class PatchMethod>
738void my_fdf (
const gsl_vector *x,
void *paramsPtr,
double *f, gsl_vector *df)
740 const Params2D *params =
static_cast<const Params2D*
>(paramsPtr);
741 const QPointF pos(gsl_vector_get(x, 0), gsl_vector_get(x, 1));
743 PatchMethod mat(pos.x(), pos.y(), *params);
744 const QPointF
S = mat.value();
745 const QPointF dU = mat.diffU();
746 const QPointF dV = mat.diffV();
750 gsl_vector_set(df, 0,
751 2 * (
S.x() - params->dstPoint.x()) * dU.x() +
752 2 * (
S.y() - params->dstPoint.y()) * dU.y());
753 gsl_vector_set(df, 1,
754 2 * (
S.x() - params->dstPoint.x()) * dV.x() +
755 2 * (
S.y() - params->dstPoint.y()) * dV.y());
758template <
class PatchMethod>
759void my_df (
const gsl_vector *x,
void *paramsPtr,
762 const Params2D *params =
static_cast<const Params2D*
>(paramsPtr);
763 const QPointF pos(gsl_vector_get(x, 0), gsl_vector_get(x, 1));
765 PatchMethod mat(pos.x(), pos.y(), *params);
766 const QPointF
S = mat.value();
767 const QPointF dU = mat.diffU();
768 const QPointF dV = mat.diffV();
770 gsl_vector_set(df, 0,
771 2 * (
S.x() - params->dstPoint.x()) * dU.x() +
772 2 * (
S.y() - params->dstPoint.y()) * dU.y());
773 gsl_vector_set(df, 1,
774 2 * (
S.x() - params->dstPoint.x()) * dV.x() +
775 2 * (
S.y() - params->dstPoint.y()) * dV.y());
779template <
class PatchMethod>
784 for (
auto it = points.begin(); it != points.end(); ++it) {
792 const gsl_multimin_fdfminimizer_type *T =
793 gsl_multimin_fdfminimizer_vector_bfgs2;
794 gsl_multimin_fdfminimizer *s = 0;
796 gsl_multimin_function_fdf minex_func;
802 x = gsl_vector_alloc (2);
803 gsl_vector_set (x, 0, approxStart.x());
804 gsl_vector_set (x, 1, approxStart.y());
828 p.dstPoint = globalPoint;
832 minex_func.f = my_f<PatchMethod>;
833 minex_func.params = (
void*)&
p;
834 minex_func.df = my_df<PatchMethod>;
835 minex_func.fdf = my_fdf<PatchMethod>;
837 s = gsl_multimin_fdfminimizer_alloc (T, 2);
838 gsl_multimin_fdfminimizer_set (s, &minex_func, x, 0.01, 0.1);
843 result.rx() = gsl_vector_get (s->x, 0);
844 result.ry() = gsl_vector_get (s->x, 1);
849 status = gsl_multimin_fdfminimizer_iterate(s);
854 status = gsl_multimin_test_gradient (s->gradient, 1e-4);
856 result.rx() = gsl_vector_get (s->x, 0);
857 result.ry() = gsl_vector_get (s->x, 1);
859 if (status == GSL_SUCCESS)
861 result.rx() = gsl_vector_get (s->x, 0);
862 result.ry() = gsl_vector_get (s->x, 1);
867 while (status == GSL_CONTINUE && iter < 10000);
873 gsl_multimin_fdfminimizer_free (s);
881template <
class PatchMethod>
906 PatchMethod f(localPoint.x(), localPoint.y(),
p);
912 return calculateLocalPosImpl<LevelBasedPatchMethod>(points, globalPoint);
917 return calculateGlobalPosImpl<LevelBasedPatchMethod>(points, localPoint);
922 return calculateLocalPosImpl<SvgPatchMethod>(points, globalPoint);
927 return calculateGlobalPosImpl<SvgPatchMethod>(points, localPoint);
932 if (t <= 0.0 || t >= 1.0)
943 QPointF c1 = pt - (1.0-t) * (1.0-t)*
p0 - t * t *
p2;
945 qreal denom = 2.0 * t * (1.0-t);
968 feel_good = (pow((6 * t - 1) / 2.0, 3)) / 2;
969 else if (t <= 5.0 / 6.0)
970 feel_good = (1 - pow((6 * (1-t) - 1) / 2.0, 3)) / 2 + 0.5;
974 const QPointF moveP1 = ((1-feel_good)/(3*t*(1-t)*(1-t))) * offset;
975 const QPointF moveP2 = (feel_good/(3*t*t*(1-t))) * offset;
977 return std::make_pair(moveP1, moveP2);
980qreal
curveLength(
const QPointF
p0,
const QPointF
p1,
const QPointF
p2,
const QPointF
p3,
const qreal error)
1020 qreal polyLength = 0.0;
1026 if ((polyLength - chordLen) > error) {
1035 return 0.5 * chordLen + 0.5 * polyLength;
1037 return (2.0 * chordLen + polyLength) / 3.0;
1051 const qreal splitAtParam = expectedLength / totalLength;
1058 if (std::abs(portionLength - expectedLength) < error) {
1059 return splitAtParam;
1060 }
else if (portionLength < expectedLength) {
1061 return splitAtParam + (1.0 - splitAtParam) *
curveParamBySegmentLength(
q2,
q3, q4,
p3, expectedLength - portionLength, totalLength - portionLength, error);
1071 const qreal expectedLength = proportion * totalLength;
1147 const qreal z = lenP / (lenP + lenQ);
1155 Eigen::DiagonalMatrix<float, 4> Z_1;
1156 Z_1.diagonal() << 1, z,
pow2(z),
pow3(z);
1158 Eigen::Matrix4f Z_2;
1160 0, 1 - z, 2 * z * (1 - z), 3 *
pow2(z) * (1 - z),
1161 0, 0,
pow2(1 - z), 3 * z *
pow2(1 - z),
1162 0, 0, 0,
pow3(1 - z);
1164 Eigen::Matrix<float, 8, 2>
R;
1165 R <<
p0.x(),
p0.y(),
1174 Eigen::Matrix<float, 2, 2> B_const;
1175 B_const <<
p0.x(),
p0.y(),
1179 Eigen::Matrix4f M1 = M.inverse() * Z_1 * M;
1180 Eigen::Matrix4f M2 = M.inverse() * Z_2 * M;
1182 Eigen::Matrix<float, 8, 4>
C;
1185 Eigen::Matrix<float, 8, 2> C_const;
1186 C_const <<
C.col(0),
C.col(3);
1188 Eigen::Matrix<float, 8, 2> C_var;
1189 C_var <<
C.col(1),
C.col(2);
1191 Eigen::Matrix<float, 8, 2> R_var;
1192 R_var =
R - C_const * B_const;
1194 Eigen::Matrix<float, 6, 2> R_reduced;
1195 R_reduced = R_var.block(1, 0, 6, 2);
1197 Eigen::Matrix<float, 6, 2> C_reduced;
1198 C_reduced = C_var.block(1, 0, 6, 2);
1200 Eigen::Matrix<float, 2, 2> result;
1201 result = (C_reduced.transpose() * C_reduced).inverse() * C_reduced.transpose() * R_reduced;
1203 QPointF resultP0(result(0, 0), result(0, 1));
1204 QPointF resultP1(result(1, 0), result(1, 1));
1206 return std::make_pair(resultP0, resultP1);
1220 if (intersectLines(
p0,
p3, line.p1(), line.p2())) {
1221 result << alpha * 0.5 + beta;
1225 const bool hasIntersections =
1226 intersectLines(
p0,
p1, line.p1(), line.p2()) ||
1227 intersectLines(
p1,
p2, line.p1(), line.p2()) ||
1228 intersectLines(
p2,
p3, line.p1(), line.p2());
1230 if (hasIntersections) {
1251 qreal minDistance = std::numeric_limits<qreal>::max();
1252 boost::optional<qreal> nearestRoot;
1254 Q_FOREACH (qreal root, result) {
qreal length(const QPointF &vec)
float value(const T *src, size_t ch)
Eigen::Matrix< double, 4, 2 > Q
Eigen::Matrix< double, 4, 2 > S
Eigen::Matrix< double, 4, 2 > RS_bottom
Eigen::Matrix< double, 1, 4 > T_dot_v3
Eigen::Matrix< double, 4, 2 > PQ_left
Eigen::Matrix< double, 1, 2 > T_dot_u1
Eigen::Matrix< double, 4, 2 > RS_top
Eigen::Matrix4d M_3rel2abs
Eigen::Matrix< double, 1, 2 > T_u1
Eigen::Matrix< double, 4, 2 > R
Eigen::Matrix< double, 1, 4 > T_dot_u3
Eigen::Matrix< double, 1, 2 > T_dot_v1
Eigen::Matrix< double, 1, 2 > T_v1
Eigen::Matrix< double, 1, 4 > T_u3
Eigen::Matrix< double, 1, 4 > T_v3
Eigen::Matrix< double, 2, 4 > M_1
Eigen::Matrix< double, 4, 2 > PQ_right
qreal distance(const QPointF &p1, const QPointF &p2)
QPointF lerp(const QPointF &p1, const QPointF &p2, qreal t)
int isFlat(qreal tolerance) const
const int MaxRecursionDepth
Maximal recursion depth for finding root params.
QPointF evaluate(qreal t, BezierSegment *left, BezierSegment *right) const
static uint controlPolygonZeros(const QList< QPointF > &controlPoints)
void setPoint(int index, const QPointF &p)
BezierSegment(int degree=0, QPointF *p=0)
QPointF point(int index) const
const qreal FlatnessTolerance
Flatness tolerance for finding root params.
QList< qreal > roots(int depth=0) const
void setDegree(int degree)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
qreal kisDistance(const QPointF &pt1, const QPointF &pt2)
qreal kisSquareDistance(const QPointF &pt1, const QPointF &pt2)
QPointF absoluteToRelative(const QPointF &pt, const QRectF &rc)
void accumulateBounds(const Point &pt, Rect *bounds)
boost::optional< QPointF > intersectLines(const QLineF &boundedLine, const QLineF &unboundedLine)
qreal curveParamByProportion(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, qreal proportion, const qreal error)
QPointF calculateLocalPos(const std::array< QPointF, 12 > &points, const QPointF &globalPoint)
calculates local (u,v) coordinates of the patch corresponding to globalPoint
void deCasteljau(const QPointF &q0, const QPointF &q1, const QPointF &q2, const QPointF &q3, qreal t, QPointF *p0, QPointF *p1, QPointF *p2, QPointF *p3, QPointF *p4)
QPointF calculateLocalPosSVG2(const std::array< QPointF, 12 > &points, const QPointF &globalPoint)
calculates local (u,v) coordinates of the patch corresponding to globalPoint
QPointF calculateLocalPosImpl(const std::array< QPointF, 12 > &points, const QPointF &globalPoint)
QVector< qreal > intersectWithLine(const QPointF &p0, const QPointF &p1, const QPointF &p2, const QPointF &p3, const QLineF &line, qreal eps)
qreal curveProportionByParam(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, qreal t, const qreal error)
QVector< qreal > linearizeCurve(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, const qreal eps)
qreal curveLengthAtPoint(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, qreal t, const qreal error)
QVector< qreal > intersectWithLineImpl(const QPointF &p0, const QPointF &p1, const QPointF &p2, const QPointF &p3, const QLineF &line, qreal eps, qreal alpha, qreal beta)
QPointF calculateGlobalPos(const std::array< QPointF, 12 > &points, const QPointF &localPoint)
calculates global coordinate corresponding to the patch coordinate (u, v)
bool isLinearSegmentByDerivatives(const QPointF &p0, const QPointF &d0, const QPointF &p1, const QPointF &d1, const qreal eps=1e-4)
int controlPolygonZeros(const QList< QPointF > &controlPoints)
QPointF calculateGlobalPosSVG2(const std::array< QPointF, 12 > &points, const QPointF &localPoint)
calculates global coordinate corresponding to the patch coordinate (u, v)
QPointF bezierCurveDeriv(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, qreal t)
qreal curveParamBySegmentLength(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, qreal expectedLength, qreal totalLength, const qreal error)
std::pair< QPointF, QPointF > offsetSegment(qreal t, const QPointF &offset)
moves point t of the curve by offset offset
QPointF bezierCurve(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, qreal t)
qreal nearestPoint(const QList< QPointF > controlPoints, const QPointF &point, qreal *resultDistance, QPointF *resultPoint)
std::pair< QPointF, QPointF > removeBezierNode(const QPointF &p0, const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &q1, const QPointF &q2, const QPointF &q3)
Adjusts position for the bezier control points after removing a node.
qreal curveLength(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, const qreal error)
QPointF calculateGlobalPosImpl(const std::array< QPointF, 12 > &points, const QPointF &localPoint)
QVector< qreal > mergeLinearizationSteps(const QVector< qreal > &a, const QVector< qreal > &b)
boost::optional< qreal > intersectWithLineNearest(const QPointF &p0, const QPointF &p1, const QPointF &p2, const QPointF &p3, const QLineF &line, const QPointF &nearestAnchor, qreal eps)
QPointF interpolateQuadric(const QPointF &p0, const QPointF &p2, const QPointF &pt, qreal t)
Interpolates quadric curve passing through given points.
int bezierDegree(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3)