Krita Source Code Documentation
Loading...
Searching...
No Matches
KisAlgebra2D Namespace Reference

Namespaces

namespace  Private
 

Classes

struct  DecomposedMatrix
 
class  HaltonSequenceGenerator
 a simple class to generate Halton sequence More...
 
class  OuterCircle
 
struct  PointTypeTraits
 
struct  PointTypeTraits< QPoint >
 
struct  PointTypeTraits< QPointF >
 
class  RightHalfPlane
 

Functions

template<class Point >
Point abs (const Point &pt)
 
QPointF absoluteToRelative (const QPointF &pt, const QRectF &rc)
 
qreal absoluteToRelative (const qreal value, const QRectF &rc)
 
QRectF absoluteToRelative (const QRectF &rel, const QRectF &rc)
 
template<template< class T > class Container, class Point >
PointTypeTraits< Point >::rect_type accumulateBounds (const Container< Point > &points)
 
template<template< class T > class Container, class Point , class Rect >
void accumulateBounds (const Container< Point > &points, Rect *bounds)
 
template<class Point , class Rect >
void accumulateBounds (const Point &pt, Rect *bounds)
 
template<class Point , class Rect >
void accumulateBoundsNonEmpty (const Point &pt, Rect *bounds)
 
void adjustIfOnPolygonBoundary (const QPolygonF &poly, int polygonDirection, QPointF *pt)
 
QPointF alignForZoom (const QPointF &pt, qreal zoom)
 
qreal angleBetweenVectors (const QPointF &v1, const QPointF &v2)
 
QRect approximateRectFromPoints (const QVector< QPoint > &points)
 
QRectF approximateRectFromPoints (const QVector< QPointF > &points)
 
template<class Rect , class Point , bool alignPixels>
Rect approximateRectFromPointsImpl (const QVector< Point > &points)
 
QRect approximateRectWithPointTransform (const QRect &rect, std::function< QPointF(QPointF)> func)
 
template<class Rect >
Rect blowRect (const Rect &rect, qreal coeff)
 
template<class Point , class Rect >
Point clampPoint (Point pt, const Rect &bounds)
 
template<typename T >
copysign (T x, T y)
 
void cropLineToConvexPolygon (QLineF &line, const QPolygonF polygon, bool extendFirst, bool extendSecond)
 
void cropLineToRect (QLineF &line, const QRect rect, bool extendFirst, bool extendSecond)
 
template<class T >
PointTypeTraits< T >::value_type crossProduct (const T &a, const T &b)
 
QRectF cutOffRect (const QRectF &rc, const KisAlgebra2D::RightHalfPlane &p)
 
qreal directionBetweenPoints (const QPointF &p1, const QPointF &p2, qreal defaultAngle)
 
template<class T >
std::enable_if< std::is_integral< T >::value, T >::type divideFloor (T a, T b)
 
template<class T >
PointTypeTraits< T >::value_type dotProduct (const T &a, const T &b)
 
QPoint ensureInRect (QPoint pt, const QRect &bounds)
 
QPointF ensureInRect (QPointF pt, const QRectF &bounds)
 
template<class Point , class Rect >
Point ensureInRectImpl (Point pt, const Rect &bounds)
 
template<class Rect >
Rect ensureRectNotSmaller (Rect rc, const decltype(Rect().size()) &size)
 
template<class Size >
Size ensureSizeNotSmaller (const Size &size, const Size &bounds)
 
qreal findMinimumGoldenSection (std::function< qreal(qreal)> f, qreal xA, qreal xB, qreal eps, int maxIter=100)
 
qreal findMinimumTernarySection (std::function< qreal(qreal)> f, qreal xA, qreal xB, qreal eps, int maxIter=100)
 
QVector< QPointF > findTrianglePoint (const QPointF &p1, const QPointF &p2, qreal a, qreal b)
 
boost::optional< QPointF > findTrianglePointNearest (const QPointF &p1, const QPointF &p2, qreal a, qreal b, const QPointF &nearest)
 
Eigen::Matrix3d fromQTransformStraight (const QTransform &t)
 
template<class Rect , typename Difference = decltype(Rect::width())>
bool fuzzyCompareRects (const Rect &r1, const Rect &r2, Difference tolerance)
 
bool fuzzyMatrixCompare (const QTransform &t1, const QTransform &t2, qreal delta)
 
template<template< typename > class Cont, class Point >
bool fuzzyPointCompare (const Cont< Point > &c1, const Cont< Point > &c2, qreal delta)
 
bool fuzzyPointCompare (const QPointF &p1, const QPointF &p2)
 
bool fuzzyPointCompare (const QPointF &p1, const QPointF &p2, qreal delta)
 
bool intersectLineConvexPolygon (QLineF &line, const QPolygonF polygon, bool extendFirst, bool extendSecond)
 
bool intersectLineRect (QLineF &line, const QRect rect, bool extend)
 
bool intersectLineRect (QLineF &line, const QRect rect, bool extendFirst, bool extendSecond)
 
boost::optional< QPointF > intersectLines (const QLineF &boundedLine, const QLineF &unboundedLine)
 
boost::optional< QPointF > intersectLines (const QPointF &p1, const QPointF &p2, const QPointF &q1, const QPointF &q2)
 
QVector< QPointF > intersectTwoCircles (const QPointF &center1, qreal r1, const QPointF &center2, qreal r2)
 
template<class T >
inwardUnitNormal (const T &a, int polygonDirection)
 
template<typename T >
bool isInRange (T x, T a, T b)
 
template<typename R >
R lazyRound (qreal value)
 
template<>
int lazyRound< int > (qreal value)
 
template<>
qreal lazyRound< qreal > (qreal value)
 
template<class T >
leftUnitNormal (const T &a)
 
template<typename Point >
Point lerp (const Point &pt1, const Point &pt2, qreal t)
 
template<typename T >
linearReshapeFunc (T x, T x0, T x1, T y0, T y1)
 
QTransform mapToRect (const QRectF &rect)
 
QTransform mapToRectInverse (const QRectF &rect)
 
template<class Size >
auto maxDimension (Size size) -> decltype(size.width())
 
template<class Size >
auto minDimension (Size size) -> decltype(size.width())
 
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
 
QPointF moveElasticPoint (const QPointF &pt, const QPointF &base, const QPointF &newBase, const QVector< QPointF > &anchorPoints)
 moveElasticPoint moves point pt based on the model of elasticity
 
template<class T >
qreal norm (const T &a)
 
template<class Point >
Point normalize (const Point &a)
 
qreal pointToLineDistSquared (const QPointF &pt, const QLineF &line)
 
template<class T >
int polygonDirection (const QVector< T > &polygon)
 
int quadraticEquation (qreal a, qreal b, qreal c, qreal *x1, qreal *x2)
 
QPointF relativeToAbsolute (const QPointF &pt, const QRectF &rc)
 
QRectF relativeToAbsolute (const QRectF &rel, const QRectF &rc)
 
qreal relativeToAbsolute (qreal value, const QRectF &rc)
 
template<class T >
rightUnitNormal (const T &a)
 
QVector< QPoint > sampleRectWithPoints (const QRect &rect)
 
QVector< QPointF > sampleRectWithPoints (const QRectF &rect)
 
template<class Rect , class Point >
QVector< Point > sampleRectWithPoints (const Rect &rect)
 
template<typename T >
signPZ (T x)
 
template<typename T >
signZZ (T x)
 
QPainterPath smallArrow ()
 
QTransform toQTransformStraight (const Eigen::Matrix3d &m)
 
QPointF transformAsBase (const QPointF &pt, const QPointF &base1, const QPointF &base2)
 
std::pair< QPointF, QTransform > transformEllipse (const QPointF &axes, const QTransform &fullLocalToGlobal)
 
template<typename T >
wrapValue (T value, T min, T max)
 
template<typename T , typename std::enable_if< std::is_integral< T >::value, T >::type * = nullptr>
wrapValue (T value, T wrapBounds)
 

Function Documentation

◆ abs()

template<class Point >
Point KisAlgebra2D::abs ( const Point & pt)
inline

Definition at line 446 of file kis_algebra_2d.h.

446 {
447 return Point(qAbs(pt.x()), qAbs(pt.y()));
448}

◆ absoluteToRelative() [1/3]

QPointF KisAlgebra2D::absoluteToRelative ( const QPointF & pt,
const QRectF & rc )
inline

Get the relative position of pt inside rectangle rc. The point can be outside the rectangle.

Definition at line 615 of file kis_algebra_2d.h.

615 {
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}

◆ absoluteToRelative() [2/3]

qreal KisAlgebra2D::absoluteToRelative ( const qreal value,
const QRectF & rc )
inline

Scales absolute isotropic value from absolute to relative coordinate system using SVG 1.1 rules (see chapter 7.10)

Definition at line 635 of file kis_algebra_2d.h.

635 {
636 const qreal coeff = std::sqrt(pow2(rc.width()) + pow2(rc.height())) / std::sqrt(2.0);
637 return coeff != 0 ? value / coeff : 0;
638}
float value(const T *src, size_t ch)
T pow2(const T &x)
Definition kis_global.h:166

References pow2(), and value().

◆ absoluteToRelative() [3/3]

QRectF KisAlgebra2D::absoluteToRelative ( const QRectF & rel,
const QRectF & rc )
inline

Scales absolute isotropic value from absolute to relative coordinate system using SVG 1.1 rules (see chapter 7.10)

Definition at line 652 of file kis_algebra_2d.h.

652 {
653 return QRectF(absoluteToRelative(rel.topLeft(), rc), absoluteToRelative(rel.bottomRight(), rc));
654}
QPointF absoluteToRelative(const QPointF &pt, const QRectF &rc)

References absoluteToRelative().

◆ accumulateBounds() [1/3]

template<template< class T > class Container, class Point >
PointTypeTraits< Point >::rect_type KisAlgebra2D::accumulateBounds ( const Container< Point > & points)
inline

Definition at line 280 of file kis_algebra_2d.h.

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}
void accumulateBounds(const Point &pt, Rect *bounds)

References accumulateBounds().

◆ accumulateBounds() [2/3]

template<template< class T > class Container, class Point , class Rect >
void KisAlgebra2D::accumulateBounds ( const Container< Point > & points,
Rect * bounds )
inline

Definition at line 271 of file kis_algebra_2d.h.

272{
273 Q_FOREACH (const Point &pt, points) {
275 }
276}
#define bounds(x, a, b)

References accumulateBounds(), and bounds.

◆ accumulateBounds() [3/3]

template<class Point , class Rect >
void KisAlgebra2D::accumulateBounds ( const Point & pt,
Rect * bounds )
inline

Rect::left() is cheaper than Rect::right(), so check it first

Rect::top() is cheaper than Rect::bottom(), so check it first

Definition at line 227 of file kis_algebra_2d.h.

228{
229 if (bounds->isEmpty()) {
230 Private::resetEmptyRectangle(pt, bounds);
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}

References bounds, and KisAlgebra2D::Private::resetEmptyRectangle().

◆ accumulateBoundsNonEmpty()

template<class Point , class Rect >
void KisAlgebra2D::accumulateBoundsNonEmpty ( const Point & pt,
Rect * bounds )
inline

Definition at line 255 of file kis_algebra_2d.h.

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}

References bounds.

◆ adjustIfOnPolygonBoundary()

void KRITAGLOBAL_EXPORT KisAlgebra2D::adjustIfOnPolygonBoundary ( const QPolygonF & poly,
int polygonDirection,
QPointF * pt )

Definition at line 36 of file kis_algebra_2d.cpp.

37{
38 const int numPoints = poly.size();
39 for (int i = 0; i < numPoints; i++) {
40 int nextI = i + 1;
41 if (nextI >= numPoints) {
42 nextI = 0;
43 }
44
45 const QPointF &p0 = poly[i];
46 const QPointF &p1 = poly[nextI];
47
48 QPointF edge = p1 - p0;
49
50 qreal cross = crossProduct(edge, *pt - p0)
51 / (0.5 * edge.manhattanLength());
52
53 if (cross < 1.0 &&
54 isInRange(pt->x(), p0.x(), p1.x()) &&
55 isInRange(pt->y(), p0.y(), p1.y())) {
56
57 QPointF salt = 1.0e-3 * inwardUnitNormal(edge, polygonDirection);
58
59 QPointF adjustedPoint = *pt + salt;
60
61 // in case the polygon is self-intersecting, polygon direction
62 // might not help
63 if (kisDistanceToLine(adjustedPoint, QLineF(p0, p1)) < 1e-4) {
64 adjustedPoint = *pt - salt;
65
66#ifdef SANITY_CHECKS
67 if (kisDistanceToLine(adjustedPoint, QLineF(p0, p1)) < 1e-4) {
68 dbgKrita << ppVar(*pt);
69 dbgKrita << ppVar(adjustedPoint);
70 dbgKrita << ppVar(QLineF(p0, p1));
72
73 dbgKrita << ppVar(poly.containsPoint(*pt, Qt::OddEvenFill));
74
75 dbgKrita << ppVar(kisDistanceToLine(*pt, QLineF(p0, p1)));
76 dbgKrita << ppVar(kisDistanceToLine(adjustedPoint, QLineF(p0, p1)));
77 }
78
79 *pt = adjustedPoint;
80
81 KIS_ASSERT_RECOVER_NOOP(kisDistanceToLine(*pt, QLineF(p0, p1)) > 1e-4);
82#endif /* SANITY_CHECKS */
83 }
84 }
85 }
86}
QPointF p0
QPointF p1
#define KIS_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:97
#define dbgKrita
Definition kis_debug.h:45
#define ppVar(var)
Definition kis_debug.h:155
qreal kisDistanceToLine(const QPointF &m, const QLineF &line)
Definition kis_global.h:234
const unsigned char salt[256][256]
Definition rand_salt.h:30

References crossProduct(), dbgKrita, inwardUnitNormal(), isInRange(), KIS_ASSERT_RECOVER_NOOP, kisDistanceToLine(), p0, p1, polygonDirection(), ppVar, and salt.

◆ alignForZoom()

QPointF KRITAGLOBAL_EXPORT KisAlgebra2D::alignForZoom ( const QPointF & pt,
qreal zoom )

Definition at line 969 of file kis_algebra_2d.cpp.

970{
971 return QPointF((pt * zoom).toPoint()) / zoom;
972}

◆ angleBetweenVectors()

qreal KRITAGLOBAL_EXPORT KisAlgebra2D::angleBetweenVectors ( const QPointF & v1,
const QPointF & v2 )

Definition at line 110 of file kis_algebra_2d.cpp.

111{
112 qreal a1 = std::atan2(v1.y(), v1.x());
113 qreal a2 = std::atan2(v2.y(), v2.x());
114
115 return a2 - a1;
116}

◆ approximateRectFromPoints() [1/2]

QRect KRITAGLOBAL_EXPORT KisAlgebra2D::approximateRectFromPoints ( const QVector< QPoint > & points)

Definition at line 544 of file kis_algebra_2d.cpp.

545 {
546 return approximateRectFromPointsImpl<QRect, QPoint, true>(points);
547 }

◆ approximateRectFromPoints() [2/2]

QRectF KRITAGLOBAL_EXPORT KisAlgebra2D::approximateRectFromPoints ( const QVector< QPointF > & points)

Definition at line 549 of file kis_algebra_2d.cpp.

550 {
551 return approximateRectFromPointsImpl<QRectF, QPointF, false>(points);
552 }

◆ approximateRectFromPointsImpl()

template<class Rect , class Point , bool alignPixels>
Rect KisAlgebra2D::approximateRectFromPointsImpl ( const QVector< Point > & points)

Definition at line 520 of file kis_algebra_2d.cpp.

521 {
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;
525
526 Q_FOREACH (const Point &pt, points) {
527 accX(pt.x());
528 accY(pt.y());
529 }
530
531 Rect resultRect;
532
533 if (alignPixels) {
534 resultRect.setCoords(std::floor(min(accX)), std::floor(min(accY)),
535 std::ceil(max(accX)), std::ceil(max(accY)));
536 } else {
537 resultRect.setCoords(min(accX), min(accY),
538 max(accX), max(accY));
539 }
540
541 return resultRect;
542 }
T min(T a, T b, T c)
constexpr std::enable_if< sizeof...(values)==0, size_t >::type max()

◆ approximateRectWithPointTransform()

QRect KRITAGLOBAL_EXPORT KisAlgebra2D::approximateRectWithPointTransform ( const QRect & rect,
std::function< QPointF(QPointF)> func )

Definition at line 554 of file kis_algebra_2d.cpp.

555 {
557
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;
561
562 Q_FOREACH (const QPoint &pt, points) {
563 QPointF dstPt = func(pt);
564
565 accX(dstPt.x());
566 accY(dstPt.y());
567 }
568
569 QRect resultRect;
570 resultRect.setCoords(std::floor(min(accX)), std::floor(min(accY)),
571 std::ceil(max(accX)), std::ceil(max(accY)));
572
573 return resultRect;
574 }
QVector< Point > sampleRectWithPoints(const Rect &rect)

References sampleRectWithPoints().

◆ blowRect()

template<class Rect >
Rect KisAlgebra2D::blowRect ( const Rect & rect,
qreal coeff )

Multiply width and height of rect by coeff keeping the center of the rectangle pinned

Definition at line 330 of file kis_algebra_2d.h.

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}

◆ clampPoint()

template<class Point , class Rect >
Point KisAlgebra2D::clampPoint ( Point pt,
const Rect & bounds )
inline

Definition at line 292 of file kis_algebra_2d.h.

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}

References bounds.

◆ copysign()

template<typename T >
T KisAlgebra2D::copysign ( T x,
T y )
inline

Copies the sign of y into x and returns the result

Definition at line 99 of file kis_algebra_2d.h.

99 {
100 T strippedX = qAbs(x);
101 return y >= T(0) ? strippedX : -strippedX;
102}

◆ cropLineToConvexPolygon()

void KRITAGLOBAL_EXPORT KisAlgebra2D::cropLineToConvexPolygon ( QLineF & line,
const QPolygonF polygon,
bool extendFirst,
bool extendSecond )

Definition at line 1299 of file kis_algebra_2d.cpp.

1300{
1301 bool intersects = intersectLineConvexPolygon(line, polygon, extendFirst, extendSecond);
1302 if (!intersects) {
1303 line = QLineF(); // empty line to help with drawing
1304 }
1305}
bool intersectLineConvexPolygon(QLineF &line, const QPolygonF polygon, bool extendFirst, bool extendSecond)

References intersectLineConvexPolygon().

◆ cropLineToRect()

void KRITAGLOBAL_EXPORT KisAlgebra2D::cropLineToRect ( QLineF & line,
const QRect rect,
bool extendFirst,
bool extendSecond )

Crop line to rect; if it doesn't intersect, just return an empty line (QLineF()).

This is using intersectLineRect, but with the difference that it doesn't require the user to check the return value. It's useful for drawing code, since it let the developer not use if before drawing.

If the line intersects the rectangle, it will be modified to represent the intersecting line segment. If the line does not intersect the area, it will return an empty one-point line.

extendFirst and extendSecond parameters allow one to use this function in case of unbounded lines (if both are true), line segments (if both are false) or half-lines/rays (if one is true and another is false). Note that which point is the "first" and which is the "second" is determined by which is the p1() and which is p2() in QLineF.

Parameters
lineline segment
rectarea
extendFirstextend the line to the edge of the rect area even if the first point of the line segment lies inside the rectangle
extendSecondextend the line to the edge of the rect area even if the second point of the line segment lies inside the rectangle

Definition at line 1291 of file kis_algebra_2d.cpp.

1292{
1293 bool intersects = intersectLineRect(line, rect, extendFirst, extendSecond);
1294 if (!intersects) {
1295 line = QLineF(); // empty line to help with drawing
1296 }
1297}
bool intersectLineRect(QLineF &line, const QRect rect, bool extend)

References intersectLineRect().

◆ crossProduct()

template<class T >
PointTypeTraits< T >::value_type KisAlgebra2D::crossProduct ( const T & a,
const T & b )

Definition at line 55 of file kis_algebra_2d.h.

56{
57 return a.x() * b.y() - a.y() * b.x();
58}

◆ cutOffRect()

KRITAGLOBAL_EXPORT QRectF KisAlgebra2D::cutOffRect ( const QRectF & rc,
const KisAlgebra2D::RightHalfPlane & p )

Cuts off a portion of a rect rc defined by a half-plane p

Returns
the bounding rect of the resulting polygon

Definition at line 577 of file kis_algebra_2d.cpp.

578{
579 QVector<QPointF> points;
580
581 const QLineF cutLine = p.getLine();
582
583 points << rc.topLeft();
584 points << rc.topRight();
585 points << rc.bottomRight();
586 points << rc.bottomLeft();
587
588 QPointF p1 = points[3];
589 bool p1Valid = p.pos(p1) >= 0;
590
591 QVector<QPointF> resultPoints;
592
593 for (int i = 0; i < 4; i++) {
594 const QPointF p2 = points[i];
595 const bool p2Valid = p.pos(p2) >= 0;
596
597 if (p1Valid != p2Valid) {
598 QPointF intersection;
599 cutLine.intersects(QLineF(p1, p2), &intersection);
600 resultPoints << intersection;
601 }
602
603 if (p2Valid) {
604 resultPoints << p2;
605 }
606
607 p1 = p2;
608 p1Valid = p2Valid;
609 }
610
611 return approximateRectFromPoints(resultPoints);
612}
const Params2D p
QPointF p2
QRect approximateRectFromPoints(const QVector< QPoint > &points)

References approximateRectFromPoints(), p, p1, and p2.

◆ directionBetweenPoints()

qreal KRITAGLOBAL_EXPORT KisAlgebra2D::directionBetweenPoints ( const QPointF & p1,
const QPointF & p2,
qreal defaultAngle )

Computes an angle indicating the direction from p1 to p2. If p1 and p2 are too close together to compute an angle, defaultAngle is returned.

Definition at line 118 of file kis_algebra_2d.cpp.

119{
120 if (fuzzyPointCompare(p1, p2)) {
121 return defaultAngle;
122 }
123
124 const QVector2D diff(p2 - p1);
125 return std::atan2(diff.y(), diff.x());
126}
bool fuzzyPointCompare(const QPointF &p1, const QPointF &p2)

References fuzzyPointCompare(), p1, and p2.

◆ divideFloor()

template<class T >
std::enable_if< std::is_integral< T >::value, T >::type KisAlgebra2D::divideFloor ( T a,
T b )

Definition at line 106 of file kis_algebra_2d.h.

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}

◆ dotProduct()

template<class T >
PointTypeTraits< T >::value_type KisAlgebra2D::dotProduct ( const T & a,
const T & b )

Definition at line 49 of file kis_algebra_2d.h.

50{
51 return a.x() * b.x() + a.y() * b.y();
52}

◆ ensureInRect() [1/2]

QPoint KRITAGLOBAL_EXPORT KisAlgebra2D::ensureInRect ( QPoint pt,
const QRect & bounds )

Definition at line 162 of file kis_algebra_2d.cpp.

163{
164 return ensureInRectImpl(pt, bounds);
165}
Point ensureInRectImpl(Point pt, const Rect &bounds)

References bounds, and ensureInRectImpl().

◆ ensureInRect() [2/2]

QPointF KRITAGLOBAL_EXPORT KisAlgebra2D::ensureInRect ( QPointF pt,
const QRectF & bounds )

Definition at line 167 of file kis_algebra_2d.cpp.

168{
169 return ensureInRectImpl(pt, bounds);
170}

References bounds, and ensureInRectImpl().

◆ ensureInRectImpl()

template<class Point , class Rect >
Point KisAlgebra2D::ensureInRectImpl ( Point pt,
const Rect & bounds )
inline

Definition at line 145 of file kis_algebra_2d.cpp.

146{
147 if (pt.x() > bounds.right()) {
148 pt.rx() = bounds.right();
149 } else if (pt.x() < bounds.left()) {
150 pt.rx() = bounds.left();
151 }
152
153 if (pt.y() > bounds.bottom()) {
154 pt.ry() = bounds.bottom();
155 } else if (pt.y() < bounds.top()) {
156 pt.ry() = bounds.top();
157 }
158
159 return pt;
160}

References bounds.

◆ ensureRectNotSmaller()

template<class Rect >
Rect KisAlgebra2D::ensureRectNotSmaller ( Rect rc,
const decltype(Rect().size()) & size )

Definition at line 344 of file kis_algebra_2d.h.

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}

◆ ensureSizeNotSmaller()

template<class Size >
Size KisAlgebra2D::ensureSizeNotSmaller ( const Size & size,
const Size & bounds )

Definition at line 362 of file kis_algebra_2d.h.

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}
T copysign(T x, T y)

References bounds, and copysign().

◆ findMinimumGoldenSection()

qreal KisAlgebra2D::findMinimumGoldenSection ( std::function< qreal(qreal)> f,
qreal xA,
qreal xB,
qreal eps,
int maxIter = 100 )

Definition at line 1308 of file kis_algebra_2d.cpp.

1309{
1310 // requirements:
1311 // only one local minimum between xA and xB
1312
1313 int i = 0;
1314 const double phi = 0.618033988749894; // 1/(golden ratio)
1315 qreal a = xA;
1316 qreal b = xB;
1317 qreal c = b - (b - a)*phi;
1318 qreal d = a + (b - a)*phi;
1319
1320 while (qAbs(b - a) > eps) {
1321 if (f(c) < f(d)) {
1322 b = d;
1323 } else {
1324 a = c;
1325 }
1326
1327 // Wikipedia says to recompute both c and d here to avoid loss of precision which may lead to incorrect results or infinite loop
1328 c = b - (b - a) * phi;
1329 d = a + (b - a) * phi;
1330
1331 i++;
1332 if (i > maxIter) {
1333 break;
1334 }
1335
1336 }
1337
1338 return (b + a)/2;
1339}
const qreal eps

References eps.

◆ findMinimumTernarySection()

qreal KisAlgebra2D::findMinimumTernarySection ( std::function< qreal(qreal)> f,
qreal xA,
qreal xB,
qreal eps,
int maxIter = 100 )

Definition at line 1341 of file kis_algebra_2d.cpp.

1342{
1343 // requirements:
1344 // only one local minimum between xA and xB
1345
1346 int i = 0;
1347 qreal l = qMin(xA, xB);
1348 qreal r = qMax(xA, xB);
1349
1350
1351 qreal m1 = l + (r - l)/3;
1352 qreal m2 = r - (r - l)/3;
1353
1354 while ((r - l) > eps) {
1355 qreal f1 = f(m1);
1356 qreal f2 = f(m2);
1357
1358 if (f1 > f2) {
1359 l = m1;
1360 } else {
1361 r = m2;
1362 }
1363
1364 // In Golden Section, Wikipedia says to recompute both c and d here to avoid loss of precision which may lead to incorrect results or infinite loop
1365 // so it's probably a good idea to do it here too
1366 m1 = l + (r - l)/3;
1367 m2 = r - (r - l)/3;
1368
1369 i++;
1370
1371 if (i > maxIter) {
1372 break;
1373 }
1374 }
1375
1376 return (l + r)/2;
1377}

References eps.

◆ findTrianglePoint()

QVector< QPointF > KRITAGLOBAL_EXPORT KisAlgebra2D::findTrianglePoint ( const QPointF & p1,
const QPointF & p2,
qreal a,
qreal b )

Find possible positions for point p3, such that points \p1, \p2 and p3 form a triangle, such that the distance between p1 ad p3 is a and the distance between p2 and p3 is b. There might be 0, 1 or 2 such positions.

Definition at line 1016 of file kis_algebra_2d.cpp.

1017{
1018 using KisAlgebra2D::norm;
1020
1021 QVector<QPointF> result;
1022
1023 const QPointF p = p2 - p1;
1024
1025 const qreal pSq = dotProduct(p, p);
1026
1027 const qreal T = 0.5 * (-pow2(b) + pow2(a) + pSq);
1028
1029 if (p.isNull()) return result;
1030
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;
1035
1036 const qreal D4 = pow2(B2) - A * C;
1037
1038 if (D4 > 0 || qFuzzyIsNull(D4)) {
1039 if (qFuzzyIsNull(D4)) {
1040 const qreal y = -B2 / A;
1041 const qreal x = (T - y * p.y()) / p.x();
1042 result << p1 + QPointF(x, y);
1043 } else {
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);
1047
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);
1051 }
1052 }
1053 } else {
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;
1057
1058 const qreal D4 = pow2(B2) - A * C;
1059
1060 if (D4 > 0 || qFuzzyIsNull(D4)) {
1061 if (qFuzzyIsNull(D4)) {
1062 const qreal x = -B2 / A;
1063 const qreal y = (T - x * p.x()) / p.y();
1064 result << p1 + QPointF(x, y);
1065 } else {
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);
1069
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);
1073 }
1074 }
1075 }
1076
1077 return result;
1078}
static qreal B2(qreal u)
#define C(i, j)
static bool qFuzzyIsNull(half h)
qreal norm(const T &a)
PointTypeTraits< T >::value_type dotProduct(const T &a, const T &b)

References A, B2(), C, dotProduct(), norm(), p, p1, p2, pow2(), and qFuzzyIsNull().

◆ findTrianglePointNearest()

boost::optional< QPointF > KRITAGLOBAL_EXPORT KisAlgebra2D::findTrianglePointNearest ( const QPointF & p1,
const QPointF & p2,
qreal a,
qreal b,
const QPointF & nearest )

Find a point p3 that forms a triangle with \p1 and \p2 and is the nearest possible point to nearest

See also
findTrianglePoint

Definition at line 1080 of file kis_algebra_2d.cpp.

1081{
1082 const QVector<QPointF> points = findTrianglePoint(p1, p2, a, b);
1083
1084 boost::optional<QPointF> result;
1085
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();
1090 }
1091
1092 return result;
1093}
qreal kisDistance(const QPointF &pt1, const QPointF &pt2)
Definition kis_global.h:190
QVector< QPointF > findTrianglePoint(const QPointF &p1, const QPointF &p2, qreal a, qreal b)

References findTrianglePoint(), kisDistance(), p1, and p2.

◆ fromQTransformStraight()

Eigen::Matrix3d KisAlgebra2D::fromQTransformStraight ( const QTransform & t)
inline

Definition at line 775 of file kis_algebra_2d.cpp.

776{
777 Eigen::Matrix3d m;
778
779 m << t.m11() , t.m12() , t.m13()
780 ,t.m21() , t.m22() , t.m23()
781 ,t.m31() , t.m32() , t.m33();
782
783 return m;
784}

◆ fuzzyCompareRects()

template<class Rect , typename Difference = decltype(Rect::width())>
bool KisAlgebra2D::fuzzyCompareRects ( const Rect & r1,
const Rect & r2,
Difference tolerance )

Compare two rectangles with tolerance tolerance. The tolerance means that the coordinates of top left and bottom right corners should not differ more than tolerance pixels.

Definition at line 697 of file kis_algebra_2d.h.

697 {
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}
QPointF r2
QPointF r1
Point abs(const Point &pt)

References abs(), r1, and r2.

◆ fuzzyMatrixCompare()

bool KRITAGLOBAL_EXPORT KisAlgebra2D::fuzzyMatrixCompare ( const QTransform & t1,
const QTransform & t2,
qreal delta )

Compare the matrices with tolerance delta

Definition at line 743 of file kis_algebra_2d.cpp.

743 {
744 return
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;
754}

◆ fuzzyPointCompare() [1/3]

template<template< typename > class Cont, class Point >
bool KisAlgebra2D::fuzzyPointCompare ( const Cont< Point > & c1,
const Cont< Point > & c2,
qreal delta )

Returns true if points in two containers are equal with specified tolerance

Definition at line 676 of file kis_algebra_2d.h.

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}

References eps.

◆ fuzzyPointCompare() [2/3]

bool KRITAGLOBAL_EXPORT KisAlgebra2D::fuzzyPointCompare ( const QPointF & p1,
const QPointF & p2 )

Returns true if the two points are equal within some tolerance, where the tolerance is determined by Qt's built-in fuzzy comparison functions.

Definition at line 756 of file kis_algebra_2d.cpp.

757{
758 return qFuzzyCompare(p1.x(), p2.x()) && qFuzzyCompare(p1.y(), p2.y());
759}
static bool qFuzzyCompare(half p1, half p2)

References p1, p2, and qFuzzyCompare().

◆ fuzzyPointCompare() [3/3]

bool KRITAGLOBAL_EXPORT KisAlgebra2D::fuzzyPointCompare ( const QPointF & p1,
const QPointF & p2,
qreal delta )

Returns true if the two points are equal within the specified tolerance

Definition at line 762 of file kis_algebra_2d.cpp.

763{
764 return qAbs(p1.x() - p2.x()) < delta && qAbs(p1.y() - p2.y()) < delta;
765}

References p1, and p2.

◆ intersectLineConvexPolygon()

bool KRITAGLOBAL_EXPORT KisAlgebra2D::intersectLineConvexPolygon ( QLineF & line,
const QPolygonF polygon,
bool extendFirst,
bool extendSecond )

Definition at line 250 of file kis_algebra_2d.cpp.

251{
252 qreal epsilon = 1e-07;
253
254 if (polygon.size() == 0) {
255 return false;
256 }
257
258 // trivial case: no extends, all points inside the polygon
259 if (!extendFirst && !extendSecond && polygon.containsPoint(line.p1(), Qt::WindingFill) && polygon.containsPoint(line.p2(), Qt::WindingFill)) {
260 return true;
261 }
262
263 // Cyrus-Beck algorithm: https://en.wikipedia.org/wiki/Cyrus%E2%80%93Beck_algorithm
264
265 // parametric equation for the line:
266 // p(t) = t*P1 + (1-t)*P2
267
268 // we can't use infinity here, because the points would all end up as (+/- inf, +/- inf)
269 // which would be useless if we have a very specific direction
270 // hence we use just "a big number"
271 float aBigNumber = 100000; // that will keep t*Px still on the line // this is LIMITATION of the algorithm
272 float tmin = extendFirst ? -aBigNumber : 0; // line.p1() - first point, or infinity
273 float tmax = extendSecond ? aBigNumber : 1; // line.p2() - second point, or infinity
274
275
276
277 QList<QLineF> clippingLines;
278 QList<QPointF> normals;
279
280 bool clockwise = false;
281 {
282 // only temporary values to check whether the polygon is clockwise or counterclockwise
283 QPointF vec1 = polygon[1] - polygon[0];
284 QPointF vec2 = polygon[2] - polygon[0];
285
286 QLineF line1(QPointF(0, 0), vec1);
287 QLineF line2(QPointF(0, 0), vec2);
288
289 qreal angle = line1.angleTo(line2); // range: <0, 360) // <0, 180) means counter-clockwise
290 if (angle >= 180) {
291 clockwise = true;
292 }
293 }
294
295
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();
300
301 if (!clockwise) {
302 normals.append(QPointF(ydiff, -xdiff));
303 } else {
304 normals.append(QPointF(-ydiff, xdiff));
305 }
306
307 }
308
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();
314
315 if (!clockwise) {
316 normals.append(QPointF(ydiff, -xdiff));
317 } else {
318 normals.append(QPointF(-ydiff, xdiff));
319 }
320
321 }
322
323 QPointF lineVec = line.p2() - line.p1();
324 // ax + by + c = 0
325 // c = -ax - by
326// qreal cFromStandardEquation = -lineVec.x()*line.p1().x() - lineVec.y()*line.p1().y();
327
328
329 QPointF p1 = line.p1();
330 QPointF p2 = line.p2();
331
332 qreal pA, pB, pC; // standard equation for the line: ax + by + c = 0
333 if (qAbs(lineVec.x()) < epsilon) {
334 // x1 ~= x2, line looks like: x = -pC
335 pB = 0;
336 pA = 1;
337 pC = -p1.x();
338 } else {
339 pB = 1; // let b = 1 to simplify
340 qreal tmp = (p1.y() - p2.y())/(p1.x() - p2.x());
341 pA = -tmp;
342 pC = tmp * p1.x() - p1.y();
343 }
344
345
346 int pEFound = 0;
347
348
349 for (int i = 0; i < clippingLines.size(); i++) {
350
351 // is the clipping line parallel to the line?
352 QPointF clipVec = clippingLines[i].p2() - clippingLines[i].p1();
353
354 if (qFuzzyCompare(clipVec.x()*lineVec.y(), clipVec.y()*lineVec.x())) {
355
356 // vectors are parallel
357 // let's check if one of the clipping points is on the line (extended) to see if it's the same line; if not, proceed normally
358
359 qreal distanceBetweenLines = qAbs(pA*clippingLines[i].p1().x() + pB*clippingLines[i].p1().y() + pC)
360 /(sqrt(pA*pA + pB*pB));
361
362
363 if (qAbs(distanceBetweenLines) < epsilon) {
364 // they are the same line
365
366 qreal t1;
367 qreal t2;
368
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());
372 } else {
373 t1 = (clippingLines[i].p1().y() - p1.y())/(p2.y() - p1.y());
374 t2 = (clippingLines[i].p2().y() - p1.y())/(p2.y() - p1.y());
375 }
376
377 qreal tmin1 = qMin(t1, t2);
378 qreal tmax2 = qMax(t1, t2);
379
380
381
382 if (tmin < tmin1) {
383 tmin = tmin1;
384 }
385 if (tmax > tmax2) {
386 tmax = tmax2;
387 }
388 continue;
389 }
390 else {
391 // if clipping line points are P1 and P2, and some other point is P(t) (given by parametric equation),
392 // and N is the normal vector
393 // and one of the points of the line we're intersecting is K,
394 // then we have a following equation:
395 // K = P(t) + a * N
396 // where t and a are unknown.
397 // after simplifying we get:
398 // t*(p2 - p1) + a*(n) = k - p1
399 // and since we have two axis, we get a linear system of two equations
400 // A * [t; a] = B
401
402 Eigen::Matrix2f A;
403 Eigen::Vector2f b;
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();
408
409 Eigen::Vector2f ta = A.colPivHouseholderQr().solve(b);
410
411 qreal tt = ta(1);
412 if (tt < 0) {
413 return false;
414 }
415 }
416
417 }
418
419
420 boost::optional<QPointF> pEOptional = intersectLines(clippingLines[i], line); // bounded, unbounded
421
422
423 if (pEOptional) {
424 pEFound++;
425
426 QPointF pE = pEOptional.value();
427 QPointF n = normals[i];
428
429 QPointF A = line.p2() - line.p1();
430 QPointF B = line.p1() - pE;
431
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;
435
436// if (pE.x() != p2.x()) {
437// qreal maybet = (pE.x() - p1.x())/(p2.x() - p1.x());
438// }
439
440 qreal tminvalue = tmin * under + over;
441 qreal tmaxvalue = tmax * under + over;
442
443 if (tminvalue > 0 && tmaxvalue > 0) {
444 // both outside of the edge
445 return false;
446 }
447 if (tminvalue <= 0 && tmaxvalue <= 0) {
448 // noop, both inside
449 }
450 if (tminvalue*tmaxvalue < 0) {
451
452 // on two different sides
453 if (tminvalue > 0) {
454 // tmin outside, tmax inside
455 if (t > tmin) {
456 tmin = t;
457 }
458 } else {
459 if (t < tmax) {
460 tmax = t;
461 }
462 }
463 }
464
465
466
467 if (tmax < tmin) {
468 return false;
469 }
470 }
471 else {
472 }
473
474 }
475
476 if (pEFound == 0) {
477 return false;
478 }
479
480 QLineF response = QLineF(tmin*line.p2() + (1-tmin)*line.p1(), tmax*line.p2() + (1-tmax)*line.p1());
481 line = response;
482 return true;
483}
boost::optional< QPointF > intersectLines(const QLineF &boundedLine, const QLineF &unboundedLine)

References A, B, intersectLines(), p1, p2, and qFuzzyCompare().

◆ intersectLineRect() [1/2]

bool KRITAGLOBAL_EXPORT KisAlgebra2D::intersectLineRect ( QLineF & line,
const QRect rect,
bool extend )

Attempt to intersect a line to the area of the a rectangle.

If the line intersects the rectangle, it will be modified to represent the intersecting line segment and true is returned. If the line does not intersect the area, it remains unmodified and false will be returned. If the line is fully inside the rectangle, it's considered "intersecting" so true will be returned.

Parameters
lineline segment
rectarea
extendextend the line to the edges of the rect area even if the line segment fits inside the rectangle (so, consider the line to be a line defined by those two points, not a line segment)
Returns
true if successful

Definition at line 172 of file kis_algebra_2d.cpp.

173{
174 return intersectLineRect(line, rect, extend, extend);
175}

References intersectLineRect().

◆ intersectLineRect() [2/2]

bool KRITAGLOBAL_EXPORT KisAlgebra2D::intersectLineRect ( QLineF & line,
const QRect rect,
bool extendFirst,
bool extendSecond )

Attempt to intersect a line to the area of the a rectangle.

If the line intersects the rectangle, it will be modified to represent the intersecting line segment and true is returned. If the line does not intersect the area, it remains unmodified and false will be returned. If the line is fully inside the rectangle, it's considered "intersecting" so true will be returned.

extendFirst and extendSecond parameters allow one to use this function in case of unbounded lines (if both are true), line segments (if both are false) or half-lines/rays (if one is true and another is false). Note that which point is the "first" and which is the "second" is determined by which is the p1() and which is p2() in QLineF.

Parameters
lineline segment
rectarea
extendFirstextend the line to the edge of the rect area even if the first point of the line segment lies inside the rectangle
extendSecondextend the line to the edge of the rect area even if the second point of the line segment lies inside the rectangle
Returns
true if successful

Definition at line 177 of file kis_algebra_2d.cpp.

178{
179 // using Liang-Barsky algorithm
180 // using parametric equation for a line:
181 // X = x1 + t(x2-x1) = x1 + t*p2
182 // Y = y1 + t(y2-y1) = y1 + t*p4
183 // note that we have a line *segment* here, not a line
184 // t1 = 0, t2 = 1, no matter what points we got
185
186 double p1 = -(line.x2() - line.x1());
187 double p2 = -p1;
188 double p3 = -(line.y2() - line.y1());
189 double p4 = -p3;
190
192 QVector<double> q = QVector<double>({line.x1() - rect.x(), rect.x() + rect.width() - line.x1(), line.y1() - rect.y(), rect.y() + rect.height() - line.y1()});
193
194 float tmin = extendFirst ? -std::numeric_limits<float>::infinity() : 0; // line.p1() - first point, or infinity
195 float tmax = extendSecond ? std::numeric_limits<float>::infinity() : 1; // line.p2() - second point, or infinity
196
197 for (int i = 0; i < p.length(); i++) {
198 // now clipping
199 if (p[i] == 0 && q[i] < 0) {
200 // line is parallel to the boundary and outside of it
201 return false;
202 } else if (p[i] < 0) {
203 // line entry point (should be tmin)
204 double t = q[i]/p[i];
205 if (t > tmax) {
206 if (extendSecond) {
207 tmax = t;
208 } else {
209 return false;
210 }
211 }
212 if (t > tmin) {
213 tmin = t;
214 }
215
216
217 } else if (p[i] > 0) {
218 // line leaving point (should be tmax)
219 double t = q[i]/p[i];
220 if (t < tmin) {
221 if (extendFirst) {
222 tmin = t;
223 } else {
224 return false;
225 }
226 }
227 if (t < tmax) {
228 tmax = t;
229 }
230 }
231 }
232
233 QPointF pt1 = line.p1();
234 QPointF pt2 = line.p2();
235
236 if (extendFirst || tmin > 0) {
237 pt1 = QPointF(line.x1() + tmin*(line.x2() - line.x1()), line.y1() + tmin*(line.y2() - line.y1()));
238 }
239 if (extendSecond || tmax < 1) {
240 pt2 = QPointF(line.x1() + tmax*(line.x2() - line.x1()), line.y1() + tmax*(line.y2() - line.y1()));
241 }
242
243 line.setP1(pt1);
244 line.setP2(pt2);
245
246 return true;
247
248}
QPointF p3

References p, p1, p2, and p3.

◆ intersectLines() [1/2]

KRITAGLOBAL_EXPORT boost::optional< QPointF > KisAlgebra2D::intersectLines ( const QLineF & boundedLine,
const QLineF & unboundedLine )

Find intersection of a bounded line boundedLine with unbounded line unboundedLine (if an intersection exists)

Definition at line 974 of file kis_algebra_2d.cpp.

975{
976 const QPointF B1 = unboundedLine.p1();
977 const QPointF A1 = unboundedLine.p2() - unboundedLine.p1();
978
979 const QPointF B2 = boundedLine.p1();
980 const QPointF A2 = boundedLine.p2() - boundedLine.p1();
981
982 Eigen::Matrix<float, 2, 2> A;
983 A << A1.x(), -A2.x(),
984 A1.y(), -A2.y();
985
986 Eigen::Matrix<float, 2, 1> B;
987 B << B2.x() - B1.x(),
988 B2.y() - B1.y();
989
990 if (qFuzzyIsNull(A.determinant())) {
991 return boost::none;
992 }
993
994 Eigen::Matrix<float, 2, 1> T;
995
996 T = A.inverse() * B;
997
998 const qreal t2 = T(1,0);
999 double epsilon = 1e-06; // to avoid precision issues
1000
1001 if (t2 < 0.0 || t2 > 1.0) {
1002 if (qAbs(t2) > epsilon && qAbs(t2 - 1.0) > epsilon) {
1003 return boost::none;
1004 }
1005 }
1006
1007 return t2 * A2 + B2;
1008}
static qreal B1(qreal u)

References A, B, B1(), B2(), and qFuzzyIsNull().

◆ intersectLines() [2/2]

KRITAGLOBAL_EXPORT boost::optional< QPointF > KisAlgebra2D::intersectLines ( const QPointF & p1,
const QPointF & p2,
const QPointF & q1,
const QPointF & q2 )

Find intersection of a bounded line p1, p2 with unbounded line q1, q2 (if an intersection exists)

Definition at line 1010 of file kis_algebra_2d.cpp.

1012{
1013 return intersectLines(QLineF(p1, p2), QLineF(q1, q2));
1014}
QPointF q1
QPointF q2

References intersectLines(), p1, p2, q1, and q2.

◆ intersectTwoCircles()

KRITAGLOBAL_EXPORT QVector< QPointF > KisAlgebra2D::intersectTwoCircles ( const QPointF & c1,
qreal r1,
const QPointF & c2,
qreal r2 )

Finds the points of intersections between two circles

Returns
the found circles, the result can have 0, 1 or 2 points

Definition at line 637 of file kis_algebra_2d.cpp.

639{
640 QVector<QPointF> points;
641
642 const QPointF diff = (center2 - center1);
643 const QPointF c1;
644 const QPointF c2 = diff;
645
646 const qreal centerDistance = norm(diff);
647
648 if (centerDistance > r1 + r2) return points;
649 if (centerDistance < qAbs(r1 - r2)) return points;
650
651 if (centerDistance < qAbs(r1 - r2) + 0.001) {
652 dbgKrita << "Skipping intersection" << ppVar(center1) << ppVar(center2) << ppVar(r1) << ppVar(r2) << ppVar(centerDistance) << ppVar(qAbs(r1-r2));
653 return points;
654 }
655
656 const qreal x_kp1 = diff.x();
657 const qreal y_kp1 = diff.y();
658
659 const qreal F2 =
660 0.5 * (pow2(x_kp1) +
661 pow2(y_kp1) + pow2(r1) - pow2(r2));
662
663 const qreal eps = 1e-6;
664
665 if (qAbs(diff.y()) < eps) {
666 qreal x = F2 / diff.x();
667 qreal y1, y2;
669 1, 0,
670 pow2(x) - pow2(r2),
671 &y1, &y2);
672
673 KIS_SAFE_ASSERT_RECOVER(result > 0) { return points; }
674
675 if (result == 1) {
676 points << QPointF(x, y1);
677 } else if (result == 2) {
679
680 QPointF p1(x, y1);
681 QPointF p2(x, y2);
682
683 if (p.pos(p1) >= 0) {
684 points << p1;
685 points << p2;
686 } else {
687 points << p2;
688 points << p1;
689 }
690 }
691 } else {
692 const qreal A = diff.x() / diff.y();
693 const qreal C = F2 / diff.y();
694
695 qreal x1, x2;
697 1 + pow2(A), -2 * A * C,
698 pow2(C) - pow2(r1),
699 &x1, &x2);
700
701 KIS_SAFE_ASSERT_RECOVER(result > 0) { return points; }
702
703 if (result == 1) {
704 points << QPointF(x1, C - x1 * A);
705 } else if (result == 2) {
707
708 QPointF p1(x1, C - x1 * A);
709 QPointF p2(x2, C - x2 * A);
710
711 if (p.pos(p1) >= 0) {
712 points << p1;
713 points << p2;
714 } else {
715 points << p2;
716 points << p1;
717 }
718 }
719 }
720
721 for (int i = 0; i < points.size(); i++) {
722 points[i] = center1 + points[i];
723 }
724
725 return points;
726}
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
int quadraticEquation(qreal a, qreal b, qreal c, qreal *x1, qreal *x2)

References A, C, dbgKrita, eps, KIS_SAFE_ASSERT_RECOVER, norm(), p, p1, p2, pow2(), ppVar, quadraticEquation(), r1, and r2.

◆ inwardUnitNormal()

template<class T >
T KisAlgebra2D::inwardUnitNormal ( const T & a,
int polygonDirection )

Definition at line 140 of file kis_algebra_2d.h.

141{
143}
T leftUnitNormal(const T &a)
int polygonDirection(const QVector< T > &polygon)

References leftUnitNormal(), and polygonDirection().

◆ isInRange()

template<typename T >
bool KisAlgebra2D::isInRange ( T x,
T a,
T b )

Definition at line 191 of file kis_algebra_2d.h.

191 {
192 T length = qAbs(a - b);
193 return qAbs(x - a) <= length && qAbs(x - b) <= length;
194}
qreal length(const QPointF &vec)
Definition Ellipse.cc:82

References length().

◆ lazyRound()

template<typename R >
R KisAlgebra2D::lazyRound ( qreal value)

Helper function to convert a qreal to int lazily. If the passed type is an integer, then the value is rounded. Otherwise it is just passed forward.

◆ lazyRound< int >()

template<>
int KisAlgebra2D::lazyRound< int > ( qreal value)
inline

Definition at line 154 of file kis_algebra_2d.h.

155{
156 return qRound(value);
157}

References value().

◆ lazyRound< qreal >()

template<>
qreal KisAlgebra2D::lazyRound< qreal > ( qreal value)
inline

Definition at line 160 of file kis_algebra_2d.h.

161{
162 return value;
163}

References value().

◆ leftUnitNormal()

template<class T >
T KisAlgebra2D::leftUnitNormal ( const T & a)

Definition at line 124 of file kis_algebra_2d.h.

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}
PointTypeTraits< T >::value_type crossProduct(const T &a, const T &b)

References crossProduct(), length(), and norm().

◆ lerp()

template<typename Point >
Point KisAlgebra2D::lerp ( const Point & pt1,
const Point & pt2,
qreal t )

Definition at line 74 of file kis_algebra_2d.h.

75{
76 return pt1 + (pt2 - pt1) * t;
77}

◆ linearReshapeFunc()

template<typename T >
T KisAlgebra2D::linearReshapeFunc ( T x,
T x0,
T x1,
T y0,
T y1 )
inline

Linearly reshape function x so that in range [x0, x1] it would cross points (x0, y0) and (x1, y1).

Definition at line 782 of file kis_algebra_2d.h.

783{
784 return y0 + (y1 - y0) * (x - x0) / (x1 - x0);
785}

◆ mapToRect()

KRITAGLOBAL_EXPORT QTransform KisAlgebra2D::mapToRect ( const QRectF & rect)

Definition at line 728 of file kis_algebra_2d.cpp.

729{
730 return
731 QTransform(rect.width(), 0, 0, rect.height(),
732 rect.x(), rect.y());
733}

◆ mapToRectInverse()

KRITAGLOBAL_EXPORT QTransform KisAlgebra2D::mapToRectInverse ( const QRectF & rect)

Definition at line 735 of file kis_algebra_2d.cpp.

736{
737 return
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);
741}

◆ maxDimension()

template<class Size >
auto KisAlgebra2D::maxDimension ( Size size) -> decltype(size.width())

Definition at line 314 of file kis_algebra_2d.h.

314 {
315 return qMax(size.width(), size.height());
316}

◆ minDimension()

template<class Size >
auto KisAlgebra2D::minDimension ( Size size) -> decltype(size.width())

Definition at line 319 of file kis_algebra_2d.h.

319 {
320 return qMin(size.width(), size.height());
321}

◆ moveElasticPoint() [1/2]

QPointF KRITAGLOBAL_EXPORT KisAlgebra2D::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

Parameters
ptpoint in question, tied to points base, wingA and wingB using springs
baseinitial position of the dragged point
newBasefinal position of the dragged point
wingAfirst anchor point
wingBsecond anchor point
Returns
the new position of pt

The function requires (newBase - base) be much smaller than any of the distances between other points. If larger distances are necessary, then use integration.

Definition at line 1095 of file kis_algebra_2d.cpp.

1096{
1097 using KisAlgebra2D::norm;
1100
1101 const QPointF vecL = base - pt;
1102 const QPointF vecLa = wingA - pt;
1103 const QPointF vecLb = wingB - pt;
1104
1105 const qreal L = norm(vecL);
1106 const qreal La = norm(vecLa);
1107 const qreal Lb = norm(vecLb);
1108
1109 const qreal sinMuA = crossProduct(vecLa, vecL) / (La * L);
1110 const qreal sinMuB = crossProduct(vecL, vecLb) / (Lb * L);
1111
1112 const qreal cosMuA = dotProduct(vecLa, vecL) / (La * L);
1113 const qreal cosMuB = dotProduct(vecLb, vecL) / (Lb * L);
1114
1115 const qreal dL = dotProduct(newBase - base, -vecL) / L;
1116
1117
1118 const qreal divB = (cosMuB + La / Lb * sinMuB * cosMuA / sinMuA) / L +
1119 (cosMuB + sinMuB * cosMuA / sinMuA) / Lb;
1120 const qreal dLb = dL / ( L * divB);
1121
1122 const qreal divA = (cosMuA + Lb / La * sinMuA * cosMuB / sinMuB) / L +
1123 (cosMuA + sinMuA * cosMuB / sinMuB) / La;
1124 const qreal dLa = dL / ( L * divA);
1125
1126 boost::optional<QPointF> result =
1127 KisAlgebra2D::findTrianglePointNearest(wingA, wingB, La + dLa, Lb + dLb, pt);
1128
1129 const QPointF resultPoint = result ? *result : pt;
1130
1131 return resultPoint;
1132}
boost::optional< QPointF > findTrianglePointNearest(const QPointF &p1, const QPointF &p2, qreal a, qreal b, const QPointF &nearest)

References crossProduct(), dotProduct(), findTrianglePointNearest(), and norm().

◆ moveElasticPoint() [2/2]

QPointF KRITAGLOBAL_EXPORT KisAlgebra2D::moveElasticPoint ( const QPointF & pt,
const QPointF & base,
const QPointF & newBase,
const QVector< QPointF > & anchorPoints )

moveElasticPoint moves point pt based on the model of elasticity

Parameters
ptpoint in question, tied to points base, anchorPoints using springs
baseinitial position of the dragged point
newBasefinal position of the dragged point
anchorPointsanchor points
Returns
the new position of pt

The function expects (newBase - base) be much smaller than any of the distances between other points. If larger distances are necessary, then use integration.

Definition at line 1201 of file kis_algebra_2d.cpp.

1204{
1205 const QPointF offset = newBase - base;
1206
1207 QPointF newResultPoint = pt + offset;
1208
1209#ifdef HAVE_GSL
1210
1211 ElasticMotionData data;
1212 data.newBasePos = newBase;
1213 data.oldBasePos = base;
1214 data.anchorPoints = anchorPoints;
1215 data.oldResultPoint = pt;
1216
1217 const gsl_multimin_fminimizer_type *T =
1218 gsl_multimin_fminimizer_nmsimplex2;
1219 gsl_multimin_fminimizer *s = 0;
1220 gsl_vector *ss, *x;
1221 gsl_multimin_function minex_func;
1222
1223 size_t iter = 0;
1224 int status;
1225 double size;
1226
1227 /* Starting point */
1228 x = gsl_vector_alloc (2);
1229 gsl_vector_set (x, 0, newResultPoint.x());
1230 gsl_vector_set (x, 1, newResultPoint.y());
1231
1232 /* Set initial step sizes to 0.1 */
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());
1236
1237 /* Initialize method and iterate */
1238 minex_func.n = 2;
1239 minex_func.f = elasticMotionError;
1240 minex_func.params = (void*)&data;
1241
1242 s = gsl_multimin_fminimizer_alloc (T, 2);
1243 gsl_multimin_fminimizer_set (s, &minex_func, x, ss);
1244
1245 do
1246 {
1247 iter++;
1248 status = gsl_multimin_fminimizer_iterate(s);
1249
1250 if (status)
1251 break;
1252
1253 size = gsl_multimin_fminimizer_size (s);
1254 status = gsl_multimin_test_size (size, 1e-6);
1255
1261 if (status == GSL_SUCCESS && elasticMotionError(s->x, &data) > 0.5) {
1262 status = GSL_CONTINUE;
1263 }
1264
1265 if (status == GSL_SUCCESS)
1266 {
1267// qDebug() << "*******Converged to minimum";
1268// qDebug() << gsl_vector_get (s->x, 0)
1269// << gsl_vector_get (s->x, 1)
1270// << "|" << s->fval << size;
1271// qDebug() << ppVar(iter);
1272
1273 newResultPoint.rx() = gsl_vector_get (s->x, 0);
1274 newResultPoint.ry() = gsl_vector_get (s->x, 1);
1275 }
1276 }
1277 while (status == GSL_CONTINUE && iter < 10000);
1278
1279 if (status != GSL_SUCCESS) {
1280 ENTER_FUNCTION() << "failed to find point" << ppVar(pt) << ppVar(base) << ppVar(newBase);
1281 }
1282
1283 gsl_vector_free(x);
1284 gsl_vector_free(ss);
1285 gsl_multimin_fminimizer_free (s);
1286#endif
1287
1288 return newResultPoint;
1289}
#define ENTER_FUNCTION()
Definition kis_debug.h:178

References ENTER_FUNCTION, and ppVar.

◆ norm()

template<class T >
qreal KisAlgebra2D::norm ( const T & a)

Definition at line 61 of file kis_algebra_2d.h.

62{
63 return std::sqrt(pow2(a.x()) + pow2(a.y()));
64}

References pow2().

◆ normalize()

template<class Point >
Point KisAlgebra2D::normalize ( const Point & a)

Definition at line 67 of file kis_algebra_2d.h.

68{
69 const qreal length = norm(a);
70 return (1.0 / length) * a;
71}

References length(), and norm().

◆ pointToLineDistSquared()

qreal KRITAGLOBAL_EXPORT KisAlgebra2D::pointToLineDistSquared ( const QPointF & pt,
const QLineF & line )

Definition at line 1379 of file kis_algebra_2d.cpp.

1380{
1381 // distance = |(p2 - p1) x (p1 - pt)| / |p2 - p1|
1382
1383 // magnitude of (p2 - p1) x (p1 - pt)
1384 const qreal cross = (line.dx() * (line.y1() - pt.y()) - line.dy() * (line.x1() - pt.x()));
1385
1386 return cross * cross / (line.dx() * line.dx() + line.dy() * line.dy());
1387}

◆ polygonDirection()

template<class T >
int KisAlgebra2D::polygonDirection ( const QVector< T > & polygon)
Returns
1 if the polygon is counterclockwise -1 if the polygon is clockwise

Note: the sign is flipped because our 0y axis is reversed

Definition at line 173 of file kis_algebra_2d.h.

173 {
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}

◆ quadraticEquation()

KRITAGLOBAL_EXPORT int KisAlgebra2D::quadraticEquation ( qreal a,
qreal b,
qreal c,
qreal * x1,
qreal * x2 )

Solves a quadratic equation in a form:

a * x^2 + b * x + c = 0

WARNING: Please note that a must be nonzero! Otherwise the equation is not quadratic! And this function doesn't check that!

Returns
the number of solutions. It can be 0, 1 or 2.

x1, x2 — the found solution. The variables are filled with data iff the corresponding solution is found. That is: 0 solutions — variables are not touched, 1 solution — x1 is filled with the result, 2 solutions — x1 and x2 are filled.

Definition at line 614 of file kis_algebra_2d.cpp.

615{
616 int numSolutions = 0;
617
618 const qreal D = pow2(b) - 4 * a * c;
619 const qreal eps = 1e-14;
620
621 if (qAbs(D) <= eps) {
622 *x1 = -b / (2 * a);
623 numSolutions = 1;
624 } else if (D < 0) {
625 return 0;
626 } else {
627 const qreal sqrt_D = std::sqrt(D);
628
629 *x1 = (-b + sqrt_D) / (2 * a);
630 *x2 = (-b - sqrt_D) / (2 * a);
631 numSolutions = 2;
632 }
633
634 return numSolutions;
635}
qreal D(qreal t, const QPointF &P0, const QPointF &P1, const QPointF &P2, const QPointF &P3, const QPointF &p)

References D(), eps, and pow2().

◆ relativeToAbsolute() [1/3]

QPointF KisAlgebra2D::relativeToAbsolute ( const QPointF & pt,
const QRectF & rc )
inline

Scale the relative point \pt into the bounds of rc. The point might be outside the rectangle.

Definition at line 607 of file kis_algebra_2d.h.

607 {
608 return rc.topLeft() + QPointF(pt.x() * rc.width(), pt.y() * rc.height());
609}

◆ relativeToAbsolute() [2/3]

QRectF KisAlgebra2D::relativeToAbsolute ( const QRectF & rel,
const QRectF & rc )
inline

Scales relative isotropic value from relative to absolute coordinate system using SVG 1.1 rules (see chapter 7.10)

Definition at line 644 of file kis_algebra_2d.h.

644 {
645 return QRectF(relativeToAbsolute(rel.topLeft(), rc), relativeToAbsolute(rel.bottomRight(), rc));
646}
QPointF relativeToAbsolute(const QPointF &pt, const QRectF &rc)

References relativeToAbsolute().

◆ relativeToAbsolute() [3/3]

qreal KisAlgebra2D::relativeToAbsolute ( qreal value,
const QRectF & rc )
inline

Scales relative isotropic value from relative to absolute coordinate system using SVG 1.1 rules (see chapter 7.10)

Definition at line 626 of file kis_algebra_2d.h.

626 {
627 const qreal coeff = std::sqrt(pow2(rc.width()) + pow2(rc.height())) / std::sqrt(2.0);
628 return value * coeff;
629}

References pow2(), and value().

◆ rightUnitNormal()

template<class T >
T KisAlgebra2D::rightUnitNormal ( const T & a)

Definition at line 134 of file kis_algebra_2d.h.

135{
136 return -leftUnitNormal(a);
137}

References leftUnitNormal().

◆ sampleRectWithPoints() [1/3]

QVector< QPoint > KRITAGLOBAL_EXPORT KisAlgebra2D::sampleRectWithPoints ( const QRect & rect)

Definition at line 508 of file kis_algebra_2d.cpp.

509 {
510 return sampleRectWithPoints<QRect, QPoint>(rect);
511 }

◆ sampleRectWithPoints() [2/3]

QVector< QPointF > KRITAGLOBAL_EXPORT KisAlgebra2D::sampleRectWithPoints ( const QRectF & rect)

Definition at line 513 of file kis_algebra_2d.cpp.

514 {
515 return sampleRectWithPoints<QRectF, QPointF>(rect);
516 }

◆ sampleRectWithPoints() [3/3]

template<class Rect , class Point >
QVector< Point > KisAlgebra2D::sampleRectWithPoints ( const Rect & rect)

Definition at line 486 of file kis_algebra_2d.cpp.

487 {
488 QVector<Point> points;
489
490 Point m1 = 0.5 * (rect.topLeft() + rect.topRight());
491 Point m2 = 0.5 * (rect.bottomLeft() + rect.bottomRight());
492
493 points << rect.topLeft();
494 points << m1;
495 points << rect.topRight();
496
497 points << 0.5 * (rect.topLeft() + rect.bottomLeft());
498 points << 0.5 * (m1 + m2);
499 points << 0.5 * (rect.topRight() + rect.bottomRight());
500
501 points << rect.bottomLeft();
502 points << m2;
503 points << rect.bottomRight();
504
505 return points;
506 }

◆ signPZ()

template<typename T >
T KisAlgebra2D::signPZ ( T x)

Usual sign() function with positive zero

Definition at line 83 of file kis_algebra_2d.h.

83 {
84 return x >= T(0) ? T(1) : T(-1);
85}

◆ signZZ()

template<typename T >
T KisAlgebra2D::signZZ ( T x)

Usual sign() function with zero returning zero

Definition at line 91 of file kis_algebra_2d.h.

91 {
92 return x == T(0) ? T(0) : x > T(0) ? T(1) : T(-1);
93}

◆ smallArrow()

QPainterPath KRITAGLOBAL_EXPORT KisAlgebra2D::smallArrow ( )

Definition at line 128 of file kis_algebra_2d.cpp.

129{
130 QPainterPath p;
131
132 p.moveTo(5, 2);
133 p.lineTo(-3, 8);
134 p.lineTo(-5, 5);
135 p.lineTo( 2, 0);
136 p.lineTo(-5,-5);
137 p.lineTo(-3,-8);
138 p.lineTo( 5,-2);
139 p.arcTo(QRectF(3, -2, 4, 4), 90, -180);
140
141 return p;
142}

References p.

◆ toQTransformStraight()

QTransform KisAlgebra2D::toQTransformStraight ( const Eigen::Matrix3d & m)
inline

Definition at line 768 of file kis_algebra_2d.cpp.

769{
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));
773}

◆ transformAsBase()

QPointF KRITAGLOBAL_EXPORT KisAlgebra2D::transformAsBase ( const QPointF & pt,
const QPointF & base1,
const QPointF & base2 )

Let pt, base1 are two vectors. base1 is uniformly scaled and then rotated into base2 using transformation matrix S * R. The function applies the same transformation to \pt and returns the result.

Definition at line 88 of file kis_algebra_2d.cpp.

88 {
89 qreal len1 = norm(base1);
90 if (len1 < 1e-5) return pt;
91 qreal sin1 = base1.y() / len1;
92 qreal cos1 = base1.x() / len1;
93
94 qreal len2 = norm(base2);
95 if (len2 < 1e-5) return QPointF();
96 qreal sin2 = base2.y() / len2;
97 qreal cos2 = base2.x() / len2;
98
99 qreal sinD = sin2 * cos1 - cos2 * sin1;
100 qreal cosD = cos1 * cos2 + sin1 * sin2;
101 qreal scaleD = len2 / len1;
102
103 QPointF result;
104 result.rx() = scaleD * (pt.x() * cosD - pt.y() * sinD);
105 result.ry() = scaleD * (pt.x() * sinD + pt.y() * cosD);
106
107 return result;
108}

References norm().

◆ transformEllipse()

std::pair< QPointF, QTransform > KRITAGLOBAL_EXPORT KisAlgebra2D::transformEllipse ( const QPointF & axes,
const QTransform & fullLocalToGlobal )

Definition at line 912 of file kis_algebra_2d.cpp.

913{
914 KisAlgebra2D::DecomposedMatrix decomposed(fullLocalToGlobal);
915 const QTransform localToGlobal =
916 decomposed.scaleTransform() *
917 decomposed.shearTransform() *
918
919 /* decomposed.projectTransform() * */
920 /*decomposed.translateTransform() * */
921
922 decomposed.rotateTransform();
923
924 const QTransform localEllipse = QTransform(1.0 / pow2(axes.x()), 0.0, 0.0,
925 0.0, 1.0 / pow2(axes.y()), 0.0,
926 0.0, 0.0, 1.0);
927
928
929 const QTransform globalToLocal = localToGlobal.inverted();
930
931 Eigen::Matrix3d eqM =
932 fromQTransformStraight(globalToLocal *
933 localEllipse *
934 globalToLocal.transposed());
935
936// std::cout << "eqM:" << std::endl << eqM << std::endl;
937
938 Eigen::EigenSolver<Eigen::Matrix3d> eigenSolver(eqM);
939
940 const Eigen::Matrix3d T = eigenSolver.eigenvalues().real().asDiagonal();
941 const Eigen::Matrix3d U = eigenSolver.eigenvectors().real();
942
943 const Eigen::Matrix3d Ti = eigenSolver.eigenvalues().imag().asDiagonal();
944 const Eigen::Matrix3d Ui = eigenSolver.eigenvectors().imag();
945
946 KIS_SAFE_ASSERT_RECOVER_NOOP(Ti.isZero());
948 KIS_SAFE_ASSERT_RECOVER_NOOP((U * U.transpose()).isIdentity());
949
950// std::cout << "T:" << std::endl << T << std::endl;
951// std::cout << "U:" << std::endl << U << std::endl;
952
953// std::cout << "Ti:" << std::endl << Ti << std::endl;
954// std::cout << "Ui:" << std::endl << Ui << std::endl;
955
956// std::cout << "UTU':" << std::endl << U * T * U.transpose() << std::endl;
957
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));
960
961 const QTransform newGlobalToLocal = toQTransformStraight(U);
962 const QTransform newLocalToGlobal = QTransform::fromScale(-1,-1) *
963 newGlobalToLocal.inverted() *
964 decomposed.translateTransform();
965
966 return std::make_pair(QPointF(newA, newB), newLocalToGlobal);
967}
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
QTransform toQTransformStraight(const Eigen::Matrix3d &m)
Eigen::Matrix3d fromQTransformStraight(const QTransform &t)

References fromQTransformStraight(), KIS_SAFE_ASSERT_RECOVER_NOOP, pow2(), KisAlgebra2D::DecomposedMatrix::rotateTransform(), KisAlgebra2D::DecomposedMatrix::scaleTransform(), KisAlgebra2D::DecomposedMatrix::shearTransform(), toQTransformStraight(), and KisAlgebra2D::DecomposedMatrix::translateTransform().

◆ wrapValue() [1/2]

template<typename T >
T KisAlgebra2D::wrapValue ( T value,
T min,
T max )
inline

Definition at line 476 of file kis_algebra_2d.h.

476 {
477 return wrapValue(value - min, max - min) + min;
478}
T wrapValue(T value, T wrapBounds)

References value(), and wrapValue().

◆ wrapValue() [2/2]

template<typename T , typename std::enable_if< std::is_integral< T >::value, T >::type * = nullptr>
T KisAlgebra2D::wrapValue ( T value,
T wrapBounds )
inline

Definition at line 451 of file kis_algebra_2d.h.

451 {
452 value %= wrapBounds;
453 if (value < 0) {
454 value += wrapBounds;
455 }
456 return value;
457}

References value().