10#include <QPainterPath>
13#include <boost/accumulators/accumulators.hpp>
14#include <boost/accumulators/statistics/stats.hpp>
15#include <boost/accumulators/statistics/min.hpp>
16#include <boost/accumulators/statistics/max.hpp>
24#include <config-gsl.h>
27#include <gsl/gsl_multimin.h>
30#include <Eigen/Eigenvalues>
38 const int numPoints = poly.size();
39 for (
int i = 0; i < numPoints; i++) {
41 if (nextI >= numPoints) {
45 const QPointF &
p0 = poly[i];
46 const QPointF &
p1 = poly[nextI];
48 QPointF edge =
p1 -
p0;
51 / (0.5 * edge.manhattanLength());
59 QPointF adjustedPoint = *pt +
salt;
64 adjustedPoint = *pt -
salt;
88QPointF
transformAsBase(
const QPointF &pt,
const QPointF &base1,
const QPointF &base2) {
89 qreal len1 =
norm(base1);
90 if (len1 < 1e-5)
return pt;
91 qreal sin1 = base1.y() / len1;
92 qreal cos1 = base1.x() / len1;
94 qreal len2 =
norm(base2);
95 if (len2 < 1e-5)
return QPointF();
96 qreal sin2 = base2.y() / len2;
97 qreal cos2 = base2.x() / len2;
99 qreal sinD = sin2 * cos1 - cos2 * sin1;
100 qreal cosD = cos1 * cos2 + sin1 * sin2;
101 qreal scaleD = len2 / len1;
104 result.rx() = scaleD * (pt.x() * cosD - pt.y() * sinD);
105 result.ry() = scaleD * (pt.x() * sinD + pt.y() * cosD);
112 qreal a1 = std::atan2(v1.y(), v1.x());
113 qreal a2 = std::atan2(v2.y(), v2.x());
124 const QVector2D diff(
p2 -
p1);
125 return std::atan2(diff.y(), diff.x());
139 p.arcTo(QRectF(3, -2, 4, 4), 90, -180);
144template <
class Po
int,
class Rect>
147 if (pt.x() >
bounds.right()) {
149 }
else if (pt.x() <
bounds.left()) {
153 if (pt.y() >
bounds.bottom()) {
154 pt.ry() =
bounds.bottom();
155 }
else if (pt.y() <
bounds.top()) {
186 double p1 = -(line.x2() - line.x1());
188 double p3 = -(line.y2() - line.y1());
194 float tmin = extendFirst ? -std::numeric_limits<float>::infinity() : 0;
195 float tmax = extendSecond ? std::numeric_limits<float>::infinity() : 1;
197 for (
int i = 0; i <
p.length(); i++) {
199 if (
p[i] == 0 && q[i] < 0) {
202 }
else if (
p[i] < 0) {
204 double t = q[i]/
p[i];
217 }
else if (
p[i] > 0) {
219 double t = q[i]/
p[i];
233 QPointF pt1 = line.p1();
234 QPointF pt2 = line.p2();
236 if (extendFirst || tmin > 0) {
237 pt1 = QPointF(line.x1() + tmin*(line.x2() - line.x1()), line.y1() + tmin*(line.y2() - line.y1()));
239 if (extendSecond || tmax < 1) {
240 pt2 = QPointF(line.x1() + tmax*(line.x2() - line.x1()), line.y1() + tmax*(line.y2() - line.y1()));
252 qreal epsilon = 1e-07;
254 if (polygon.size() == 0) {
259 if (!extendFirst && !extendSecond && polygon.containsPoint(line.p1(), Qt::WindingFill) && polygon.containsPoint(line.p2(), Qt::WindingFill)) {
271 float aBigNumber = 100000;
272 float tmin = extendFirst ? -aBigNumber : 0;
273 float tmax = extendSecond ? aBigNumber : 1;
280 bool clockwise =
false;
283 QPointF vec1 = polygon[1] - polygon[0];
284 QPointF vec2 = polygon[2] - polygon[0];
286 QLineF line1(QPointF(0, 0), vec1);
287 QLineF line2(QPointF(0, 0), vec2);
289 qreal angle = line1.angleTo(line2);
296 for (
int i = 0; i < polygon.size() - 1; i++) {
297 clippingLines.append(QLineF(polygon[i], polygon[i + 1]));
298 float xdiff = polygon[i].x() - polygon[i + 1].x();
299 float ydiff = polygon[i].y() - polygon[i + 1].y();
302 normals.append(QPointF(ydiff, -xdiff));
304 normals.append(QPointF(-ydiff, xdiff));
309 if (!polygon.isClosed()) {
310 int i = polygon.size() - 1;
311 clippingLines.append(QLineF(polygon[i], polygon[0]));
312 float xdiff = polygon[i].x() - polygon[0].x();
313 float ydiff = polygon[i].y() - polygon[0].y();
316 normals.append(QPointF(ydiff, -xdiff));
318 normals.append(QPointF(-ydiff, xdiff));
323 QPointF lineVec = line.p2() - line.p1();
329 QPointF
p1 = line.p1();
330 QPointF
p2 = line.p2();
333 if (qAbs(lineVec.x()) < epsilon) {
349 for (
int i = 0; i < clippingLines.size(); i++) {
352 QPointF clipVec = clippingLines[i].p2() - clippingLines[i].p1();
354 if (
qFuzzyCompare(clipVec.x()*lineVec.y(), clipVec.y()*lineVec.x())) {
359 qreal distanceBetweenLines = qAbs(pA*clippingLines[i].
p1().x() + pB*clippingLines[i].
p1().y() + pC)
360 /(sqrt(pA*pA + pB*pB));
363 if (qAbs(distanceBetweenLines) < epsilon) {
369 if (qAbs(
p2.x() -
p1.x()) > epsilon) {
370 t1 = (clippingLines[i].p1().x() -
p1.x())/(
p2.x() -
p1.x());
371 t2 = (clippingLines[i].p2().x() -
p1.x())/(
p2.x() -
p1.x());
373 t1 = (clippingLines[i].p1().y() -
p1.y())/(
p2.y() -
p1.y());
374 t2 = (clippingLines[i].p2().y() -
p1.y())/(
p2.y() -
p1.y());
377 qreal tmin1 = qMin(t1, t2);
378 qreal tmax2 = qMax(t1, t2);
404 A <<
p2.x() -
p1.x(), normals[i].x(),
405 p2.y() -
p1.y(), normals[i].y();
406 b << clippingLines[i].p1().x() -
p1.x(),
407 clippingLines[i].p1().y() -
p1.y();
409 Eigen::Vector2f ta =
A.colPivHouseholderQr().solve(b);
420 boost::optional<QPointF> pEOptional =
intersectLines(clippingLines[i], line);
426 QPointF pE = pEOptional.value();
427 QPointF n = normals[i];
429 QPointF
A = line.p2() - line.p1();
430 QPointF
B = line.p1() - pE;
432 qreal over = (n.x()*
B.x() + n.y()*
B.y());
433 qreal under = (n.x()*
A.x() + n.y()*
A.y());
434 qreal t = -over/under;
440 qreal tminvalue = tmin * under + over;
441 qreal tmaxvalue = tmax * under + over;
443 if (tminvalue > 0 && tmaxvalue > 0) {
447 if (tminvalue <= 0 && tmaxvalue <= 0) {
450 if (tminvalue*tmaxvalue < 0) {
480 QLineF response = QLineF(tmin*line.p2() + (1-tmin)*line.p1(), tmax*line.p2() + (1-tmax)*line.p1());
485 template <
class Rect,
class Po
int>
490 Point m1 = 0.5 * (
rect.topLeft() +
rect.topRight());
491 Point m2 = 0.5 * (
rect.bottomLeft() +
rect.bottomRight());
493 points <<
rect.topLeft();
495 points <<
rect.topRight();
497 points << 0.5 * (
rect.topLeft() +
rect.bottomLeft());
498 points << 0.5 * (m1 + m2);
499 points << 0.5 * (
rect.topRight() +
rect.bottomRight());
501 points <<
rect.bottomLeft();
503 points <<
rect.bottomRight();
510 return sampleRectWithPoints<QRect, QPoint>(
rect);
515 return sampleRectWithPoints<QRectF, QPointF>(
rect);
519 template <
class Rect,
class Po
int,
bool alignPixels>
522 using namespace boost::accumulators;
523 accumulator_set<qreal, stats<tag::min, tag::max > > accX;
524 accumulator_set<qreal, stats<tag::min, tag::max > > accY;
526 Q_FOREACH (
const Point &pt, points) {
534 resultRect.setCoords(std::floor(min(accX)), std::floor(min(accY)),
535 std::ceil(max(accX)), std::ceil(max(accY)));
537 resultRect.setCoords(min(accX), min(accY),
538 max(accX), max(accY));
546 return approximateRectFromPointsImpl<QRect, QPoint, true>(points);
551 return approximateRectFromPointsImpl<QRectF, QPointF, false>(points);
558 using namespace boost::accumulators;
559 accumulator_set<qreal, stats<tag::min, tag::max > > accX;
560 accumulator_set<qreal, stats<tag::min, tag::max > > accY;
562 Q_FOREACH (
const QPoint &pt, points) {
563 QPointF dstPt = func(pt);
570 resultRect.setCoords(std::floor(min(accX)), std::floor(min(accY)),
571 std::ceil(max(accX)), std::ceil(max(accY)));
581 const QLineF cutLine =
p.getLine();
583 points << rc.topLeft();
584 points << rc.topRight();
585 points << rc.bottomRight();
586 points << rc.bottomLeft();
588 QPointF
p1 = points[3];
589 bool p1Valid =
p.pos(
p1) >= 0;
593 for (
int i = 0; i < 4; i++) {
594 const QPointF
p2 = points[i];
595 const bool p2Valid =
p.pos(
p2) >= 0;
597 if (p1Valid != p2Valid) {
598 QPointF intersection;
599 cutLine.intersects(QLineF(
p1,
p2), &intersection);
600 resultPoints << intersection;
616 int numSolutions = 0;
618 const qreal
D =
pow2(b) - 4 * a * c;
619 const qreal
eps = 1e-14;
621 if (qAbs(
D) <=
eps) {
627 const qreal sqrt_D = std::sqrt(
D);
629 *x1 = (-b + sqrt_D) / (2 * a);
630 *x2 = (-b - sqrt_D) / (2 * a);
638 const QPointF ¢er2, qreal
r2)
642 const QPointF diff = (center2 - center1);
644 const QPointF c2 = diff;
646 const qreal centerDistance =
norm(diff);
648 if (centerDistance >
r1 +
r2)
return points;
649 if (centerDistance < qAbs(
r1 -
r2))
return points;
651 if (centerDistance < qAbs(
r1 -
r2) + 0.001) {
656 const qreal x_kp1 = diff.x();
657 const qreal y_kp1 = diff.y();
663 const qreal
eps = 1e-6;
665 if (qAbs(diff.y()) <
eps) {
666 qreal x = F2 / diff.x();
676 points << QPointF(x, y1);
677 }
else if (result == 2) {
683 if (
p.pos(
p1) >= 0) {
692 const qreal
A = diff.x() / diff.y();
693 const qreal
C = F2 / diff.y();
704 points << QPointF(x1,
C - x1 *
A);
705 }
else if (result == 2) {
708 QPointF
p1(x1,
C - x1 *
A);
709 QPointF
p2(x2,
C - x2 *
A);
711 if (
p.pos(
p1) >= 0) {
721 for (
int i = 0; i < points.size(); i++) {
722 points[i] = center1 + points[i];
731 QTransform(
rect.width(), 0, 0,
rect.height(),
738 QTransform::fromTranslate(-
rect.x(), -
rect.y()) *
739 QTransform::fromScale(
rect.width() != 0 ? 1.0 /
rect.width() : 0.0,
740 rect.height() != 0 ? 1.0 /
rect.height() : 0.0);
745 qAbs(t1.m11() - t2.m11()) < delta &&
746 qAbs(t1.m12() - t2.m12()) < delta &&
747 qAbs(t1.m13() - t2.m13()) < delta &&
748 qAbs(t1.m21() - t2.m21()) < delta &&
749 qAbs(t1.m22() - t2.m22()) < delta &&
750 qAbs(t1.m23() - t2.m23()) < delta &&
751 qAbs(t1.m31() - t2.m31()) < delta &&
752 qAbs(t1.m32() - t2.m32()) < delta &&
753 qAbs(t1.m33() - t2.m33()) < delta;
764 return qAbs(
p1.x() -
p2.x()) < delta && qAbs(
p1.y() -
p2.y()) < delta;
770 return QTransform(m(0,0), m(0,1), m(0,2),
771 m(1,0), m(1,1), m(1,2),
772 m(2,0), m(2,1), m(2,2));
779 m << t.m11() , t.m12() , t.m13()
780 ,t.m21() , t.m22() , t.m23()
781 ,t.m31() , t.m32() , t.m33();
798 QTransform projMatrix;
800 if (t.m33() == 0.0 || t0.determinant() == 0.0) {
801 qWarning() <<
"Cannot decompose matrix!" << t;
806 if (t.type() == QTransform::TxProject) {
807 QTransform affineTransform(
812 projMatrix = affineTransform.inverted() * t;
815 proj[0] = projMatrix.m13();
816 proj[1] = projMatrix.m23();
817 proj[2] = projMatrix.m33();
821 std::array<Eigen::Vector3d, 3> rows;
825 rows[0] = Eigen::Vector3d(t.m11(), t.m12(), t.m13());
826 rows[1] = Eigen::Vector3d(t.m21(), t.m22(), t.m23());
827 rows[2] = Eigen::Vector3d(t.m31(), t.m32(), t.m33());
830 const qreal invM33 = 1.0 / t.m33();
832 for (
auto &row : rows) {
840 rows[2] = Eigen::Vector3d(0,0,1);
846 shearXY = rows[0].dot(rows[1]);
847 rows[1] = rows[1] -
shearXY * rows[0];
854 qreal determinant = rows[0].x() * rows[1].y() - rows[0].y() * rows[1].x();
855 if (determinant < 0) {
857 if (rows[0].x() < rows[1].y()) {
874 qreal sn = -rows[0].y();
875 qreal cs = rows[0].x();
876 qreal m11 = rows[0].x();
877 qreal m12 = rows[0].y();
878 qreal m21 = rows[1].x();
879 qreal m22 = rows[1].y();
880 rows[0][0] = (cs * m11 + sn * m21);
881 rows[0][1] = (cs * m12 + sn * m22);
882 rows[1][0] = (-sn * m11 + cs * m21);
883 rows[1][1] = (-sn * m12 + cs * m22);
887 rows[0].x(), rows[0].y(), rows[0].z(),
888 rows[1].x(), rows[1].y(), rows[1].z(),
889 rows[2].x(), rows[2].y(), rows[2].z());
899 Eigen::Matrix3d mat3 = mat2 - mat1;
912std::pair<QPointF, QTransform>
transformEllipse(
const QPointF &axes,
const QTransform &fullLocalToGlobal)
915 const QTransform localToGlobal =
924 const QTransform localEllipse = QTransform(1.0 /
pow2(axes.x()), 0.0, 0.0,
925 0.0, 1.0 /
pow2(axes.y()), 0.0,
929 const QTransform globalToLocal = localToGlobal.inverted();
931 Eigen::Matrix3d eqM =
934 globalToLocal.transposed());
938 Eigen::EigenSolver<Eigen::Matrix3d> eigenSolver(eqM);
940 const Eigen::Matrix3d T = eigenSolver.eigenvalues().real().asDiagonal();
941 const Eigen::Matrix3d U = eigenSolver.eigenvectors().real();
943 const Eigen::Matrix3d Ti = eigenSolver.eigenvalues().imag().asDiagonal();
944 const Eigen::Matrix3d
Ui = eigenSolver.eigenvectors().imag();
958 const qreal newA = 1.0 / std::sqrt(T(0,0) * T(2,2));
959 const qreal newB = 1.0 / std::sqrt(T(1,1) * T(2,2));
962 const QTransform newLocalToGlobal = QTransform::fromScale(-1,-1) *
963 newGlobalToLocal.inverted() *
966 return std::make_pair(QPointF(newA, newB), newLocalToGlobal);
971 return QPointF((pt * zoom).toPoint()) / zoom;
974boost::optional<QPointF>
intersectLines(
const QLineF &boundedLine,
const QLineF &unboundedLine)
976 const QPointF
B1 = unboundedLine.p1();
977 const QPointF A1 = unboundedLine.p2() - unboundedLine.p1();
979 const QPointF
B2 = boundedLine.p1();
980 const QPointF A2 = boundedLine.p2() - boundedLine.p1();
982 Eigen::Matrix<float, 2, 2>
A;
983 A << A1.x(), -A2.x(),
986 Eigen::Matrix<float, 2, 1>
B;
987 B <<
B2.x() -
B1.x(),
994 Eigen::Matrix<float, 2, 1> T;
998 const qreal t2 = T(1,0);
999 double epsilon = 1e-06;
1001 if (t2 < 0.0 || t2 > 1.0) {
1002 if (qAbs(t2) > epsilon && qAbs(t2 - 1.0) > epsilon) {
1007 return t2 * A2 +
B2;
1011 const QPointF &
q1,
const QPointF &
q2)
1023 const QPointF
p =
p2 -
p1;
1027 const qreal T = 0.5 * (-
pow2(b) +
pow2(a) + pSq);
1029 if (
p.isNull())
return result;
1031 if (qAbs(
p.x()) > qAbs(
p.y())) {
1032 const qreal
A = 1.0;
1033 const qreal
B2 = -T *
p.y() / pSq;
1034 const qreal
C =
pow2(T) / pSq -
pow2(a *
p.x()) / pSq;
1040 const qreal y = -
B2 /
A;
1041 const qreal x = (T - y *
p.y()) /
p.x();
1042 result <<
p1 + QPointF(x, y);
1044 const qreal y1 = (-
B2 + std::sqrt(D4)) /
A;
1045 const qreal x1 = (T - y1 *
p.y()) /
p.x();
1046 result <<
p1 + QPointF(x1, y1);
1048 const qreal y2 = (-
B2 - std::sqrt(D4)) /
A;
1049 const qreal x2 = (T - y2 *
p.y()) /
p.x();
1050 result <<
p1 + QPointF(x2, y2);
1054 const qreal
A = 1.0;
1055 const qreal
B2 = -T *
p.x() / pSq;
1056 const qreal
C =
pow2(T) / pSq -
pow2(a *
p.y()) / pSq;
1062 const qreal x = -
B2 /
A;
1063 const qreal y = (T - x *
p.x()) /
p.y();
1064 result <<
p1 + QPointF(x, y);
1066 const qreal x1 = (-
B2 + std::sqrt(D4)) /
A;
1067 const qreal y1 = (T - x1 *
p.x()) /
p.y();
1068 result <<
p1 + QPointF(x1, y1);
1070 const qreal x2 = (-
B2 - std::sqrt(D4)) /
A;
1071 const qreal y2 = (T - x2 *
p.x()) /
p.y();
1072 result <<
p1 + QPointF(x2, y2);
1084 boost::optional<QPointF> result;
1086 if (points.size() == 1) {
1087 result = points.first();
1088 }
else if (points.size() > 1) {
1089 result =
kisDistance(points.first(), nearest) <
kisDistance(points.last(), nearest) ? points.first() : points.last();
1095QPointF
moveElasticPoint(
const QPointF &pt,
const QPointF &base,
const QPointF &newBase,
const QPointF &wingA,
const QPointF &wingB)
1101 const QPointF vecL = base - pt;
1102 const QPointF vecLa = wingA - pt;
1103 const QPointF vecLb = wingB - pt;
1105 const qreal L =
norm(vecL);
1106 const qreal La =
norm(vecLa);
1107 const qreal Lb =
norm(vecLb);
1109 const qreal sinMuA =
crossProduct(vecLa, vecL) / (La * L);
1110 const qreal sinMuB =
crossProduct(vecL, vecLb) / (Lb * L);
1112 const qreal cosMuA =
dotProduct(vecLa, vecL) / (La * L);
1113 const qreal cosMuB =
dotProduct(vecLb, vecL) / (Lb * L);
1115 const qreal dL =
dotProduct(newBase - base, -vecL) / L;
1118 const qreal divB = (cosMuB + La / Lb * sinMuB * cosMuA / sinMuA) / L +
1119 (cosMuB + sinMuB * cosMuA / sinMuA) / Lb;
1120 const qreal dLb = dL / ( L * divB);
1122 const qreal divA = (cosMuA + Lb / La * sinMuA * cosMuB / sinMuB) / L +
1123 (cosMuA + sinMuA * cosMuB / sinMuB) / La;
1124 const qreal dLa = dL / ( L * divA);
1126 boost::optional<QPointF> result =
1129 const QPointF resultPoint = result ? *result : pt;
1136struct ElasticMotionData
1142 QPointF oldResultPoint;
1145double elasticMotionError(
const gsl_vector * x,
void *paramsPtr)
1151 const QPointF newResultPoint(gsl_vector_get(x, 0), gsl_vector_get(x, 1));
1153 const ElasticMotionData *
p =
static_cast<const ElasticMotionData*
>(paramsPtr);
1155 const QPointF vecL = newResultPoint -
p->newBasePos;
1156 const qreal L =
norm(vecL);
1158 const qreal deltaL = L -
kisDistance(
p->oldBasePos,
p->oldResultPoint);
1164 Q_FOREACH (
const QPointF &anchorPoint,
p->anchorPoints) {
1165 const QPointF vecLi = newResultPoint - anchorPoint;
1166 const qreal _Li =
norm(vecLi);
1169 deltaLi << _Li -
kisDistance(
p->oldResultPoint, anchorPoint);
1170 cosMuI <<
dotProduct(vecLi, vecL) / (_Li * L);
1174 qreal finalError = 0;
1176 qreal tangentialForceSum = 0;
1177 for (
int i = 0; i <
p->anchorPoints.size(); i++) {
1178 const qreal sum = deltaLi[i] * sinMuI[i] / Li[i];
1179 tangentialForceSum += sum;
1182 finalError +=
pow2(tangentialForceSum);
1184 qreal normalForceSum = 0;
1187 for (
int i = 0; i <
p->anchorPoints.size(); i++) {
1188 sum += deltaLi[i] * cosMuI[i] / Li[i];
1190 normalForceSum = (-deltaL) / L - sum;
1193 finalError +=
pow2(normalForceSum);
1202 const QPointF &base,
const QPointF &newBase,
1205 const QPointF offset = newBase - base;
1207 QPointF newResultPoint = pt + offset;
1211 ElasticMotionData data;
1212 data.newBasePos = newBase;
1213 data.oldBasePos = base;
1214 data.anchorPoints = anchorPoints;
1215 data.oldResultPoint = pt;
1217 const gsl_multimin_fminimizer_type *T =
1218 gsl_multimin_fminimizer_nmsimplex2;
1219 gsl_multimin_fminimizer *s = 0;
1221 gsl_multimin_function minex_func;
1228 x = gsl_vector_alloc (2);
1229 gsl_vector_set (x, 0, newResultPoint.x());
1230 gsl_vector_set (x, 1, newResultPoint.y());
1233 ss = gsl_vector_alloc (2);
1234 gsl_vector_set (ss, 0, 0.1 * offset.x());
1235 gsl_vector_set (ss, 1, 0.1 * offset.y());
1239 minex_func.f = elasticMotionError;
1240 minex_func.params = (
void*)&data;
1242 s = gsl_multimin_fminimizer_alloc (T, 2);
1243 gsl_multimin_fminimizer_set (s, &minex_func, x, ss);
1248 status = gsl_multimin_fminimizer_iterate(s);
1253 size = gsl_multimin_fminimizer_size (s);
1254 status = gsl_multimin_test_size (size, 1e-6);
1261 if (status == GSL_SUCCESS && elasticMotionError(s->x, &data) > 0.5) {
1262 status = GSL_CONTINUE;
1265 if (status == GSL_SUCCESS)
1273 newResultPoint.rx() = gsl_vector_get (s->x, 0);
1274 newResultPoint.ry() = gsl_vector_get (s->x, 1);
1277 while (status == GSL_CONTINUE && iter < 10000);
1279 if (status != GSL_SUCCESS) {
1284 gsl_vector_free(ss);
1285 gsl_multimin_fminimizer_free (s);
1288 return newResultPoint;
1314 const double phi = 0.618033988749894;
1317 qreal c = b - (b - a)*phi;
1318 qreal d = a + (b - a)*phi;
1320 while (qAbs(b - a) >
eps) {
1328 c = b - (b - a) * phi;
1329 d = a + (b - a) * phi;
1347 qreal l = qMin(xA, xB);
1348 qreal r = qMax(xA, xB);
1351 qreal m1 = l + (r - l)/3;
1352 qreal m2 = r - (r - l)/3;
1354 while ((r - l) >
eps) {
1384 const qreal cross = (line.dx() * (line.y1() - pt.y()) - line.dy() * (line.x1() - pt.x()));
1386 return cross * cross / (line.dx() * line.dx() + line.dy() * line.dy());
qreal D(qreal t, const QPointF &P0, const QPointF &P1, const QPointF &P2, const QPointF &P3, const QPointF &p)
static bool qFuzzyCompare(half p1, half p2)
static bool qFuzzyIsNull(half h)
#define KIS_SAFE_ASSERT_RECOVER(cond)
#define KIS_ASSERT_RECOVER_NOOP(cond)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
qreal kisDistance(const QPointF &pt1, const QPointF &pt2)
T kisRadiansToDegrees(T radians)
qreal kisDistanceToLine(const QPointF &m, const QLineF &line)
boost::optional< QPointF > findTrianglePointNearest(const QPointF &p1, const QPointF &p2, qreal a, qreal b, const QPointF &nearest)
QVector< QPointF > intersectTwoCircles(const QPointF ¢er1, qreal r1, const QPointF ¢er2, qreal r2)
Point ensureInRectImpl(Point pt, const Rect &bounds)
qreal findMinimumTernarySection(std::function< qreal(qreal)> f, qreal xA, qreal xB, qreal eps, int maxIter=100)
QTransform toQTransformStraight(const Eigen::Matrix3d &m)
QVector< Point > sampleRectWithPoints(const Rect &rect)
QRect approximateRectFromPoints(const QVector< QPoint > &points)
void adjustIfOnPolygonBoundary(const QPolygonF &poly, int polygonDirection, QPointF *pt)
std::pair< QPointF, QTransform > transformEllipse(const QPointF &axes, const QTransform &fullLocalToGlobal)
bool fuzzyMatrixCompare(const QTransform &t1, const QTransform &t2, qreal delta)
qreal directionBetweenPoints(const QPointF &p1, const QPointF &p2, qreal defaultAngle)
void cropLineToConvexPolygon(QLineF &line, const QPolygonF polygon, bool extendFirst, bool extendSecond)
QTransform mapToRectInverse(const QRectF &rect)
QPointF moveElasticPoint(const QPointF &pt, const QPointF &base, const QPointF &newBase, const QPointF &wingA, const QPointF &wingB)
moveElasticPoint moves point pt based on the model of elasticity
qreal angleBetweenVectors(const QPointF &v1, const QPointF &v2)
qreal pointToLineDistSquared(const QPointF &pt, const QLineF &line)
QPoint ensureInRect(QPoint pt, const QRect &bounds)
int quadraticEquation(qreal a, qreal b, qreal c, qreal *x1, qreal *x2)
QPointF alignForZoom(const QPointF &pt, qreal zoom)
void cropLineToRect(QLineF &line, const QRect rect, bool extendFirst, bool extendSecond)
bool isInRange(T x, T a, T b)
QPainterPath smallArrow()
QVector< QPointF > findTrianglePoint(const QPointF &p1, const QPointF &p2, qreal a, qreal b)
PointTypeTraits< T >::value_type dotProduct(const T &a, const T &b)
QRectF cutOffRect(const QRectF &rc, const KisAlgebra2D::RightHalfPlane &p)
boost::optional< QPointF > intersectLines(const QLineF &boundedLine, const QLineF &unboundedLine)
PointTypeTraits< T >::value_type crossProduct(const T &a, const T &b)
QPointF transformAsBase(const QPointF &pt, const QPointF &base1, const QPointF &base2)
int polygonDirection(const QVector< T > &polygon)
T inwardUnitNormal(const T &a, int polygonDirection)
Rect approximateRectFromPointsImpl(const QVector< Point > &points)
Eigen::Matrix3d fromQTransformStraight(const QTransform &t)
bool intersectLineConvexPolygon(QLineF &line, const QPolygonF polygon, bool extendFirst, bool extendSecond)
QRect approximateRectWithPointTransform(const QRect &rect, std::function< QPointF(QPointF)> func)
bool fuzzyPointCompare(const QPointF &p1, const QPointF &p2)
bool intersectLineRect(QLineF &line, const QRect rect, bool extend)
QTransform mapToRect(const QRectF &rect)
qreal findMinimumGoldenSection(std::function< qreal(qreal)> f, qreal xA, qreal xB, qreal eps, int maxIter=100)
const unsigned char salt[256][256]
QTransform shearTransform() const
QTransform rotateTransform() const
QTransform scaleTransform() const
QTransform translateTransform() const