Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_algebra_2d.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2014 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#ifndef __KIS_ALGEBRA_2D_H
8#define __KIS_ALGEBRA_2D_H
9
10#include <QPoint>
11#include <QPointF>
12#include <QVector>
13#include <QPolygonF>
14#include <QTransform>
15#include <cmath>
16#include <kis_global.h>
17#include <kritaglobal_export.h>
18#include <functional>
19#include <boost/optional.hpp>
20
21class QPainterPath;
22class QTransform;
23
24namespace KisAlgebra2D {
25
26template <class T>
28{
29};
30
31template <>
32struct PointTypeTraits<QPoint>
33{
34 typedef int value_type;
35 typedef qreal calculation_type;
36 typedef QRect rect_type;
37};
38
39template <>
40struct PointTypeTraits<QPointF>
41{
42 typedef qreal value_type;
43 typedef qreal calculation_type;
44 typedef QRectF rect_type;
45};
46
47
48template <class T>
49typename PointTypeTraits<T>::value_type dotProduct(const T &a, const T &b)
50{
51 return a.x() * b.x() + a.y() * b.y();
52}
53
54template <class T>
55typename PointTypeTraits<T>::value_type crossProduct(const T &a, const T &b)
56{
57 return a.x() * b.y() - a.y() * b.x();
58}
59
60template <class T>
61qreal norm(const T &a)
62{
63 return std::sqrt(pow2(a.x()) + pow2(a.y()));
64}
65
66template <class Point>
67Point normalize(const Point &a)
68{
69 const qreal length = norm(a);
70 return (1.0 / length) * a;
71}
72
73template <typename Point>
74Point lerp(const Point &pt1, const Point &pt2, qreal t)
75{
76 return pt1 + (pt2 - pt1) * t;
77}
78
82template <typename T>
83T signPZ(T x) {
84 return x >= T(0) ? T(1) : T(-1);
85}
86
90template <typename T>
91T signZZ(T x) {
92 return x == T(0) ? T(0) : x > T(0) ? T(1) : T(-1);
93}
94
98template <typename T>
99 inline T copysign(T x, T y) {
100 T strippedX = qAbs(x);
101 return y >= T(0) ? strippedX : -strippedX;
102}
103
104template<class T>
105typename std::enable_if<std::is_integral<T>::value, T>::type
106divideFloor(T a, T b)
107{
108 const bool a_neg = a < T(0);
109 const bool b_neg = b < T(0);
110
111 if (a == T(0)) {
112 return 0;
113 } else if (a_neg == b_neg) {
114 return a / b;
115 } else {
116 const T a_abs = qAbs(a);
117 const T b_abs = qAbs(b);
118
119 return - 1 - (a_abs - T(1)) / b_abs;
120 }
121}
122
123template <class T>
124T leftUnitNormal(const T &a)
125{
126 T result = a.x() != 0 ? T(-a.y() / a.x(), 1) : T(-1, 0);
127 qreal length = norm(result);
128 result *= (crossProduct(a, result) >= 0 ? 1 : -1) / length;
129
130 return -result;
131}
132
133template <class T>
134T rightUnitNormal(const T &a)
135{
136 return -leftUnitNormal(a);
137}
138
139template <class T>
141{
143}
144
150template<typename R>
152
153template<>
154inline int lazyRound<int>(qreal value)
155{
156 return qRound(value);
157}
158
159template<>
160inline qreal lazyRound<qreal>(qreal value)
161{
162 return value;
163}
164
172template <class T>
173int polygonDirection(const QVector<T> &polygon) {
174
175 typename PointTypeTraits<T>::value_type doubleSum = 0;
176
177 const int numPoints = polygon.size();
178 for (int i = 1; i <= numPoints; i++) {
179 int prev = i - 1;
180 int next = i == numPoints ? 0 : i;
181
182 doubleSum +=
183 (polygon[next].x() - polygon[prev].x()) *
184 (polygon[next].y() + polygon[prev].y());
185 }
186
187 return doubleSum >= 0 ? 1 : -1;
188}
189
190template <typename T>
191bool isInRange(T x, T a, T b) {
192 T length = qAbs(a - b);
193 return qAbs(x - a) <= length && qAbs(x - b) <= length;
194}
195
196void KRITAGLOBAL_EXPORT adjustIfOnPolygonBoundary(const QPolygonF &poly, int polygonDirection, QPointF *pt);
197
204QPointF KRITAGLOBAL_EXPORT transformAsBase(const QPointF &pt, const QPointF &base1, const QPointF &base2);
205
206qreal KRITAGLOBAL_EXPORT angleBetweenVectors(const QPointF &v1, const QPointF &v2);
207
212qreal KRITAGLOBAL_EXPORT directionBetweenPoints(const QPointF &p1, const QPointF &p2,
213 qreal defaultAngle);
214
215namespace Private {
216 inline void resetEmptyRectangle(const QPoint &pt, QRect *rc) {
217 *rc = QRect(pt, QSize(1, 1));
218 }
219
220 inline void resetEmptyRectangle(const QPointF &pt, QRectF *rc) {
221 static const qreal eps = 1e-10;
222 *rc = QRectF(pt, QSizeF(eps, eps));
223 }
224}
225
226template <class Point, class Rect>
227inline void accumulateBounds(const Point &pt, Rect *bounds)
228{
229 if (bounds->isEmpty()) {
231 }
232
237 if (pt.x() < bounds->left()) {
238 bounds->setLeft(pt.x());
239 } else if (pt.x() > bounds->right()) {
240 bounds->setRight(pt.x());
241 }
242
247 if (pt.y() < bounds->top()) {
248 bounds->setTop(pt.y());
249 } else if (pt.y() > bounds->bottom()) {
250 bounds->setBottom(pt.y());
251 }
252}
253
254template <class Point, class Rect>
255inline void accumulateBoundsNonEmpty(const Point &pt, Rect *bounds)
256{
257 if (pt.x() < bounds->left()) {
258 bounds->setLeft(pt.x());
259 } else if (pt.x() > bounds->right()) {
260 bounds->setRight(pt.x());
261 }
262
263 if (pt.y() < bounds->top()) {
264 bounds->setTop(pt.y());
265 } else if (pt.y() > bounds->bottom()) {
266 bounds->setBottom(pt.y());
267 }
268}
269
270template <template <class T> class Container, class Point, class Rect>
271inline void accumulateBounds(const Container<Point> &points, Rect *bounds)
272{
273 Q_FOREACH (const Point &pt, points) {
275 }
276}
277
278template <template <class T> class Container, class Point>
279inline typename PointTypeTraits<Point>::rect_type
280accumulateBounds(const Container<Point> &points)
281{
282 typename PointTypeTraits<Point>::rect_type result;
283
284 Q_FOREACH (const Point &pt, points) {
285 accumulateBounds(pt, &result);
286 }
287
288 return result;
289}
290
291template <class Point, class Rect>
292inline Point clampPoint(Point pt, const Rect &bounds)
293{
294 if (pt.x() > bounds.right()) {
295 pt.rx() = bounds.right();
296 }
297
298 if (pt.x() < bounds.left()) {
299 pt.rx() = bounds.left();
300 }
301
302 if (pt.y() > bounds.bottom()) {
303 pt.ry() = bounds.bottom();
304 }
305
306 if (pt.y() < bounds.top()) {
307 pt.ry() = bounds.top();
308 }
309
310 return pt;
311}
312
313template <class Size>
314auto maxDimension(Size size) -> decltype(size.width()) {
315 return qMax(size.width(), size.height());
316}
317
318template <class Size>
319auto minDimension(Size size) -> decltype(size.width()) {
320 return qMin(size.width(), size.height());
321}
322
323QPainterPath KRITAGLOBAL_EXPORT smallArrow();
324
329template <class Rect>
330Rect blowRect(const Rect &rect, qreal coeff)
331{
332 typedef decltype(rect.x()) CoordType;
333
334 CoordType w = rect.width() * coeff;
335 CoordType h = rect.height() * coeff;
336
337 return rect.adjusted(-w, -h, w, h);
338}
339
340QPoint KRITAGLOBAL_EXPORT ensureInRect(QPoint pt, const QRect &bounds);
341QPointF KRITAGLOBAL_EXPORT ensureInRect(QPointF pt, const QRectF &bounds);
342
343template <class Rect>
344Rect ensureRectNotSmaller(Rect rc, const decltype(Rect().size()) &size)
345{
346 typedef decltype(Rect().size()) Size;
347 typedef decltype(Rect().top()) ValueType;
348
349 if (rc.width() < size.width() ||
350 rc.height() < size.height()) {
351
352 ValueType width = qMax(rc.width(), size.width());
353 ValueType height = qMax(rc.height(), size.height());
354
355 rc = Rect(rc.topLeft(), Size(width, height));
356 }
357
358 return rc;
359}
360
361template <class Size>
362Size ensureSizeNotSmaller(const Size &size, const Size &bounds)
363{
364 Size result = size;
365
366 const auto widthBound = qAbs(bounds.width());
367 auto width = result.width();
368 if (qAbs(width) < widthBound) {
369 width = copysign(widthBound, width);
370 result.setWidth(width);
371 }
372
373 const auto heightBound = qAbs(bounds.height());
374 auto height = result.height();
375 if (qAbs(height) < heightBound) {
376 height = copysign(heightBound, height);
377 result.setHeight(height);
378 }
379
380 return result;
381}
382
396bool KRITAGLOBAL_EXPORT intersectLineRect(QLineF &line, const QRect rect, bool extend);
397
415bool KRITAGLOBAL_EXPORT intersectLineRect(QLineF &line, const QRect rect, bool extendFirst, bool extendSecond);
416
417// the same but with a convex polygon; uses Cyrus-Beck algorithm
418bool KRITAGLOBAL_EXPORT intersectLineConvexPolygon(QLineF &line, const QPolygonF polygon, bool extendFirst, bool extendSecond);
419
438void KRITAGLOBAL_EXPORT cropLineToRect(QLineF &line, const QRect rect, bool extendFirst, bool extendSecond);
439
440void KRITAGLOBAL_EXPORT cropLineToConvexPolygon(QLineF &line, const QPolygonF polygon, bool extendFirst, bool extendSecond);
441
442
443
444
445template <class Point>
446inline Point abs(const Point &pt) {
447 return Point(qAbs(pt.x()), qAbs(pt.y()));
448}
449
450template<typename T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
451inline T wrapValue(T value, T wrapBounds) {
452 value %= wrapBounds;
453 if (value < 0) {
454 value += wrapBounds;
455 }
456 return value;
457}
458
459template<typename T, typename std::enable_if<std::is_floating_point<T>::value, T>::type* = nullptr>
460inline T wrapValue(T value, T wrapBounds) {
461 value = std::fmod(value, wrapBounds);
462 if (value < 0) {
463 value += wrapBounds;
464 }
465 return value;
466}
467
468template<typename T, typename std::enable_if<std::is_same<decltype(T().x()), decltype(T().y())>::value, T>::type* = nullptr>
469inline T wrapValue(T value, T wrapBounds) {
470 value.rx() = wrapValue(value.x(), wrapBounds.x());
471 value.ry() = wrapValue(value.y(), wrapBounds.y());
472 return value;
473}
474
475template<typename T>
476inline T wrapValue(T value, T min, T max) {
477 return wrapValue(value - min, max - min) + min;
478}
479
481public:
482
483 RightHalfPlane(const QPointF &a, const QPointF &b)
484 : m_a(a), m_p(b - a), m_norm_p_inv(1.0 / norm(m_p))
485 {
486 }
487
488 RightHalfPlane(const QLineF &line)
489 : RightHalfPlane(line.p1(), line.p2())
490 {
491 }
492
493 qreal valueSq(const QPointF &pt) const {
494 const qreal val = value(pt);
495 return signZZ(val) * pow2(val);
496 }
497
498 qreal value(const QPointF &pt) const {
499 return crossProduct(m_p, pt - m_a) * m_norm_p_inv;
500 }
501
502 int pos(const QPointF &pt) const {
503 return signZZ(value(pt));
504 }
505
506 QLineF getLine() const {
507 return QLineF(m_a, m_a + m_p);
508 }
509
510private:
511 const QPointF m_a;
512 const QPointF m_p;
513 const qreal m_norm_p_inv;
514};
515
517public:
518
519 OuterCircle(const QPointF &c, qreal radius)
520 : m_c(c),
521 m_radius(radius),
522 m_radius_sq(pow2(radius)),
523 m_fadeCoeff(1.0 / (pow2(radius + 1.0) - m_radius_sq))
524 {
525 }
526
527 qreal valueSq(const QPointF &pt) const {
528 const qreal val = value(pt);
529
530 return signZZ(val) * pow2(val);
531 }
532
533 qreal value(const QPointF &pt) const {
534 return kisDistance(pt, m_c) - m_radius;
535 }
536
537 int pos(const QPointF &pt) const {
538 return signZZ(valueSq(pt));
539 }
540
541 qreal fadeSq(const QPointF &pt) const {
542 const qreal valSq = kisSquareDistance(pt, m_c);
543 return (valSq - m_radius_sq) * m_fadeCoeff;
544 }
545
546private:
547 const QPointF m_c;
548 const qreal m_radius;
549 const qreal m_radius_sq;
550 const qreal m_fadeCoeff;
551};
552
553QVector<QPoint> KRITAGLOBAL_EXPORT sampleRectWithPoints(const QRect &rect);
554QVector<QPointF> KRITAGLOBAL_EXPORT sampleRectWithPoints(const QRectF &rect);
555
556QRect KRITAGLOBAL_EXPORT approximateRectFromPoints(const QVector<QPoint> &points);
557QRectF KRITAGLOBAL_EXPORT approximateRectFromPoints(const QVector<QPointF> &points);
558
559QRect KRITAGLOBAL_EXPORT approximateRectWithPointTransform(const QRect &rect, std::function<QPointF(QPointF)> func);
560
561
566KRITAGLOBAL_EXPORT
567QRectF cutOffRect(const QRectF &rc, const KisAlgebra2D::RightHalfPlane &p);
568
569
586KRITAGLOBAL_EXPORT
587int quadraticEquation(qreal a, qreal b, qreal c, qreal *x1, qreal *x2);
588
593KRITAGLOBAL_EXPORT
594QVector<QPointF> intersectTwoCircles(const QPointF &c1, qreal r1,
595 const QPointF &c2, qreal r2);
596
597KRITAGLOBAL_EXPORT
598QTransform mapToRect(const QRectF &rect);
599
600KRITAGLOBAL_EXPORT
601QTransform mapToRectInverse(const QRectF &rect);
602
607inline QPointF relativeToAbsolute(const QPointF &pt, const QRectF &rc) {
608 return rc.topLeft() + QPointF(pt.x() * rc.width(), pt.y() * rc.height());
609}
610
615inline QPointF absoluteToRelative(const QPointF &pt, const QRectF &rc) {
616 const QPointF rel = pt - rc.topLeft();
617 return QPointF(rc.width() > 0 ? rel.x() / rc.width() : 0,
618 rc.height() > 0 ? rel.y() / rc.height() : 0);
619
620}
621
626inline qreal relativeToAbsolute(qreal value, const QRectF &rc) {
627 const qreal coeff = std::sqrt(pow2(rc.width()) + pow2(rc.height())) / std::sqrt(2.0);
628 return value * coeff;
629}
630
635inline qreal absoluteToRelative(const qreal value, const QRectF &rc) {
636 const qreal coeff = std::sqrt(pow2(rc.width()) + pow2(rc.height())) / std::sqrt(2.0);
637 return coeff != 0 ? value / coeff : 0;
638}
639
644inline QRectF relativeToAbsolute(const QRectF &rel, const QRectF &rc) {
645 return QRectF(relativeToAbsolute(rel.topLeft(), rc), relativeToAbsolute(rel.bottomRight(), rc));
646}
647
652inline QRectF absoluteToRelative(const QRectF &rel, const QRectF &rc) {
653 return QRectF(absoluteToRelative(rel.topLeft(), rc), absoluteToRelative(rel.bottomRight(), rc));
654}
655
659bool KRITAGLOBAL_EXPORT fuzzyMatrixCompare(const QTransform &t1, const QTransform &t2, qreal delta);
660
665bool KRITAGLOBAL_EXPORT fuzzyPointCompare(const QPointF &p1, const QPointF &p2);
666
670bool KRITAGLOBAL_EXPORT fuzzyPointCompare(const QPointF &p1, const QPointF &p2, qreal delta);
671
675template <template<typename> class Cont, class Point>
676bool fuzzyPointCompare(const Cont<Point> &c1, const Cont<Point> &c2, qreal delta)
677{
678 if (c1.size() != c2.size()) return false;
679
680 const qreal eps = delta;
681
682 return std::mismatch(c1.cbegin(),
683 c1.cend(),
684 c2.cbegin(),
685 [eps] (const QPointF &pt1, const QPointF &pt2) {
686 return fuzzyPointCompare(pt1, pt2, eps);
687 })
688 .first == c1.cend();
689}
690
696template<class Rect, typename Difference = decltype(Rect::width())>
697bool fuzzyCompareRects(const Rect &r1, const Rect &r2, Difference tolerance) {
698 typedef decltype(r1.topLeft()) Point;
699
700 const Point d1 = abs(r1.topLeft() - r2.topLeft());
701 const Point d2 = abs(r1.bottomRight() - r2.bottomRight());
702
703 const Difference maxError = std::max({d1.x(), d1.y(), d2.x(), d2.y()});
704 return maxError < tolerance;
705}
706
707struct KRITAGLOBAL_EXPORT DecomposedMatrix {
709
710 DecomposedMatrix(const QTransform &t0);
711
712 inline QTransform scaleTransform() const
713 {
714 return QTransform::fromScale(scaleX, scaleY);
715 }
716
717 inline QTransform shearTransform() const
718 {
719 QTransform t;
720 t.shear(shearXY, 0);
721 return t;
722 }
723
724 inline QTransform rotateTransform() const
725 {
726 QTransform t;
727 t.rotate(angle);
728 return t;
729 }
730
731 inline QTransform translateTransform() const
732 {
733 return QTransform::fromTranslate(dx, dy);
734 }
735
736 inline QTransform projectTransform() const
737 {
738 return
739 QTransform(
740 1,0,proj[0],
741 0,1,proj[1],
742 0,0,proj[2]);
743 }
744
745 inline QTransform transform() const {
746 return
747 scaleTransform() *
748 shearTransform() *
749 rotateTransform() *
750 translateTransform() *
751 projectTransform();
752 }
753
754 inline bool isValid() const {
755 return valid;
756 }
757
758 qreal scaleX = 1.0;
759 qreal scaleY = 1.0;
760 qreal shearXY = 0.0;
761 qreal angle = 0.0;
762 qreal dx = 0.0;
763 qreal dy = 0.0;
764 qreal proj[3] = {0.0, 0.0, 1.0};
765
766private:
767 bool valid = true;
768};
769
770// NOTE: tiar: this seems to ignore perspective transformation, be wary and use the class in PerspectiveEllipseAssistant.cpp instead
771// this is only good for rotation, translation and possibly shear
772std::pair<QPointF, QTransform> KRITAGLOBAL_EXPORT transformEllipse(const QPointF &axes, const QTransform &fullLocalToGlobal);
773
774QPointF KRITAGLOBAL_EXPORT alignForZoom(const QPointF &pt, qreal zoom);
775
776
781template <typename T>
782inline T linearReshapeFunc(T x, T x0, T x1, T y0, T y1)
783{
784 return y0 + (y1 - y0) * (x - x0) / (x1 - x0);
785}
786
787
792KRITAGLOBAL_EXPORT
793boost::optional<QPointF> intersectLines(const QLineF &boundedLine, const QLineF &unboundedLine);
794
795
800KRITAGLOBAL_EXPORT
801boost::optional<QPointF> intersectLines(const QPointF &p1, const QPointF &p2,
802 const QPointF &q1, const QPointF &q2);
803
809QVector<QPointF> KRITAGLOBAL_EXPORT findTrianglePoint(const QPointF &p1, const QPointF &p2, qreal a, qreal b);
810
817boost::optional<QPointF> KRITAGLOBAL_EXPORT findTrianglePointNearest(const QPointF &p1, const QPointF &p2, qreal a, qreal b, const QPointF &nearest);
818
833QPointF KRITAGLOBAL_EXPORT moveElasticPoint(const QPointF &pt,
834 const QPointF &base, const QPointF &newBase,
835 const QPointF &wingA, const QPointF &wingB);
836
850QPointF KRITAGLOBAL_EXPORT moveElasticPoint(const QPointF &pt,
851 const QPointF &base, const QPointF &newBase,
852 const QVector<QPointF> &anchorPoints);
853
854
865{
866public:
868 : m_base(base)
869 {
870 }
871
872 int generate(int maxRange) {
874 return (m_n * maxRange + m_d / 2) / m_d;
875 }
876
877 qreal generate() {
879 return qreal(m_n) / m_d;
880 }
881
882 void step() {
884 }
885
886 int currentValue(int maxRange) const {
887 return (m_n * maxRange + m_d / 2) / m_d;
888 }
889
890 qreal currentValue() const{
891 return qreal(m_n) / m_d;
892 }
893
894private:
895 inline void generationStep() {
896 int x = m_d - m_n;
897
898 if (x == 1) {
899 m_n = 1;
900 m_d *= m_base;
901 } else {
902 int y = m_d / m_base;
903 while (x <= y) {
904 y /= m_base;
905 }
906 m_n = (m_base + 1) * y - x;
907 }
908 }
909
910private:
911 int m_n = 0;
912 int m_d = 1;
913 const int m_base = 0;
914};
915
916
917// find minimum of the function f(x) between points xA and xB, with eps precision, using Golden Ratio Section
918// requirements: only one local minimum between xA and xB
919// Golden Section is supposed to be usually faster than Ternary Section
920// NOTE: tiar: this function was debugged and should be working correctly but is not used anywhere any longer
921qreal findMinimumGoldenSection(std::function<qreal(qreal)> f, qreal xA, qreal xB, qreal eps, int maxIter);
922
923// find minimum of the function f(x) between points xA and xB, with eps precision, using Ternary Section
924// requirements: only one local minimum between xA and xB
925// Golden Section is supposed to be usually faster than Ternary Section
926// NOTE: tiar: this function was debugged and should be working correctly but is not used anywhere any longer
927qreal findMinimumTernarySection(std::function<qreal(qreal)> f, qreal xA, qreal xB, qreal eps, int maxIter);
928
929qreal KRITAGLOBAL_EXPORT pointToLineDistSquared(const QPointF& pt, const QLineF& line);
930
931
932}
933
934
935#endif /* __KIS_ALGEBRA_2D_H */
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
float value(const T *src, size_t ch)
QPointF r2
QPointF q1
const Params2D p
Eigen::Matrix< double, 4, 2 > R
QPointF r1
QPointF p2
QPointF q2
QPointF p1
a simple class to generate Halton sequence
OuterCircle(const QPointF &c, qreal radius)
qreal valueSq(const QPointF &pt) const
qreal value(const QPointF &pt) const
int pos(const QPointF &pt) const
qreal fadeSq(const QPointF &pt) const
RightHalfPlane(const QPointF &a, const QPointF &b)
qreal value(const QPointF &pt) const
int pos(const QPointF &pt) const
RightHalfPlane(const QLineF &line)
qreal valueSq(const QPointF &pt) const
#define bounds(x, a, b)
const qreal eps
qreal kisDistance(const QPointF &pt1, const QPointF &pt2)
Definition kis_global.h:190
T pow2(const T &x)
Definition kis_global.h:166
qreal kisSquareDistance(const QPointF &pt1, const QPointF &pt2)
Definition kis_global.h:194
void resetEmptyRectangle(const QPoint &pt, QRect *rc)
boost::optional< QPointF > findTrianglePointNearest(const QPointF &p1, const QPointF &p2, qreal a, qreal b, const QPointF &nearest)
QVector< QPointF > intersectTwoCircles(const QPointF &center1, qreal r1, const QPointF &center2, qreal r2)
auto maxDimension(Size size) -> decltype(size.width())
QPointF relativeToAbsolute(const QPointF &pt, const QRectF &rc)
QPointF absoluteToRelative(const QPointF &pt, const QRectF &rc)
Rect blowRect(const Rect &rect, qreal coeff)
qreal findMinimumTernarySection(std::function< qreal(qreal)> f, qreal xA, qreal xB, qreal eps, int maxIter=100)
T leftUnitNormal(const T &a)
QVector< Point > sampleRectWithPoints(const Rect &rect)
T linearReshapeFunc(T x, T x0, T x1, T y0, T y1)
T wrapValue(T value, T wrapBounds)
QRect approximateRectFromPoints(const QVector< QPoint > &points)
Point abs(const Point &pt)
std::enable_if< std::is_integral< T >::value, T >::type divideFloor(T a, T b)
auto minDimension(Size size) -> decltype(size.width())
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)
Point lerp(const Point &pt1, const Point &pt2, qreal t)
void accumulateBounds(const Point &pt, Rect *bounds)
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)
T copysign(T x, T y)
qreal pointToLineDistSquared(const QPointF &pt, const QLineF &line)
Rect ensureRectNotSmaller(Rect rc, const decltype(Rect().size()) &size)
QPoint ensureInRect(QPoint pt, const QRect &bounds)
int quadraticEquation(qreal a, qreal b, qreal c, qreal *x1, qreal *x2)
Size ensureSizeNotSmaller(const Size &size, const Size &bounds)
QPointF alignForZoom(const QPointF &pt, qreal zoom)
Point normalize(const Point &a)
void cropLineToRect(QLineF &line, const QRect rect, bool extendFirst, bool extendSecond)
bool fuzzyCompareRects(const Rect &r1, const Rect &r2, Difference tolerance)
bool isInRange(T x, T a, T b)
Point clampPoint(Point pt, const Rect &bounds)
QPainterPath smallArrow()
qreal lazyRound< qreal >(qreal value)
qreal norm(const T &a)
QVector< QPointF > findTrianglePoint(const QPointF &p1, const QPointF &p2, qreal a, qreal b)
PointTypeTraits< T >::value_type dotProduct(const T &a, const T &b)
void accumulateBoundsNonEmpty(const Point &pt, Rect *bounds)
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)
R lazyRound(qreal value)
int polygonDirection(const QVector< T > &polygon)
T inwardUnitNormal(const T &a, int polygonDirection)
bool intersectLineConvexPolygon(QLineF &line, const QPolygonF polygon, bool extendFirst, bool extendSecond)
T rightUnitNormal(const T &a)
int lazyRound< int >(qreal value)
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)
QTransform shearTransform() const
QTransform projectTransform() const
QTransform rotateTransform() const
QTransform scaleTransform() const
QTransform translateTransform() const