7#ifndef __KIS_ALGEBRA_2D_H
8#define __KIS_ALGEBRA_2D_H
17#include <kritaglobal_export.h>
19#include <boost/optional.hpp>
51 return a.x() * b.x() + a.y() * b.y();
57 return a.x() * b.y() - a.y() * b.x();
63 return std::sqrt(
pow2(a.x()) +
pow2(a.y()));
73template <
typename Po
int>
74Point
lerp(
const Point &pt1,
const Point &pt2, qreal t)
76 return pt1 + (pt2 - pt1) * t;
84 return x >= T(0) ? T(1) : T(-1);
92 return x == T(0) ? T(0) : x > T(0) ? T(1) : T(-1);
100 T strippedX = qAbs(x);
101 return y >= T(0) ? strippedX : -strippedX;
105typename std::enable_if<std::is_integral<T>::value, T>::type
108 const bool a_neg = a < T(0);
109 const bool b_neg = b < T(0);
113 }
else if (a_neg == b_neg) {
116 const T a_abs = qAbs(a);
117 const T b_abs = qAbs(b);
119 return - 1 - (a_abs - T(1)) / b_abs;
126 T result = a.x() != 0 ? T(-a.y() / a.x(), 1) : T(-1, 0);
156 return qRound(
value);
177 const int numPoints = polygon.size();
178 for (
int i = 1; i <= numPoints; i++) {
180 int next = i == numPoints ? 0 : i;
183 (polygon[next].x() - polygon[prev].x()) *
184 (polygon[next].y() + polygon[prev].y());
187 return doubleSum >= 0 ? 1 : -1;
204QPointF KRITAGLOBAL_EXPORT
transformAsBase(
const QPointF &pt,
const QPointF &base1,
const QPointF &base2);
217 *rc = QRect(pt, QSize(1, 1));
221 static const qreal
eps = 1e-10;
222 *rc = QRectF(pt, QSizeF(
eps,
eps));
226template <
class Po
int,
class Rect>
237 if (pt.x() <
bounds->left()) {
239 }
else if (pt.x() >
bounds->right()) {
247 if (pt.y() <
bounds->top()) {
249 }
else if (pt.y() >
bounds->bottom()) {
250 bounds->setBottom(pt.y());
254template <
class Po
int,
class Rect>
257 if (pt.x() <
bounds->left()) {
259 }
else if (pt.x() >
bounds->right()) {
263 if (pt.y() <
bounds->top()) {
265 }
else if (pt.y() >
bounds->bottom()) {
266 bounds->setBottom(pt.y());
270template <
template <
class T>
class Container,
class Point,
class Rect>
273 Q_FOREACH (
const Point &pt, points) {
278template <
template <
class T>
class Container,
class Point>
279inline typename PointTypeTraits<Point>::rect_type
284 Q_FOREACH (
const Point &pt, points) {
291template <
class Po
int,
class Rect>
294 if (pt.x() >
bounds.right()) {
298 if (pt.x() <
bounds.left()) {
302 if (pt.y() >
bounds.bottom()) {
303 pt.ry() =
bounds.bottom();
306 if (pt.y() <
bounds.top()) {
315 return qMax(size.width(), size.height());
320 return qMin(size.width(), size.height());
332 typedef decltype(
rect.x()) CoordType;
334 CoordType w =
rect.width() * coeff;
335 CoordType h =
rect.height() * coeff;
337 return rect.adjusted(-w, -h, w, h);
346 typedef decltype(Rect().size()) Size;
347 typedef decltype(Rect().top()) ValueType;
349 if (rc.width() < size.width() ||
350 rc.height() < size.height()) {
352 ValueType width = qMax(rc.width(), size.width());
353 ValueType height = qMax(rc.height(), size.height());
355 rc = Rect(rc.topLeft(), Size(width, height));
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);
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);
415bool KRITAGLOBAL_EXPORT
intersectLineRect(QLineF &line,
const QRect
rect,
bool extendFirst,
bool extendSecond);
418bool KRITAGLOBAL_EXPORT
intersectLineConvexPolygon(QLineF &line,
const QPolygonF polygon,
bool extendFirst,
bool extendSecond);
438void KRITAGLOBAL_EXPORT
cropLineToRect(QLineF &line,
const QRect
rect,
bool extendFirst,
bool extendSecond);
440void KRITAGLOBAL_EXPORT
cropLineToConvexPolygon(QLineF &line,
const QPolygonF polygon,
bool extendFirst,
bool extendSecond);
445template <
class Po
int>
446inline Point
abs(
const Point &pt) {
447 return Point(qAbs(pt.x()), qAbs(pt.y()));
450template<typename T, typename std::enable_if<std::is_integral<T>::value, T>::type* =
nullptr>
459template<typename T, typename std::enable_if<std::is_floating_point<T>::value, T>::type* =
nullptr>
468template<
typename T,
typename std::enable_if<std::is_same<
decltype(T().x()),
decltype(T().y())>
::value, T>::type* =
nullptr>
484 : m_a(a), m_p(b - a), m_norm_p_inv(1.0 /
norm(m_p))
494 const qreal val =
value(pt);
498 qreal
value(
const QPointF &pt)
const {
502 int pos(
const QPointF &pt)
const {
507 return QLineF(m_a, m_a + m_p);
522 m_radius_sq(
pow2(radius)),
523 m_fadeCoeff(1.0 / (
pow2(radius + 1.0) - m_radius_sq))
528 const qreal val =
value(pt);
533 qreal
value(
const QPointF &pt)
const {
537 int pos(
const QPointF &pt)
const {
538 return signZZ(valueSq(pt));
543 return (valSq - m_radius_sq) * m_fadeCoeff;
595 const QPointF &c2, qreal
r2);
608 return rc.topLeft() + QPointF(pt.x() * rc.width(), pt.y() * rc.height());
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);
627 const qreal coeff = std::sqrt(
pow2(rc.width()) +
pow2(rc.height())) / std::sqrt(2.0);
628 return value * coeff;
636 const qreal coeff = std::sqrt(
pow2(rc.width()) +
pow2(rc.height())) / std::sqrt(2.0);
637 return coeff != 0 ?
value / coeff : 0;
659bool KRITAGLOBAL_EXPORT
fuzzyMatrixCompare(
const QTransform &t1,
const QTransform &t2, qreal delta);
675template <
template<
typename>
class Cont,
class Point>
678 if (c1.size() != c2.size())
return false;
680 const qreal
eps = delta;
682 return std::mismatch(c1.cbegin(),
685 [
eps] (
const QPointF &pt1,
const QPointF &pt2) {
686 return fuzzyPointCompare(pt1, pt2, eps);
696template<
class Rect,
typename Difference = decltype(Rect::w
idth())>
698 typedef decltype(
r1.topLeft()) Point;
700 const Point d1 =
abs(
r1.topLeft() -
r2.topLeft());
701 const Point d2 =
abs(
r1.bottomRight() -
r2.bottomRight());
703 const Difference maxError = std::max({d1.x(), d1.y(), d2.x(), d2.y()});
704 return maxError < tolerance;
714 return QTransform::fromScale(scaleX, scaleY);
733 return QTransform::fromTranslate(dx, dy);
750 translateTransform() *
764 qreal proj[3] = {0.0, 0.0, 1.0};
772std::pair<QPointF, QTransform> KRITAGLOBAL_EXPORT
transformEllipse(
const QPointF &axes,
const QTransform &fullLocalToGlobal);
774QPointF KRITAGLOBAL_EXPORT
alignForZoom(
const QPointF &pt, qreal zoom);
784 return y0 + (y1 - y0) * (x - x0) / (x1 - x0);
793boost::optional<QPointF>
intersectLines(
const QLineF &boundedLine,
const QLineF &unboundedLine);
802 const QPointF &
q1,
const QPointF &
q2);
817boost::optional<QPointF> KRITAGLOBAL_EXPORT
findTrianglePointNearest(
const QPointF &
p1,
const QPointF &
p2, qreal a, qreal b,
const QPointF &nearest);
834 const QPointF &base,
const QPointF &newBase,
835 const QPointF &wingA,
const QPointF &wingB);
851 const QPointF &base,
const QPointF &newBase,
qreal length(const QPointF &vec)
float value(const T *src, size_t ch)
Eigen::Matrix< double, 4, 2 > R
a simple class to generate Halton sequence
int currentValue(int maxRange) const
HaltonSequenceGenerator(int base)
int generate(int maxRange)
qreal currentValue() const
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
qreal kisDistance(const QPointF &pt1, const QPointF &pt2)
qreal kisSquareDistance(const QPointF &pt1, const QPointF &pt2)
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 ¢er1, qreal r1, const QPointF ¢er2, 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)
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)
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)
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 transform() const
QTransform translateTransform() const