Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtriangulator.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#include <QtGui/qevent.h>
8#include <QtGui/qpainter.h>
9#include <QtGui/qpainterpath.h>
10#include <QtGui/private/qbezier_p.h>
11#include <QtGui/private/qdatabuffer_p.h>
12#include <QtCore/qbitarray.h>
13#include <QtCore/qvarlengtharray.h>
14#include <QtCore/qqueue.h>
15#include <QtCore/qglobal.h>
16#include <QtCore/qpoint.h>
17#include <QtCore/qalgorithms.h>
18#include <private/qrbtree_p.h>
19
21
22//#define Q_TRIANGULATOR_DEBUG
23
24#define Q_FIXED_POINT_SCALE 32
25
26template<typename T>
27struct QVertexSet
28{
29 inline QVertexSet() { }
30 inline QVertexSet(const QVertexSet<T> &other) : vertices(other.vertices), indices(other.indices) { }
31 QVertexSet<T> &operator = (const QVertexSet<T> &other) {vertices = other.vertices; indices = other.indices; return *this;}
32
33 // The vertices of a triangle are given by: (x[i[n]], y[i[n]]), (x[j[n]], y[j[n]]), (x[k[n]], y[k[n]]), n = 0, 1, ...
34 QList<qreal> vertices; // [x[0], y[0], x[1], y[1], x[2], ...]
35 QList<T> indices; // [i[0], j[0], k[0], i[1], j[1], k[1], i[2], ...]
36};
37
38//============================================================================//
39// QFraction //
40//============================================================================//
41
42// Fraction must be in the range [0, 1)
44{
45 // Comparison operators must not be called on invalid fractions.
46 inline bool operator < (const QFraction &other) const;
47 inline bool operator == (const QFraction &other) const;
48 inline bool operator != (const QFraction &other) const {return !(*this == other);}
49 inline bool operator > (const QFraction &other) const {return other < *this;}
50 inline bool operator >= (const QFraction &other) const {return !(*this < other);}
51 inline bool operator <= (const QFraction &other) const {return !(*this > other);}
52
53 inline bool isValid() const {return denominator != 0;}
54
55 // numerator and denominator must not have common denominators.
57};
58
59static inline quint64 gcd(quint64 x, quint64 y)
60{
61 while (y != 0) {
62 quint64 z = y;
63 y = x % y;
64 x = z;
65 }
66 return x;
67}
68
69static inline int compare(quint64 a, quint64 b)
70{
71 return (a > b) - (a < b);
72}
73
74// Compare a/b with c/d.
75// Return negative if less, 0 if equal, positive if greater.
76// a < b, c < d
77static int qCompareFractions(quint64 a, quint64 b, quint64 c, quint64 d)
78{
79 const quint64 LIMIT = Q_UINT64_C(0x100000000);
80 for (;;) {
81 // If the products 'ad' and 'bc' fit into 64 bits, they can be directly compared.
82 if (b < LIMIT && d < LIMIT)
83 return compare(a * d, b * c);
84
85 if (a == 0 || c == 0)
86 return compare(a, c);
87
88 // a/b < c/d <=> d/c < b/a
89 quint64 b_div_a = b / a;
90 quint64 d_div_c = d / c;
91 if (b_div_a != d_div_c)
92 return compare(d_div_c, b_div_a);
93
94 // floor(d/c) == floor(b/a)
95 // frac(d/c) < frac(b/a) ?
96 // frac(x/y) = (x%y)/y
97 d -= d_div_c * c; //d %= c;
98 b -= b_div_a * a; //b %= a;
99 qSwap(a, d);
100 qSwap(b, c);
101 }
102}
103
104// Fraction must be in the range [0, 1)
105// Assume input is valid.
106static QFraction qFraction(quint64 n, quint64 d) {
107 QFraction result;
108 if (n == 0) {
109 result.numerator = 0;
110 result.denominator = 1;
111 } else {
112 quint64 g = gcd(n, d);
113 result.numerator = n / g;
114 result.denominator = d / g;
115 }
116 return result;
117}
118
119inline bool QFraction::operator < (const QFraction &other) const
120{
121 return qCompareFractions(numerator, denominator, other.numerator, other.denominator) < 0;
122}
123
124inline bool QFraction::operator == (const QFraction &other) const
125{
126 return numerator == other.numerator && denominator == other.denominator;
127}
128
129//============================================================================//
130// QPodPoint //
131//============================================================================//
132
134{
135 inline bool operator < (const QPodPoint &other) const
136 {
137 if (y != other.y)
138 return y < other.y;
139 return x < other.x;
140 }
141
142 inline bool operator > (const QPodPoint &other) const {return other < *this;}
143 inline bool operator <= (const QPodPoint &other) const {return !(*this > other);}
144 inline bool operator >= (const QPodPoint &other) const {return !(*this < other);}
145 inline bool operator == (const QPodPoint &other) const {return x == other.x && y == other.y;}
146 inline bool operator != (const QPodPoint &other) const {return x != other.x || y != other.y;}
147
148 inline QPodPoint &operator += (const QPodPoint &other) {x += other.x; y += other.y; return *this;}
149 inline QPodPoint &operator -= (const QPodPoint &other) {x -= other.x; y -= other.y; return *this;}
150 inline QPodPoint operator + (const QPodPoint &other) const {QPodPoint result = {x + other.x, y + other.y}; return result;}
151 inline QPodPoint operator - (const QPodPoint &other) const {QPodPoint result = {x - other.x, y - other.y}; return result;}
152
153 int x;
154 int y;
155};
156
157static inline qint64 qCross(const QPodPoint &u, const QPodPoint &v)
158{
159 return qint64(u.x) * qint64(v.y) - qint64(u.y) * qint64(v.x);
160}
161
162#ifdef Q_TRIANGULATOR_DEBUG
163static inline qint64 qDot(const QPodPoint &u, const QPodPoint &v)
164{
165 return qint64(u.x) * qint64(v.x) + qint64(u.y) * qint64(v.y);
166}
167#endif
168
169// Return positive value if 'p' is to the right of the line 'v1'->'v2', negative if left of the
170// line and zero if exactly on the line.
171// The returned value is the z-component of the qCross product between 'v2-v1' and 'p-v1',
172// which is twice the signed area of the triangle 'p'->'v1'->'v2' (positive for CW order).
173static inline qint64 qPointDistanceFromLine(const QPodPoint &p, const QPodPoint &v1, const QPodPoint &v2)
174{
175 return qCross(v2 - v1, p - v1);
176}
177
178static inline bool qPointIsLeftOfLine(const QPodPoint &p, const QPodPoint &v1, const QPodPoint &v2)
179{
180 return QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(p, v1, v2) < 0;
181}
182
183//============================================================================//
184// QIntersectionPoint //
185//============================================================================//
186
188{
189 inline bool isValid() const {return xOffset.isValid() && yOffset.isValid();}
191 inline bool isAccurate() const {return xOffset.numerator == 0 && yOffset.numerator == 0;}
192 bool operator < (const QIntersectionPoint &other) const;
193 bool operator == (const QIntersectionPoint &other) const;
194 inline bool operator != (const QIntersectionPoint &other) const {return !(*this == other);}
195 inline bool operator > (const QIntersectionPoint &other) const {return other < *this;}
196 inline bool operator >= (const QIntersectionPoint &other) const {return !(*this < other);}
197 inline bool operator <= (const QIntersectionPoint &other) const {return !(*this > other);}
198 bool isOnLine(const QPodPoint &u, const QPodPoint &v) const;
199
203};
204
206{
207 // upperLeft = point, xOffset = 0/1, yOffset = 0/1.
208 QIntersectionPoint p = {{point.x, point.y}, {0, 1}, {0, 1}};
209 return p;
210}
211
212static QIntersectionPoint qIntersectionPoint(const QPodPoint &u1, const QPodPoint &u2, const QPodPoint &v1, const QPodPoint &v2)
213{
214 QIntersectionPoint result = {{0, 0}, {0, 0}, {0, 0}};
215
216 QPodPoint u = u2 - u1;
217 QPodPoint v = v2 - v1;
218 qint64 d1 = qCross(u, v1 - u1);
219 qint64 d2 = qCross(u, v2 - u1);
220 qint64 det = d2 - d1;
221 qint64 d3 = qCross(v, u1 - v1);
222 qint64 d4 = d3 - det; //qCross(v, u2 - v1);
223
224 // Check that the math is correct.
225 Q_ASSERT(d4 == qCross(v, u2 - v1));
226
227 // The intersection point can be expressed as:
228 // v1 - v * d1/det
229 // v2 - v * d2/det
230 // u1 + u * d3/det
231 // u2 + u * d4/det
232
233 // I'm only interested in lines that are crossing, so ignore parallel lines even if they overlap.
234 if (det == 0)
235 return result;
236
237 if (det < 0) {
238 det = -det;
239 d1 = -d1;
240 d2 = -d2;
241 d3 = -d3;
242 d4 = -d4;
243 }
244
245 // I'm only interested in lines intersecting at their interior, not at their end points.
246 // The lines intersect at their interior if and only if 'd1 < 0', 'd2 > 0', 'd3 < 0' and 'd4 > 0'.
247 if (d1 >= 0 || d2 <= 0 || d3 <= 0 || d4 >= 0)
248 return result;
249
250 // Calculate the intersection point as follows:
251 // v1 - v * d1/det | v1 <= v2 (component-wise)
252 // v2 - v * d2/det | v2 < v1 (component-wise)
253
254 // Assuming 21 bits per vector component.
255 // TODO: Make code path for 31 bits per vector component.
256 if (v.x >= 0) {
257 result.upperLeft.x = v1.x + (-v.x * d1) / det;
258 result.xOffset = qFraction(quint64(-v.x * d1) % quint64(det), quint64(det));
259 } else {
260 result.upperLeft.x = v2.x + (-v.x * d2) / det;
261 result.xOffset = qFraction(quint64(-v.x * d2) % quint64(det), quint64(det));
262 }
263
264 if (v.y >= 0) {
265 result.upperLeft.y = v1.y + (-v.y * d1) / det;
266 result.yOffset = qFraction(quint64(-v.y * d1) % quint64(det), quint64(det));
267 } else {
268 result.upperLeft.y = v2.y + (-v.y * d2) / det;
269 result.yOffset = qFraction(quint64(-v.y * d2) % quint64(det), quint64(det));
270 }
271
272 Q_ASSERT(result.xOffset.isValid());
273 Q_ASSERT(result.yOffset.isValid());
274 return result;
275}
276
278{
279 QPodPoint result = upperLeft;
280 if (2 * xOffset.numerator >= xOffset.denominator)
281 ++result.x;
282 if (2 * yOffset.numerator >= yOffset.denominator)
283 ++result.y;
284 return result;
285}
286
288{
289 if (upperLeft.y != other.upperLeft.y)
290 return upperLeft.y < other.upperLeft.y;
291 if (yOffset != other.yOffset)
292 return yOffset < other.yOffset;
293 if (upperLeft.x != other.upperLeft.x)
294 return upperLeft.x < other.upperLeft.x;
295 return xOffset < other.xOffset;
296}
297
298bool QIntersectionPoint::operator == (const QIntersectionPoint &other) const
299{
300 return upperLeft == other.upperLeft && xOffset == other.xOffset && yOffset == other.yOffset;
301}
302
303// Returns \c true if this point is on the infinite line passing through 'u' and 'v'.
304bool QIntersectionPoint::isOnLine(const QPodPoint &u, const QPodPoint &v) const
305{
306 // TODO: Make code path for coordinates with more than 21 bits.
307 const QPodPoint p = upperLeft - u;
308 const QPodPoint q = v - u;
309 bool isHorizontal = p.y == 0 && yOffset.numerator == 0;
310 bool isVertical = p.x == 0 && xOffset.numerator == 0;
311 if (isHorizontal && isVertical)
312 return true;
313 if (isHorizontal)
314 return q.y == 0;
315 if (q.y == 0)
316 return false;
317 if (isVertical)
318 return q.x == 0;
319 if (q.x == 0)
320 return false;
321
322 // At this point, 'p+offset' and 'q' cannot lie on the x or y axis.
323
324 if (((q.x < 0) == (q.y < 0)) != ((p.x < 0) == (p.y < 0)))
325 return false; // 'p + offset' and 'q' pass through different quadrants.
326
327 // Move all coordinates into the first quadrant.
328 quint64 nx, ny;
329 if (p.x < 0)
330 nx = quint64(-p.x) * xOffset.denominator - xOffset.numerator;
331 else
332 nx = quint64(p.x) * xOffset.denominator + xOffset.numerator;
333 if (p.y < 0)
334 ny = quint64(-p.y) * yOffset.denominator - yOffset.numerator;
335 else
336 ny = quint64(p.y) * yOffset.denominator + yOffset.numerator;
337
338 return qFraction(quint64(qAbs(q.x)) * xOffset.denominator, quint64(qAbs(q.y)) * yOffset.denominator) == qFraction(nx, ny);
339}
340
341//============================================================================//
342// QMaxHeap //
343//============================================================================//
344
345template <class T>
347{
348public:
349 QMaxHeap() : m_data(0) {}
350 inline int size() const {return m_data.size();}
351 inline bool empty() const {return m_data.isEmpty();}
352 inline bool isEmpty() const {return m_data.isEmpty();}
353 void push(const T &x);
354 T pop();
355 inline const T &top() const {return m_data.first();}
356private:
357 static inline int parent(int i) {return (i - 1) / 2;}
358 static inline int left(int i) {return 2 * i + 1;}
359 static inline int right(int i) {return 2 * i + 2;}
360
361 QDataBuffer<T> m_data;
362};
363
364template <class T>
365void QMaxHeap<T>::push(const T &x)
366{
367 int current = m_data.size();
368 int parent = QMaxHeap::parent(current);
369 m_data.add(x);
370 while (current != 0 && m_data.at(parent) < x) {
371 m_data.at(current) = m_data.at(parent);
372 current = parent;
373 parent = QMaxHeap::parent(current);
374 }
375 m_data.at(current) = x;
376}
377
378template <class T>
380{
381 T result = m_data.first();
382 T back = m_data.last();
383 m_data.pop_back();
384 if (!m_data.isEmpty()) {
385 int current = 0;
386 for (;;) {
387 int left = QMaxHeap::left(current);
388 int right = QMaxHeap::right(current);
389 if (left >= m_data.size())
390 break;
391 int greater = left;
392 if (right < m_data.size() && m_data.at(left) < m_data.at(right))
393 greater = right;
394 if (m_data.at(greater) < back)
395 break;
396 m_data.at(current) = m_data.at(greater);
397 current = greater;
398 }
399 m_data.at(current) = back;
400 }
401 return result;
402}
403
404//============================================================================//
405// QInt64Hash //
406//============================================================================//
407
408static inline int primeForCount(int count)
409{
410 Q_ASSERT(count >= 0); // Q_PRE
411
412 // Copied from Qt 5 qhash.cpp
413 constexpr auto primeForNumBits = [](int numBits) -> int
414 {
415 constexpr uchar prime_deltas[] = {
416 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 17, 27, 3,
417 1, 29, 3, 21, 7, 17, 15, 9, 43, 35, 15, 0, 0, 0, 0, 0
418 };
419
420 return (1 << numBits) + prime_deltas[numBits];
421 };
422
423 int low = 0;
424 int high = 32;
425 for (int i = 0; i < 5; ++i) {
426 int mid = (high + low) / 2;
427 if (uint(count) >= (1u << mid))
428 low = mid;
429 else
430 high = mid;
431 }
432 return primeForNumBits(high);
433}
434
435// Hash set of quint64s. Elements cannot be removed without clearing the
436// entire set. A value of -1 is used to mark unused entries.
438{
440public:
441 inline QInt64Set(int capacity = 64);
442 inline ~QInt64Set() {delete[] m_array;}
443 inline bool isValid() const {return m_array;}
444 void insert(quint64 key);
445 bool contains(quint64 key) const;
446 inline void clear();
447private:
448 bool rehash(int capacity);
449
450 static const quint64 UNUSED;
451
452 quint64 *m_array;
453 int m_capacity;
454 int m_count;
455};
456
457const quint64 QInt64Set::UNUSED = quint64(-1);
458
459inline QInt64Set::QInt64Set(int capacity)
460{
461 m_capacity = primeForCount(capacity);
462 m_array = new quint64[m_capacity];
463 clear();
464}
465
466bool QInt64Set::rehash(int capacity)
467{
468 quint64 *oldArray = m_array;
469 int oldCapacity = m_capacity;
470
471 m_capacity = capacity;
472 m_array = new quint64[m_capacity];
473 clear();
474 for (int i = 0; i < oldCapacity; ++i) {
475 if (oldArray[i] != UNUSED)
476 insert(oldArray[i]);
477 }
478 delete[] oldArray;
479 return true;
480}
481
482void QInt64Set::insert(quint64 key)
483{
484 if (m_count > 3 * m_capacity / 4)
485 rehash(primeForCount(2 * m_capacity));
486 int index = int(key % m_capacity);
487 for (int i = 0; i < m_capacity; ++i) {
488 index += i;
489 if (index >= m_capacity)
490 index -= m_capacity;
491 if (m_array[index] == key)
492 return;
493 if (m_array[index] == UNUSED) {
494 ++m_count;
495 m_array[index] = key;
496 return;
497 }
498 }
499 Q_ASSERT_X(0, "QInt64Hash<T>::insert", "Hash set full.");
500}
501
502bool QInt64Set::contains(quint64 key) const
503{
504 int index = int(key % m_capacity);
505 for (int i = 0; i < m_capacity; ++i) {
506 index += i;
507 if (index >= m_capacity)
508 index -= m_capacity;
509 if (m_array[index] == key)
510 return true;
511 if (m_array[index] == UNUSED)
512 return false;
513 }
514 return false;
515}
516
517inline void QInt64Set::clear()
518{
519 for (int i = 0; i < m_capacity; ++i)
520 m_array[i] = UNUSED;
521 m_count = 0;
522}
523
524//============================================================================//
525// QTriangulator //
526//============================================================================//
527template<typename T>
529{
530public:
532
533 //================================//
534 // QTriangulator::ComplexToSimple //
535 //================================//
536 friend class ComplexToSimple;
538 {
539 public:
541 : m_parent(parent), m_edges(0), m_events(0), m_splits(0), m_initialPointCount(0) { }
542 void decompose();
543 private:
544 struct Edge
545 {
546 inline int &upper() {return pointingUp ? to : from;}
547 inline int &lower() {return pointingUp ? from : to;}
548 inline int upper() const {return pointingUp ? to : from;}
549 inline int lower() const {return pointingUp ? from : to;}
550
551 QRBTree<int>::Node *node;
552 int from, to; // vertex
553 int next, previous; // edge
554 int winding;
555 bool mayIntersect;
556 bool pointingUp, originallyPointingUp;
557 };
558
559 struct Intersection
560 {
561 bool operator < (const Intersection &other) const {return other.intersectionPoint < intersectionPoint;}
562
563 QIntersectionPoint intersectionPoint;
564 int vertex;
565 int leftEdge;
566 int rightEdge;
567 };
568
569 struct Split
570 {
571 int vertex;
572 int edge;
573 bool accurate;
574 };
575
576 struct Event
577 {
578 enum Type {Upper, Lower};
579 inline bool operator < (const Event &other) const;
580
581 QPodPoint point;
582 Type type;
583 int edge;
584 };
585
586#ifdef Q_TRIANGULATOR_DEBUG
587 friend class DebugDialog;
588 friend class QTriangulator;
589 class DebugDialog : public QDialog
590 {
591 public:
593 protected:
594 void paintEvent(QPaintEvent *);
595 void wheelEvent(QWheelEvent *);
598 private:
602 int m_vertex;
603 };
604#endif
605
606 void initEdges();
607 bool calculateIntersection(int left, int right);
608 bool edgeIsLeftOfEdge(int leftEdgeIndex, int rightEdgeIndex) const;
609 QRBTree<int>::Node *searchEdgeLeftOf(int edgeIndex) const;
610 QRBTree<int>::Node *searchEdgeLeftOf(int edgeIndex, QRBTree<int>::Node *after) const;
611 std::pair<QRBTree<int>::Node *, QRBTree<int>::Node *> bounds(const QPodPoint &point) const;
612 std::pair<QRBTree<int>::Node *, QRBTree<int>::Node *> outerBounds(const QPodPoint &point) const;
613 void splitEdgeListRange(QRBTree<int>::Node *leftmost, QRBTree<int>::Node *rightmost, int vertex, const QIntersectionPoint &intersectionPoint);
614 void reorderEdgeListRange(QRBTree<int>::Node *leftmost, QRBTree<int>::Node *rightmost);
615 void sortEdgeList(const QPodPoint eventPoint);
616 void fillPriorityQueue();
617 void calculateIntersections();
618 int splitEdge(int splitIndex);
619 bool splitEdgesAtIntersections();
620 void insertEdgeIntoVectorIfWanted(ShortArray &orderedEdges, int i);
621 void removeUnwantedEdgesAndConnect();
622 void removeUnusedPoints();
623
624 QTriangulator *m_parent;
625 QDataBuffer<Edge> m_edges;
626 QRBTree<int> m_edgeList;
627 QDataBuffer<Event> m_events;
628 QDataBuffer<Split> m_splits;
629 QMaxHeap<Intersection> m_topIntersection;
630 QInt64Set m_processedEdgePairs;
631 int m_initialPointCount;
632 };
633#ifdef Q_TRIANGULATOR_DEBUG
634 friend class ComplexToSimple::DebugDialog;
635#endif
636
637 //=================================//
638 // QTriangulator::SimpleToMonotone //
639 //=================================//
640 friend class SimpleToMonotone;
642 {
643 public:
645 : m_parent(parent), m_edges(0), m_upperVertex(0), m_clockwiseOrder(false) { }
646 void decompose();
647 private:
648 enum VertexType {MergeVertex, EndVertex, RegularVertex, StartVertex, SplitVertex};
649
650 struct Edge
651 {
652 QRBTree<int>::Node *node;
653 int helper, twin, next, previous;
654 T from, to;
655 VertexType type;
656 bool pointingUp;
657 int upper() const {return (pointingUp ? to : from);}
658 int lower() const {return (pointingUp ? from : to);}
659 };
660
661 friend class CompareVertices;
662 class CompareVertices
663 {
664 public:
665 CompareVertices(SimpleToMonotone *parent) : m_parent(parent) { }
666 bool operator () (int i, int j) const;
667 private:
668 SimpleToMonotone *m_parent;
669 };
670
671 void setupDataStructures();
672 void removeZeroLengthEdges();
673 void fillPriorityQueue();
674 bool edgeIsLeftOfEdge(int leftEdgeIndex, int rightEdgeIndex) const;
675 // Returns the rightmost edge not to the right of the given edge.
676 QRBTree<int>::Node *searchEdgeLeftOfEdge(int edgeIndex) const;
677 // Returns the rightmost edge left of the given point.
678 QRBTree<int>::Node *searchEdgeLeftOfPoint(int pointIndex) const;
679 void classifyVertex(int i);
680 void classifyVertices();
681 bool pointIsInSector(const QPodPoint &p, const QPodPoint &v1, const QPodPoint &v2, const QPodPoint &v3);
682 bool pointIsInSector(int vertex, int sector);
683 int findSector(int edge, int vertex);
684 void createDiagonal(int lower, int upper);
685 void monotoneDecomposition();
686
687 QTriangulator *m_parent;
688 QRBTree<int> m_edgeList;
689 QDataBuffer<Edge> m_edges;
690 QDataBuffer<int> m_upperVertex;
691 bool m_clockwiseOrder;
692 };
693
694 //====================================//
695 // QTriangulator::MonotoneToTriangles //
696 //====================================//
697 friend class MonotoneToTriangles;
699 {
700 public:
702 : m_parent(parent), m_first(0), m_length(0) { }
703 void decompose();
704 private:
705 inline T indices(int index) const {return m_parent->m_indices.at(index + m_first);}
706 inline int next(int index) const {return (index + 1) % m_length;}
707 inline int previous(int index) const {return (index + m_length - 1) % m_length;}
708 inline bool less(int i, int j) const {return m_parent->m_vertices.at((qint32)indices(i)) < m_parent->m_vertices.at(indices(j));}
709 inline bool leftOfEdge(int i, int j, int k) const
710 {
711 return qPointIsLeftOfLine(m_parent->m_vertices.at((qint32)indices(i)),
712 m_parent->m_vertices.at((qint32)indices(j)), m_parent->m_vertices.at((qint32)indices(k)));
713 }
714
715 QTriangulator<T> *m_parent;
716 int m_first;
717 int m_length;
718 };
719
721 : m_vertices(0), m_hint(0) { }
722
723 // Call this only once.
724 void initialize(const qreal *polygon, int count, uint hint, const QTransform &matrix);
725 // Call this only once.
726 void initialize(const QVectorPath &path, const QTransform &matrix, qreal lod);
727 // Call this only once.
728 void initialize(const QPainterPath &path, const QTransform &matrix, qreal lod);
729 // Call either triangulate() or polyline() only once.
732private:
733 QDataBuffer<QPodPoint> m_vertices;
734 QList<T> m_indices;
735 uint m_hint;
736};
737
738//============================================================================//
739// QTriangulator //
740//============================================================================//
741
742template <typename T>
744{
745 for (int i = 0; i < m_vertices.size(); ++i) {
746 Q_ASSERT(qAbs(m_vertices.at(i).x) < (1 << 21));
747 Q_ASSERT(qAbs(m_vertices.at(i).y) < (1 << 21));
748 }
749
750 if (!(m_hint & (QVectorPath::OddEvenFill | QVectorPath::WindingFill)))
751 m_hint |= QVectorPath::OddEvenFill;
752
753 if (m_hint & QVectorPath::NonConvexShapeMask) {
754 ComplexToSimple c2s(this);
755 c2s.decompose();
756 SimpleToMonotone s2m(this);
757 s2m.decompose();
758 }
759 MonotoneToTriangles m2t(this);
760 m2t.decompose();
761
762 QVertexSet<T> result;
763 result.indices = m_indices;
764 result.vertices.resize(2 * m_vertices.size());
765 for (int i = 0; i < m_vertices.size(); ++i) {
766 result.vertices[2 * i + 0] = qreal(m_vertices.at(i).x) / Q_FIXED_POINT_SCALE;
767 result.vertices[2 * i + 1] = qreal(m_vertices.at(i).y) / Q_FIXED_POINT_SCALE;
768 }
769 return result;
770}
771
772template <typename T>
774{
775 for (int i = 0; i < m_vertices.size(); ++i) {
776 Q_ASSERT(qAbs(m_vertices.at(i).x) < (1 << 21));
777 Q_ASSERT(qAbs(m_vertices.at(i).y) < (1 << 21));
778 }
779
780 if (!(m_hint & (QVectorPath::OddEvenFill | QVectorPath::WindingFill)))
781 m_hint |= QVectorPath::OddEvenFill;
782
783 if (m_hint & QVectorPath::NonConvexShapeMask) {
784 ComplexToSimple c2s(this);
785 c2s.decompose();
786 }
787
788 QVertexSet<T> result;
789 result.indices = m_indices;
790 result.vertices.resize(2 * m_vertices.size());
791 for (int i = 0; i < m_vertices.size(); ++i) {
792 result.vertices[2 * i + 0] = qreal(m_vertices.at(i).x) / Q_FIXED_POINT_SCALE;
793 result.vertices[2 * i + 1] = qreal(m_vertices.at(i).y) / Q_FIXED_POINT_SCALE;
794 }
795 return result;
796}
797
798template <typename T>
799void QTriangulator<T>::initialize(const qreal *polygon, int count, uint hint, const QTransform &matrix)
800{
801 m_hint = hint;
802 m_vertices.resize(count);
803 m_indices.resize(count + 1);
804 for (int i = 0; i < count; ++i) {
805 qreal x, y;
806 matrix.map(polygon[2 * i + 0], polygon[2 * i + 1], &x, &y);
807 m_vertices.at(i).x = qRound(x * Q_FIXED_POINT_SCALE);
808 m_vertices.at(i).y = qRound(y * Q_FIXED_POINT_SCALE);
809 m_indices[i] = i;
810 }
811 m_indices[count] = T(-1); //Q_TRIANGULATE_END_OF_POLYGON
812}
813
814template <typename T>
815void QTriangulator<T>::initialize(const QVectorPath &path, const QTransform &matrix, qreal lod)
816{
817 m_hint = path.hints();
818 // Curved paths will be converted to complex polygons.
819 m_hint &= ~QVectorPath::CurvedShapeMask;
820
821 const qreal *p = path.points();
822 const QPainterPath::ElementType *e = path.elements();
823 if (e) {
824 for (int i = 0; i < path.elementCount(); ++i, ++e, p += 2) {
825 switch (*e) {
826 case QPainterPath::MoveToElement:
827 if (!m_indices.isEmpty())
828 m_indices.push_back(T(-1)); // Q_TRIANGULATE_END_OF_POLYGON
829 Q_FALLTHROUGH();
830 case QPainterPath::LineToElement:
831 m_indices.push_back(T(m_vertices.size()));
832 m_vertices.resize(m_vertices.size() + 1);
833 qreal x, y;
834 matrix.map(p[0], p[1], &x, &y);
835 m_vertices.last().x = qRound(x * Q_FIXED_POINT_SCALE);
836 m_vertices.last().y = qRound(y * Q_FIXED_POINT_SCALE);
837 break;
838 case QPainterPath::CurveToElement:
839 {
840 qreal pts[8];
841 for (int i = 0; i < 4; ++i)
842 matrix.map(p[2 * i - 2], p[2 * i - 1], &pts[2 * i + 0], &pts[2 * i + 1]);
843 for (int i = 0; i < 8; ++i)
844 pts[i] *= lod;
845 QBezier bezier = QBezier::fromPoints(QPointF(pts[0], pts[1]), QPointF(pts[2], pts[3]), QPointF(pts[4], pts[5]), QPointF(pts[6], pts[7]));
846 QPolygonF poly = bezier.toPolygon();
847 // Skip first point, it already exists in 'm_vertices'.
848 for (int j = 1; j < poly.size(); ++j) {
849 m_indices.push_back(T(m_vertices.size()));
850 m_vertices.resize(m_vertices.size() + 1);
851 m_vertices.last().x = qRound(poly.at(j).x() * Q_FIXED_POINT_SCALE / lod);
852 m_vertices.last().y = qRound(poly.at(j).y() * Q_FIXED_POINT_SCALE / lod);
853 }
854 }
855 i += 2;
856 e += 2;
857 p += 4;
858 break;
859 default:
860 Q_ASSERT_X(0, "QTriangulator::triangulate", "Unexpected element type.");
861 break;
862 }
863 }
864 } else {
865 for (int i = 0; i < path.elementCount(); ++i, p += 2) {
866 m_indices.push_back(T(m_vertices.size()));
867 m_vertices.resize(m_vertices.size() + 1);
868 qreal x, y;
869 matrix.map(p[0], p[1], &x, &y);
870 m_vertices.last().x = qRound(x * Q_FIXED_POINT_SCALE);
871 m_vertices.last().y = qRound(y * Q_FIXED_POINT_SCALE);
872 }
873 }
874 m_indices.push_back(T(-1)); // Q_TRIANGULATE_END_OF_POLYGON
875}
876
877template <typename T>
878void QTriangulator<T>::initialize(const QPainterPath &path, const QTransform &matrix, qreal lod)
879{
880 initialize(qtVectorPathForPath(path), matrix, lod);
881}
882
883//============================================================================//
884// QTriangulator::ComplexToSimple //
885//============================================================================//
886template <typename T>
888{
889 m_initialPointCount = m_parent->m_vertices.size();
890 initEdges();
891 do {
892 calculateIntersections();
893 } while (splitEdgesAtIntersections());
894
895 removeUnwantedEdgesAndConnect();
896 removeUnusedPoints();
897
898 m_parent->m_indices.clear();
899 QBitArray processed(m_edges.size(), false);
900 for (int first = 0; first < m_edges.size(); ++first) {
901 // If already processed, or if unused path, skip.
902 if (processed.at(first) || m_edges.at(first).next == -1)
903 continue;
904
905 int i = first;
906 do {
907 Q_ASSERT(!processed.at(i));
908 Q_ASSERT(m_edges.at(m_edges.at(i).next).previous == i);
909 m_parent->m_indices.push_back(m_edges.at(i).from);
910 processed.setBit(i);
911 i = m_edges.at(i).next; // CCW order
912 } while (i != first);
913 m_parent->m_indices.push_back(T(-1)); // Q_TRIANGULATE_END_OF_POLYGON
914 }
915}
916
917template <typename T>
918void QTriangulator<T>::ComplexToSimple::initEdges()
919{
920 // Initialize edge structure.
921 // 'next' and 'previous' are not being initialized at this point.
922 int first = 0;
923 for (int i = 0; i < m_parent->m_indices.size(); ++i) {
924 if (m_parent->m_indices.at(i) == T(-1)) { // Q_TRIANGULATE_END_OF_POLYGON
925 if (m_edges.size() != first)
926 m_edges.last().to = m_edges.at(first).from;
927 first = m_edges.size();
928 } else {
929 Q_ASSERT(i + 1 < m_parent->m_indices.size());
930 // {node, from, to, next, previous, winding, mayIntersect, pointingUp, originallyPointingUp}
931 Edge edge = {nullptr, int(m_parent->m_indices.at(i)), int(m_parent->m_indices.at(i + 1)), -1, -1, 0, true, false, false};
932 m_edges.add(edge);
933 }
934 }
935 if (first != m_edges.size())
936 m_edges.last().to = m_edges.at(first).from;
937 for (int i = 0; i < m_edges.size(); ++i) {
938 m_edges.at(i).originallyPointingUp = m_edges.at(i).pointingUp =
939 m_parent->m_vertices.at(m_edges.at(i).to) < m_parent->m_vertices.at(m_edges.at(i).from);
940 }
941}
942
943// Return true if new intersection was found
944template <typename T>
945bool QTriangulator<T>::ComplexToSimple::calculateIntersection(int left, int right)
946{
947 const Edge &e1 = m_edges.at(left);
948 const Edge &e2 = m_edges.at(right);
949
950 const QPodPoint &u1 = m_parent->m_vertices.at((qint32)e1.from);
951 const QPodPoint &u2 = m_parent->m_vertices.at((qint32)e1.to);
952 const QPodPoint &v1 = m_parent->m_vertices.at((qint32)e2.from);
953 const QPodPoint &v2 = m_parent->m_vertices.at((qint32)e2.to);
954 if (qMax(u1.x, u2.x) <= qMin(v1.x, v2.x))
955 return false;
956
957 quint64 key = (left > right ? (quint64(right) << 32) | quint64(left) : (quint64(left) << 32) | quint64(right));
958 if (m_processedEdgePairs.contains(key))
959 return false;
960 m_processedEdgePairs.insert(key);
961
962 Intersection intersection;
963 intersection.leftEdge = left;
964 intersection.rightEdge = right;
965 intersection.intersectionPoint = QT_PREPEND_NAMESPACE(qIntersectionPoint)(u1, u2, v1, v2);
966
967 if (!intersection.intersectionPoint.isValid())
968 return false;
969
970 Q_ASSERT(intersection.intersectionPoint.isOnLine(u1, u2));
971 Q_ASSERT(intersection.intersectionPoint.isOnLine(v1, v2));
972
973 intersection.vertex = m_parent->m_vertices.size();
974 m_topIntersection.push(intersection);
975 m_parent->m_vertices.add(intersection.intersectionPoint.round());
976 return true;
977}
978
979template <typename T>
980bool QTriangulator<T>::ComplexToSimple::edgeIsLeftOfEdge(int leftEdgeIndex, int rightEdgeIndex) const
981{
982 const Edge &leftEdge = m_edges.at(leftEdgeIndex);
983 const Edge &rightEdge = m_edges.at(rightEdgeIndex);
984 const QPodPoint &u = m_parent->m_vertices.at(rightEdge.upper());
985 const QPodPoint &l = m_parent->m_vertices.at(rightEdge.lower());
986 const QPodPoint &upper = m_parent->m_vertices.at(leftEdge.upper());
987 if (upper.x < qMin(l.x, u.x))
988 return true;
989 if (upper.x > qMax(l.x, u.x))
990 return false;
991 qint64 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(upper, l, u);
992 // d < 0: left, d > 0: right, d == 0: on top
993 if (d == 0)
994 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(m_parent->m_vertices.at(leftEdge.lower()), l, u);
995 return d < 0;
996}
997
998template <typename T>
999QRBTree<int>::Node *QTriangulator<T>::ComplexToSimple::searchEdgeLeftOf(int edgeIndex) const
1000{
1001 QRBTree<int>::Node *current = m_edgeList.root;
1002 QRBTree<int>::Node *result = nullptr;
1003 while (current) {
1004 if (edgeIsLeftOfEdge(edgeIndex, current->data)) {
1005 current = current->left;
1006 } else {
1007 result = current;
1008 current = current->right;
1009 }
1010 }
1011 return result;
1012}
1013
1014template <typename T>
1015QRBTree<int>::Node *QTriangulator<T>::ComplexToSimple::searchEdgeLeftOf(int edgeIndex, QRBTree<int>::Node *after) const
1016{
1017 if (!m_edgeList.root)
1018 return after;
1019 QRBTree<int>::Node *result = after;
1020 QRBTree<int>::Node *current = (after ? m_edgeList.next(after) : m_edgeList.front(m_edgeList.root));
1021 while (current) {
1022 if (edgeIsLeftOfEdge(edgeIndex, current->data))
1023 return result;
1024 result = current;
1025 current = m_edgeList.next(current);
1026 }
1027 return result;
1028}
1029
1030template <typename T>
1031std::pair<QRBTree<int>::Node *, QRBTree<int>::Node *> QTriangulator<T>::ComplexToSimple::bounds(const QPodPoint &point) const
1032{
1033 QRBTree<int>::Node *current = m_edgeList.root;
1034 std::pair<QRBTree<int>::Node *, QRBTree<int>::Node *> result(nullptr, nullptr);
1035 while (current) {
1036 const QPodPoint &v1 = m_parent->m_vertices.at(m_edges.at(current->data).lower());
1037 const QPodPoint &v2 = m_parent->m_vertices.at(m_edges.at(current->data).upper());
1038 qint64 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(point, v1, v2);
1039 if (d == 0) {
1040 result.first = result.second = current;
1041 break;
1042 }
1043 current = (d < 0 ? current->left : current->right);
1044 }
1045 if (current == nullptr)
1046 return result;
1047
1048 current = result.first->left;
1049 while (current) {
1050 const QPodPoint &v1 = m_parent->m_vertices.at(m_edges.at(current->data).lower());
1051 const QPodPoint &v2 = m_parent->m_vertices.at(m_edges.at(current->data).upper());
1052 qint64 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(point, v1, v2);
1053 Q_ASSERT(d >= 0);
1054 if (d == 0) {
1055 result.first = current;
1056 current = current->left;
1057 } else {
1058 current = current->right;
1059 }
1060 }
1061
1062 current = result.second->right;
1063 while (current) {
1064 const QPodPoint &v1 = m_parent->m_vertices.at(m_edges.at(current->data).lower());
1065 const QPodPoint &v2 = m_parent->m_vertices.at(m_edges.at(current->data).upper());
1066 qint64 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(point, v1, v2);
1067 Q_ASSERT(d <= 0);
1068 if (d == 0) {
1069 result.second = current;
1070 current = current->right;
1071 } else {
1072 current = current->left;
1073 }
1074 }
1075
1076 return result;
1077}
1078
1079template <typename T>
1080std::pair<QRBTree<int>::Node *, QRBTree<int>::Node *> QTriangulator<T>::ComplexToSimple::outerBounds(const QPodPoint &point) const
1081{
1082 QRBTree<int>::Node *current = m_edgeList.root;
1083 std::pair<QRBTree<int>::Node *, QRBTree<int>::Node *> result(nullptr, nullptr);
1084
1085 while (current) {
1086 const QPodPoint &v1 = m_parent->m_vertices.at(m_edges.at(current->data).lower());
1087 const QPodPoint &v2 = m_parent->m_vertices.at(m_edges.at(current->data).upper());
1088 qint64 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(point, v1, v2);
1089 if (d == 0)
1090 break;
1091 if (d < 0) {
1092 result.second = current;
1093 current = current->left;
1094 } else {
1095 result.first = current;
1096 current = current->right;
1097 }
1098 }
1099
1100 if (!current)
1101 return result;
1102
1103 QRBTree<int>::Node *mid = current;
1104
1105 current = mid->left;
1106 while (current) {
1107 const QPodPoint &v1 = m_parent->m_vertices.at(m_edges.at(current->data).lower());
1108 const QPodPoint &v2 = m_parent->m_vertices.at(m_edges.at(current->data).upper());
1109 qint64 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(point, v1, v2);
1110 Q_ASSERT(d >= 0);
1111 if (d == 0) {
1112 current = current->left;
1113 } else {
1114 result.first = current;
1115 current = current->right;
1116 }
1117 }
1118
1119 current = mid->right;
1120 while (current) {
1121 const QPodPoint &v1 = m_parent->m_vertices.at(m_edges.at(current->data).lower());
1122 const QPodPoint &v2 = m_parent->m_vertices.at(m_edges.at(current->data).upper());
1123 qint64 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(point, v1, v2);
1124 Q_ASSERT(d <= 0);
1125 if (d == 0) {
1126 current = current->right;
1127 } else {
1128 result.second = current;
1129 current = current->left;
1130 }
1131 }
1132
1133 return result;
1134}
1135
1136template <typename T>
1137void QTriangulator<T>::ComplexToSimple::splitEdgeListRange(QRBTree<int>::Node *leftmost, QRBTree<int>::Node *rightmost, int vertex, const QIntersectionPoint &intersectionPoint)
1138{
1139 Q_ASSERT(leftmost && rightmost);
1140
1141 // Split.
1142 for (;;) {
1143 const QPodPoint &u = m_parent->m_vertices.at(m_edges.at(leftmost->data).from);
1144 const QPodPoint &v = m_parent->m_vertices.at(m_edges.at(leftmost->data).to);
1145 Q_ASSERT(intersectionPoint.isOnLine(u, v));
1146 const Split split = {vertex, leftmost->data, intersectionPoint.isAccurate()};
1147 if (intersectionPoint.xOffset.numerator != 0 || intersectionPoint.yOffset.numerator != 0 || (intersectionPoint.upperLeft != u && intersectionPoint.upperLeft != v))
1148 m_splits.add(split);
1149 if (leftmost == rightmost)
1150 break;
1151 leftmost = m_edgeList.next(leftmost);
1152 }
1153}
1154
1155template <typename T>
1156void QTriangulator<T>::ComplexToSimple::reorderEdgeListRange(QRBTree<int>::Node *leftmost, QRBTree<int>::Node *rightmost)
1157{
1158 Q_ASSERT(leftmost && rightmost);
1159
1160 QRBTree<int>::Node *storeLeftmost = leftmost;
1161 QRBTree<int>::Node *storeRightmost = rightmost;
1162
1163 // Reorder.
1164 while (leftmost != rightmost) {
1165 Edge &left = m_edges.at(leftmost->data);
1166 Edge &right = m_edges.at(rightmost->data);
1167 qSwap(left.node, right.node);
1168 qSwap(leftmost->data, rightmost->data);
1169 leftmost = m_edgeList.next(leftmost);
1170 if (leftmost == rightmost)
1171 break;
1172 rightmost = m_edgeList.previous(rightmost);
1173 }
1174
1175 rightmost = m_edgeList.next(storeRightmost);
1176 leftmost = m_edgeList.previous(storeLeftmost);
1177 if (leftmost)
1178 calculateIntersection(leftmost->data, storeLeftmost->data);
1179 if (rightmost)
1180 calculateIntersection(storeRightmost->data, rightmost->data);
1181}
1182
1183template <typename T>
1184void QTriangulator<T>::ComplexToSimple::sortEdgeList(const QPodPoint eventPoint)
1185{
1186 QIntersectionPoint eventPoint2 = QT_PREPEND_NAMESPACE(qIntersectionPoint)(eventPoint);
1187 while (!m_topIntersection.isEmpty() && m_topIntersection.top().intersectionPoint < eventPoint2) {
1188 Intersection intersection = m_topIntersection.pop();
1189
1190 QIntersectionPoint currentIntersectionPoint = intersection.intersectionPoint;
1191 int currentVertex = intersection.vertex;
1192
1193 QRBTree<int>::Node *leftmost = m_edges.at(intersection.leftEdge).node;
1194 QRBTree<int>::Node *rightmost = m_edges.at(intersection.rightEdge).node;
1195
1196 for (;;) {
1197 QRBTree<int>::Node *previous = m_edgeList.previous(leftmost);
1198 if (!previous)
1199 break;
1200 const Edge &edge = m_edges.at(previous->data);
1201 const QPodPoint &u = m_parent->m_vertices.at((qint32)edge.from);
1202 const QPodPoint &v = m_parent->m_vertices.at((qint32)edge.to);
1203 if (!currentIntersectionPoint.isOnLine(u, v)) {
1204 Q_ASSERT(!currentIntersectionPoint.isAccurate() || qCross(currentIntersectionPoint.upperLeft - u, v - u) != 0);
1205 break;
1206 }
1207 leftmost = previous;
1208 }
1209
1210 for (;;) {
1211 QRBTree<int>::Node *next = m_edgeList.next(rightmost);
1212 if (!next)
1213 break;
1214 const Edge &edge = m_edges.at(next->data);
1215 const QPodPoint &u = m_parent->m_vertices.at((qint32)edge.from);
1216 const QPodPoint &v = m_parent->m_vertices.at((qint32)edge.to);
1217 if (!currentIntersectionPoint.isOnLine(u, v)) {
1218 Q_ASSERT(!currentIntersectionPoint.isAccurate() || qCross(currentIntersectionPoint.upperLeft - u, v - u) != 0);
1219 break;
1220 }
1221 rightmost = next;
1222 }
1223
1224 Q_ASSERT(leftmost && rightmost);
1225 splitEdgeListRange(leftmost, rightmost, currentVertex, currentIntersectionPoint);
1226 reorderEdgeListRange(leftmost, rightmost);
1227
1228 while (!m_topIntersection.isEmpty() && m_topIntersection.top().intersectionPoint <= currentIntersectionPoint)
1229 m_topIntersection.pop();
1230
1231#ifdef Q_TRIANGULATOR_DEBUG
1232 DebugDialog dialog(this, intersection.vertex);
1233 dialog.exec();
1234#endif
1235
1236 }
1237}
1238
1239template <typename T>
1240void QTriangulator<T>::ComplexToSimple::fillPriorityQueue()
1241{
1242 m_events.reset();
1243 m_events.reserve(m_edges.size() * 2);
1244 for (int i = 0; i < m_edges.size(); ++i) {
1245 Q_ASSERT(m_edges.at(i).previous == -1 && m_edges.at(i).next == -1);
1246 Q_ASSERT(m_edges.at(i).node == nullptr);
1247 Q_ASSERT(m_edges.at(i).pointingUp == m_edges.at(i).originallyPointingUp);
1248 Q_ASSERT(m_edges.at(i).pointingUp == (m_parent->m_vertices.at(m_edges.at(i).to) < m_parent->m_vertices.at(m_edges.at(i).from)));
1249 // Ignore zero-length edges.
1250 if (m_parent->m_vertices.at(m_edges.at(i).to) != m_parent->m_vertices.at(m_edges.at(i).from)) {
1251 QPodPoint upper = m_parent->m_vertices.at(m_edges.at(i).upper());
1252 QPodPoint lower = m_parent->m_vertices.at(m_edges.at(i).lower());
1253 Event upperEvent = {{upper.x, upper.y}, Event::Upper, i};
1254 Event lowerEvent = {{lower.x, lower.y}, Event::Lower, i};
1255 m_events.add(upperEvent);
1256 m_events.add(lowerEvent);
1257 }
1258 }
1259
1260 std::sort(m_events.data(), m_events.data() + m_events.size());
1261}
1262
1263template <typename T>
1264void QTriangulator<T>::ComplexToSimple::calculateIntersections()
1265{
1266 fillPriorityQueue();
1267
1268 Q_ASSERT(m_topIntersection.empty());
1269 Q_ASSERT(m_edgeList.root == nullptr);
1270
1271 // Find all intersection points.
1272 while (!m_events.isEmpty()) {
1273 Event event = m_events.last();
1274 sortEdgeList(event.point);
1275
1276 // Find all edges in the edge list that contain the current vertex and mark them to be split later.
1277 std::pair<QRBTree<int>::Node *, QRBTree<int>::Node *> range = bounds(event.point);
1278 QRBTree<int>::Node *leftNode = range.first ? m_edgeList.previous(range.first) : nullptr;
1279 int vertex = (event.type == Event::Upper ? m_edges.at(event.edge).upper() : m_edges.at(event.edge).lower());
1280 QIntersectionPoint eventPoint = QT_PREPEND_NAMESPACE(qIntersectionPoint)(event.point);
1281
1282 if (range.first != nullptr) {
1283 splitEdgeListRange(range.first, range.second, vertex, eventPoint);
1284 reorderEdgeListRange(range.first, range.second);
1285 }
1286
1287 // Handle the edges with start or end point in the current vertex.
1288 while (!m_events.isEmpty() && m_events.last().point == event.point) {
1289 event = m_events.last();
1290 m_events.pop_back();
1291 int i = event.edge;
1292
1293 if (m_edges.at(i).node) {
1294 // Remove edge from edge list.
1295 Q_ASSERT(event.type == Event::Lower);
1296 QRBTree<int>::Node *left = m_edgeList.previous(m_edges.at(i).node);
1297 QRBTree<int>::Node *right = m_edgeList.next(m_edges.at(i).node);
1298 m_edgeList.deleteNode(m_edges.at(i).node);
1299 if (!left || !right)
1300 continue;
1301 calculateIntersection(left->data, right->data);
1302 } else {
1303 // Insert edge into edge list.
1304 Q_ASSERT(event.type == Event::Upper);
1305 QRBTree<int>::Node *left = searchEdgeLeftOf(i, leftNode);
1306 m_edgeList.attachAfter(left, m_edges.at(i).node = m_edgeList.newNode());
1307 m_edges.at(i).node->data = i;
1308 QRBTree<int>::Node *right = m_edgeList.next(m_edges.at(i).node);
1309 if (left)
1310 calculateIntersection(left->data, i);
1311 if (right)
1312 calculateIntersection(i, right->data);
1313 }
1314 }
1315 while (!m_topIntersection.isEmpty() && m_topIntersection.top().intersectionPoint <= eventPoint)
1316 m_topIntersection.pop();
1317#ifdef Q_TRIANGULATOR_DEBUG
1318 DebugDialog dialog(this, vertex);
1319 dialog.exec();
1320#endif
1321 }
1322 m_processedEdgePairs.clear();
1323}
1324
1325// Split an edge into two pieces at the given point.
1326// The upper piece is pushed to the end of the 'm_edges' vector.
1327// The lower piece replaces the old edge.
1328// Return the edge whose 'from' is 'pointIndex'.
1329template <typename T>
1330int QTriangulator<T>::ComplexToSimple::splitEdge(int splitIndex)
1331{
1332 const Split &split = m_splits.at(splitIndex);
1333 Edge &lowerEdge = m_edges.at(split.edge);
1334 Q_ASSERT(lowerEdge.node == nullptr);
1335 Q_ASSERT(lowerEdge.previous == -1 && lowerEdge.next == -1);
1336
1337 if (lowerEdge.from == split.vertex)
1338 return split.edge;
1339 if (lowerEdge.to == split.vertex)
1340 return lowerEdge.next;
1341
1342 // Check that angle >= 90 degrees.
1343 //Q_ASSERT(qDot(m_points.at(m_edges.at(edgeIndex).from) - m_points.at(pointIndex),
1344 // m_points.at(m_edges.at(edgeIndex).to) - m_points.at(pointIndex)) <= 0);
1345
1346 Edge upperEdge = lowerEdge;
1347 upperEdge.mayIntersect |= !split.accurate; // The edge may have been split before at an inaccurate split point.
1348 lowerEdge.mayIntersect = !split.accurate;
1349 if (lowerEdge.pointingUp) {
1350 lowerEdge.to = upperEdge.from = split.vertex;
1351 m_edges.add(upperEdge);
1352 return m_edges.size() - 1;
1353 } else {
1354 lowerEdge.from = upperEdge.to = split.vertex;
1355 m_edges.add(upperEdge);
1356 return split.edge;
1357 }
1358}
1359
1360template <typename T>
1361bool QTriangulator<T>::ComplexToSimple::splitEdgesAtIntersections()
1362{
1363 for (int i = 0; i < m_edges.size(); ++i)
1364 m_edges.at(i).mayIntersect = false;
1365 bool checkForNewIntersections = false;
1366 for (int i = 0; i < m_splits.size(); ++i) {
1367 splitEdge(i);
1368 checkForNewIntersections |= !m_splits.at(i).accurate;
1369 }
1370 for (int i = 0; i < m_edges.size(); ++i) {
1371 m_edges.at(i).originallyPointingUp = m_edges.at(i).pointingUp =
1372 m_parent->m_vertices.at(m_edges.at(i).to) < m_parent->m_vertices.at(m_edges.at(i).from);
1373 }
1374 m_splits.reset();
1375 return checkForNewIntersections;
1376}
1377
1378template <typename T>
1379void QTriangulator<T>::ComplexToSimple::insertEdgeIntoVectorIfWanted(ShortArray &orderedEdges, int i)
1380{
1381 // Edges with zero length should not reach this part.
1382 Q_ASSERT(m_parent->m_vertices.at(m_edges.at(i).from) != m_parent->m_vertices.at(m_edges.at(i).to));
1383
1384 // Skip edges with unwanted winding number.
1385 int windingNumber = m_edges.at(i).winding;
1386 if (m_edges.at(i).originallyPointingUp)
1387 ++windingNumber;
1388
1389 // Make sure exactly one fill rule is specified.
1390 Q_ASSERT(((m_parent->m_hint & QVectorPath::WindingFill) != 0) != ((m_parent->m_hint & QVectorPath::OddEvenFill) != 0));
1391
1392 if ((m_parent->m_hint & QVectorPath::WindingFill) && windingNumber != 0 && windingNumber != 1)
1393 return;
1394
1395 // Skip cancelling edges.
1396 if (!orderedEdges.isEmpty()) {
1397 int j = orderedEdges[orderedEdges.size() - 1];
1398 // If the last edge is already connected in one end, it should not be cancelled.
1399 if (m_edges.at(j).next == -1 && m_edges.at(j).previous == -1
1400 && (m_parent->m_vertices.at(m_edges.at(i).from) == m_parent->m_vertices.at(m_edges.at(j).to))
1401 && (m_parent->m_vertices.at(m_edges.at(i).to) == m_parent->m_vertices.at(m_edges.at(j).from))) {
1402 orderedEdges.removeLast();
1403 return;
1404 }
1405 }
1406 orderedEdges.append(i);
1407}
1408
1409template <typename T>
1410void QTriangulator<T>::ComplexToSimple::removeUnwantedEdgesAndConnect()
1411{
1412 Q_ASSERT(m_edgeList.root == nullptr);
1413 // Initialize priority queue.
1414 fillPriorityQueue();
1415
1416 ShortArray orderedEdges;
1417
1418 while (!m_events.isEmpty()) {
1419 Event event = m_events.last();
1420 int edgeIndex = event.edge;
1421
1422 // Check that all the edges in the list crosses the current scanline
1423 //if (m_edgeList.root) {
1424 // for (QRBTree<int>::Node *node = m_edgeList.front(m_edgeList.root); node; node = m_edgeList.next(node)) {
1425 // Q_ASSERT(event.point <= m_points.at(m_edges.at(node->data).lower()));
1426 // }
1427 //}
1428
1429 orderedEdges.clear();
1430 std::pair<QRBTree<int>::Node *, QRBTree<int>::Node *> b = outerBounds(event.point);
1431 if (m_edgeList.root) {
1432 QRBTree<int>::Node *current = (b.first ? m_edgeList.next(b.first) : m_edgeList.front(m_edgeList.root));
1433 // Process edges that are going to be removed from the edge list at the current event point.
1434 while (current != b.second) {
1435 Q_ASSERT(current);
1436 Q_ASSERT(m_edges.at(current->data).node == current);
1437 Q_ASSERT(QT_PREPEND_NAMESPACE(qIntersectionPoint)(event.point).isOnLine(m_parent->m_vertices.at(m_edges.at(current->data).from), m_parent->m_vertices.at(m_edges.at(current->data).to)));
1438 Q_ASSERT(m_parent->m_vertices.at(m_edges.at(current->data).from) == event.point || m_parent->m_vertices.at(m_edges.at(current->data).to) == event.point);
1439 insertEdgeIntoVectorIfWanted(orderedEdges, current->data);
1440 current = m_edgeList.next(current);
1441 }
1442 }
1443
1444 // Remove edges above the event point, insert edges below the event point.
1445 do {
1446 event = m_events.last();
1447 m_events.pop_back();
1448 edgeIndex = event.edge;
1449
1450 // Edges with zero length should not reach this part.
1451 Q_ASSERT(m_parent->m_vertices.at(m_edges.at(edgeIndex).from) != m_parent->m_vertices.at(m_edges.at(edgeIndex).to));
1452
1453 if (m_edges.at(edgeIndex).node) {
1454 Q_ASSERT(event.type == Event::Lower);
1455 Q_ASSERT(event.point == m_parent->m_vertices.at(m_edges.at(event.edge).lower()));
1456 m_edgeList.deleteNode(m_edges.at(edgeIndex).node);
1457 } else {
1458 Q_ASSERT(event.type == Event::Upper);
1459 Q_ASSERT(event.point == m_parent->m_vertices.at(m_edges.at(event.edge).upper()));
1460 QRBTree<int>::Node *left = searchEdgeLeftOf(edgeIndex, b.first);
1461 m_edgeList.attachAfter(left, m_edges.at(edgeIndex).node = m_edgeList.newNode());
1462 m_edges.at(edgeIndex).node->data = edgeIndex;
1463 }
1464 } while (!m_events.isEmpty() && m_events.last().point == event.point);
1465
1466 if (m_edgeList.root) {
1467 QRBTree<int>::Node *current = (b.first ? m_edgeList.next(b.first) : m_edgeList.front(m_edgeList.root));
1468
1469 // Calculate winding number and turn counter-clockwise.
1470 int currentWindingNumber = (b.first ? m_edges.at(b.first->data).winding : 0);
1471 while (current != b.second) {
1472 Q_ASSERT(current);
1473 //Q_ASSERT(b.second == 0 || m_edgeList.order(current, b.second) < 0);
1474 int i = current->data;
1475 Q_ASSERT(m_edges.at(i).node == current);
1476
1477 // Winding number.
1478 int ccwWindingNumber = m_edges.at(i).winding = currentWindingNumber;
1479 if (m_edges.at(i).originallyPointingUp) {
1480 --m_edges.at(i).winding;
1481 } else {
1482 ++m_edges.at(i).winding;
1483 ++ccwWindingNumber;
1484 }
1485 currentWindingNumber = m_edges.at(i).winding;
1486
1487 // Turn counter-clockwise.
1488 if ((ccwWindingNumber & 1) == 0) {
1489 Q_ASSERT(m_edges.at(i).previous == -1 && m_edges.at(i).next == -1);
1490 qSwap(m_edges.at(i).from, m_edges.at(i).to);
1491 m_edges.at(i).pointingUp = !m_edges.at(i).pointingUp;
1492 }
1493
1494 current = m_edgeList.next(current);
1495 }
1496
1497 // Process edges that were inserted into the edge list at the current event point.
1498 current = (b.second ? m_edgeList.previous(b.second) : m_edgeList.back(m_edgeList.root));
1499 while (current != b.first) {
1500 Q_ASSERT(current);
1501 Q_ASSERT(m_edges.at(current->data).node == current);
1502 insertEdgeIntoVectorIfWanted(orderedEdges, current->data);
1503 current = m_edgeList.previous(current);
1504 }
1505 }
1506 if (orderedEdges.isEmpty())
1507 continue;
1508
1509 Q_ASSERT((orderedEdges.size() & 1) == 0);
1510
1511 // Connect edges.
1512 // First make sure the first edge point towards the current point.
1513 int i;
1514 if (m_parent->m_vertices.at(m_edges.at(orderedEdges[0]).from) == event.point) {
1515 i = 1;
1516 int copy = orderedEdges[0]; // Make copy in case the append() will cause a reallocation.
1517 orderedEdges.append(copy);
1518 } else {
1519 Q_ASSERT(m_parent->m_vertices.at(m_edges.at(orderedEdges[0]).to) == event.point);
1520 i = 0;
1521 }
1522
1523 // Remove references to duplicate points. First find the point with lowest index.
1524 int pointIndex = INT_MAX;
1525 for (int j = i; j < orderedEdges.size(); j += 2) {
1526 Q_ASSERT(j + 1 < orderedEdges.size());
1527 Q_ASSERT(m_parent->m_vertices.at(m_edges.at(orderedEdges[j]).to) == event.point);
1528 Q_ASSERT(m_parent->m_vertices.at(m_edges.at(orderedEdges[j + 1]).from) == event.point);
1529 if (m_edges.at(orderedEdges[j]).to < pointIndex)
1530 pointIndex = m_edges.at(orderedEdges[j]).to;
1531 if (m_edges.at(orderedEdges[j + 1]).from < pointIndex)
1532 pointIndex = m_edges.at(orderedEdges[j + 1]).from;
1533 }
1534
1535 for (; i < orderedEdges.size(); i += 2) {
1536 // Remove references to duplicate points by making all edges reference one common point.
1537 m_edges.at(orderedEdges[i]).to = m_edges.at(orderedEdges[i + 1]).from = pointIndex;
1538
1539 Q_ASSERT(m_edges.at(orderedEdges[i]).pointingUp || m_edges.at(orderedEdges[i]).previous != -1);
1540 Q_ASSERT(!m_edges.at(orderedEdges[i + 1]).pointingUp || m_edges.at(orderedEdges[i + 1]).next != -1);
1541
1542 m_edges.at(orderedEdges[i]).next = orderedEdges[i + 1];
1543 m_edges.at(orderedEdges[i + 1]).previous = orderedEdges[i];
1544 }
1545 } // end while
1546}
1547
1548template <typename T>
1549void QTriangulator<T>::ComplexToSimple::removeUnusedPoints() {
1550 QBitArray used(m_parent->m_vertices.size(), false);
1551 for (int i = 0; i < m_edges.size(); ++i) {
1552 Q_ASSERT((m_edges.at(i).previous == -1) == (m_edges.at(i).next == -1));
1553 if (m_edges.at(i).next != -1)
1554 used.setBit(m_edges.at(i).from);
1555 }
1556 QDataBuffer<quint32> newMapping(m_parent->m_vertices.size());
1557 newMapping.resize(m_parent->m_vertices.size());
1558 int count = 0;
1559 for (int i = 0; i < m_parent->m_vertices.size(); ++i) {
1560 if (used.at(i)) {
1561 m_parent->m_vertices.at(count) = m_parent->m_vertices.at(i);
1562 newMapping.at(i) = count;
1563 ++count;
1564 }
1565 }
1566 m_parent->m_vertices.resize(count);
1567 for (int i = 0; i < m_edges.size(); ++i) {
1568 m_edges.at(i).from = newMapping.at(m_edges.at(i).from);
1569 m_edges.at(i).to = newMapping.at(m_edges.at(i).to);
1570 }
1571}
1572
1573template <typename T>
1574inline bool QTriangulator<T>::ComplexToSimple::Event::operator < (const Event &other) const
1575{
1576 if (point == other.point)
1577 return type < other.type; // 'Lower' has higher priority than 'Upper'.
1578 return other.point < point;
1579}
1580
1581//============================================================================//
1582// QTriangulator::ComplexToSimple::DebugDialog //
1583//============================================================================//
1584
1585#ifdef Q_TRIANGULATOR_DEBUG
1586template <typename T>
1587QTriangulator<T>::ComplexToSimple::DebugDialog::DebugDialog(ComplexToSimple *parent, int currentVertex)
1588 : m_parent(parent), m_vertex(currentVertex)
1589{
1590 QDataBuffer<QPodPoint> &vertices = m_parent->m_parent->m_vertices;
1591 if (vertices.isEmpty())
1592 return;
1593
1594 int minX, maxX, minY, maxY;
1595 minX = maxX = vertices.at(0).x;
1596 minY = maxY = vertices.at(0).y;
1597 for (int i = 1; i < vertices.size(); ++i) {
1598 minX = qMin(minX, vertices.at(i).x);
1599 maxX = qMax(maxX, vertices.at(i).x);
1600 minY = qMin(minY, vertices.at(i).y);
1601 maxY = qMax(maxY, vertices.at(i).y);
1602 }
1603 int w = maxX - minX;
1604 int h = maxY - minY;
1605 qreal border = qMin(w, h) / 10.0;
1606 m_window = QRectF(minX - border, minY - border, (maxX - minX + 2 * border), (maxY - minY + 2 * border));
1607}
1608
1609template <typename T>
1610void QTriangulator<T>::ComplexToSimple::DebugDialog::paintEvent(QPaintEvent *)
1611{
1612 QPainter p(this);
1613 p.setRenderHint(QPainter::Antialiasing, true);
1614 p.fillRect(rect(), Qt::black);
1615 QDataBuffer<QPodPoint> &vertices = m_parent->m_parent->m_vertices;
1616 if (vertices.isEmpty())
1617 return;
1618
1619 qreal halfPointSize = qMin(m_window.width(), m_window.height()) / 300.0;
1620 p.setWindow(m_window.toRect());
1621
1622 p.setPen(Qt::white);
1623
1624 QDataBuffer<Edge> &edges = m_parent->m_edges;
1625 for (int i = 0; i < edges.size(); ++i) {
1626 QPodPoint u = vertices.at(edges.at(i).from);
1627 QPodPoint v = vertices.at(edges.at(i).to);
1628 p.drawLine(u.x, u.y, v.x, v.y);
1629 }
1630
1631 for (int i = 0; i < vertices.size(); ++i) {
1632 QPodPoint q = vertices.at(i);
1633 p.fillRect(QRectF(q.x - halfPointSize, q.y - halfPointSize, 2 * halfPointSize, 2 * halfPointSize), Qt::red);
1634 }
1635
1636 Qt::GlobalColor colors[6] = {Qt::red, Qt::green, Qt::blue, Qt::cyan, Qt::magenta, Qt::yellow};
1637 p.setOpacity(0.5);
1638 int count = 0;
1639 if (m_parent->m_edgeList.root) {
1640 QRBTree<int>::Node *current = m_parent->m_edgeList.front(m_parent->m_edgeList.root);
1641 while (current) {
1642 p.setPen(colors[count++ % 6]);
1643 QPodPoint u = vertices.at(edges.at(current->data).from);
1644 QPodPoint v = vertices.at(edges.at(current->data).to);
1645 p.drawLine(u.x, u.y, v.x, v.y);
1646 current = m_parent->m_edgeList.next(current);
1647 }
1648 }
1649
1650 p.setOpacity(1.0);
1651 QPodPoint q = vertices.at(m_vertex);
1652 p.fillRect(QRectF(q.x - halfPointSize, q.y - halfPointSize, 2 * halfPointSize, 2 * halfPointSize), Qt::green);
1653
1654 p.setPen(Qt::gray);
1655 QDataBuffer<Split> &splits = m_parent->m_splits;
1656 for (int i = 0; i < splits.size(); ++i) {
1657 QPodPoint q = vertices.at(splits.at(i).vertex);
1658 QPodPoint u = vertices.at(edges.at(splits.at(i).edge).from) - q;
1659 QPodPoint v = vertices.at(edges.at(splits.at(i).edge).to) - q;
1660 qreal uLen = qSqrt(qDot(u, u));
1661 qreal vLen = qSqrt(qDot(v, v));
1662 if (uLen) {
1663 u.x *= 2 * halfPointSize / uLen;
1664 u.y *= 2 * halfPointSize / uLen;
1665 }
1666 if (vLen) {
1667 v.x *= 2 * halfPointSize / vLen;
1668 v.y *= 2 * halfPointSize / vLen;
1669 }
1670 u += q;
1671 v += q;
1672 p.drawLine(u.x, u.y, v.x, v.y);
1673 }
1674}
1675
1676template <typename T>
1677void QTriangulator<T>::ComplexToSimple::DebugDialog::wheelEvent(QWheelEvent *event)
1678{
1679 qreal scale = qExp(-0.001 * event->delta());
1680 QPointF center = m_window.center();
1681 QPointF delta = scale * (m_window.bottomRight() - center);
1682 m_window = QRectF(center - delta, center + delta);
1683 event->accept();
1684 update();
1685}
1686
1687template <typename T>
1688void QTriangulator<T>::ComplexToSimple::DebugDialog::mouseMoveEvent(QMouseEvent *event)
1689{
1690 if (event->buttons() & Qt::LeftButton) {
1691 QPointF delta = event->pos() - m_lastMousePos;
1692 delta.setX(delta.x() * m_window.width() / width());
1693 delta.setY(delta.y() * m_window.height() / height());
1694 m_window.translate(-delta.x(), -delta.y());
1695 m_lastMousePos = event->pos();
1696 event->accept();
1697 update();
1698 }
1699}
1700
1701template <typename T>
1702void QTriangulator<T>::ComplexToSimple::DebugDialog::mousePressEvent(QMouseEvent *event)
1703{
1704 if (event->button() == Qt::LeftButton)
1705 m_lastMousePos = event->pos();
1706 event->accept();
1707}
1708
1709
1710#endif
1711
1712//============================================================================//
1713// QTriangulator::SimpleToMonotone //
1714//============================================================================//
1715template <typename T>
1717{
1718 setupDataStructures();
1719 removeZeroLengthEdges();
1720 monotoneDecomposition();
1721
1722 m_parent->m_indices.clear();
1723 QBitArray processed(m_edges.size(), false);
1724 for (int first = 0; first < m_edges.size(); ++first) {
1725 if (processed.at(first))
1726 continue;
1727 int i = first;
1728 do {
1729 Q_ASSERT(!processed.at(i));
1730 Q_ASSERT(m_edges.at(m_edges.at(i).next).previous == i);
1731 m_parent->m_indices.push_back(m_edges.at(i).from);
1732 processed.setBit(i);
1733 i = m_edges.at(i).next;
1734 } while (i != first);
1735 if (m_parent->m_indices.size() > 0 && m_parent->m_indices.back() != T(-1)) // Q_TRIANGULATE_END_OF_POLYGON
1736 m_parent->m_indices.push_back(T(-1)); // Q_TRIANGULATE_END_OF_POLYGON
1737 }
1738}
1739
1740template <typename T>
1741void QTriangulator<T>::SimpleToMonotone::setupDataStructures()
1742{
1743 int i = 0;
1744 Edge e;
1745 e.node = nullptr;
1746 e.twin = -1;
1747
1748 while (i + 3 <= m_parent->m_indices.size()) {
1749 int start = m_edges.size();
1750
1751 do {
1752 e.from = m_parent->m_indices.at(i);
1753 e.type = RegularVertex;
1754 e.next = m_edges.size() + 1;
1755 e.previous = m_edges.size() - 1;
1756 m_edges.add(e);
1757 ++i;
1758 Q_ASSERT(i < m_parent->m_indices.size());
1759 } while (m_parent->m_indices.at(i) != T(-1)); // Q_TRIANGULATE_END_OF_POLYGON
1760
1761 m_edges.last().next = start;
1762 m_edges.at(start).previous = m_edges.size() - 1;
1763 ++i; // Skip Q_TRIANGULATE_END_OF_POLYGON.
1764 }
1765
1766 for (i = 0; i < m_edges.size(); ++i) {
1767 m_edges.at(i).to = m_edges.at(m_edges.at(i).next).from;
1768 m_edges.at(i).pointingUp = m_parent->m_vertices.at(m_edges.at(i).to) < m_parent->m_vertices.at(m_edges.at(i).from);
1769 m_edges.at(i).helper = -1; // Not initialized here.
1770 }
1771}
1772
1773template <typename T>
1774void QTriangulator<T>::SimpleToMonotone::removeZeroLengthEdges()
1775{
1776 for (int i = 0; i < m_edges.size(); ++i) {
1777 if (m_parent->m_vertices.at(m_edges.at(i).from) == m_parent->m_vertices.at(m_edges.at(i).to)) {
1778 m_edges.at(m_edges.at(i).previous).next = m_edges.at(i).next;
1779 m_edges.at(m_edges.at(i).next).previous = m_edges.at(i).previous;
1780 m_edges.at(m_edges.at(i).next).from = m_edges.at(i).from;
1781 m_edges.at(i).next = -1; // Mark as removed.
1782 }
1783 }
1784
1785 QDataBuffer<int> newMapping(m_edges.size());
1786 newMapping.resize(m_edges.size());
1787 int count = 0;
1788 for (int i = 0; i < m_edges.size(); ++i) {
1789 if (m_edges.at(i).next != -1) {
1790 m_edges.at(count) = m_edges.at(i);
1791 newMapping.at(i) = count;
1792 ++count;
1793 }
1794 }
1795 m_edges.resize(count);
1796 for (int i = 0; i < m_edges.size(); ++i) {
1797 m_edges.at(i).next = newMapping.at(m_edges.at(i).next);
1798 m_edges.at(i).previous = newMapping.at(m_edges.at(i).previous);
1799 }
1800}
1801
1802template <typename T>
1803void QTriangulator<T>::SimpleToMonotone::fillPriorityQueue()
1804{
1805 m_upperVertex.reset();
1806 m_upperVertex.reserve(m_edges.size());
1807 for (int i = 0; i < m_edges.size(); ++i)
1808 m_upperVertex.add(i);
1809 CompareVertices cmp(this);
1810 std::sort(m_upperVertex.data(), m_upperVertex.data() + m_upperVertex.size(), cmp);
1811 //for (int i = 1; i < m_upperVertex.size(); ++i) {
1812 // Q_ASSERT(!cmp(m_upperVertex.at(i), m_upperVertex.at(i - 1)));
1813 //}
1814}
1815
1816template <typename T>
1817bool QTriangulator<T>::SimpleToMonotone::edgeIsLeftOfEdge(int leftEdgeIndex, int rightEdgeIndex) const
1818{
1819 const Edge &leftEdge = m_edges.at(leftEdgeIndex);
1820 const Edge &rightEdge = m_edges.at(rightEdgeIndex);
1821 const QPodPoint &u = m_parent->m_vertices.at(rightEdge.upper());
1822 const QPodPoint &l = m_parent->m_vertices.at(rightEdge.lower());
1823 qint64 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(m_parent->m_vertices.at(leftEdge.upper()), l, u);
1824 // d < 0: left, d > 0: right, d == 0: on top
1825 if (d == 0)
1826 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(m_parent->m_vertices.at(leftEdge.lower()), l, u);
1827 return d < 0;
1828}
1829
1830// Returns the rightmost edge not to the right of the given edge.
1831template <typename T>
1832QRBTree<int>::Node *QTriangulator<T>::SimpleToMonotone::searchEdgeLeftOfEdge(int edgeIndex) const
1833{
1834 QRBTree<int>::Node *current = m_edgeList.root;
1835 QRBTree<int>::Node *result = nullptr;
1836 while (current) {
1837 if (edgeIsLeftOfEdge(edgeIndex, current->data)) {
1838 current = current->left;
1839 } else {
1840 result = current;
1841 current = current->right;
1842 }
1843 }
1844 return result;
1845}
1846
1847// Returns the rightmost edge left of the given point.
1848template <typename T>
1849QRBTree<int>::Node *QTriangulator<T>::SimpleToMonotone::searchEdgeLeftOfPoint(int pointIndex) const
1850{
1851 QRBTree<int>::Node *current = m_edgeList.root;
1852 QRBTree<int>::Node *result = nullptr;
1853 while (current) {
1854 const QPodPoint &p1 = m_parent->m_vertices.at(m_edges.at(current->data).lower());
1855 const QPodPoint &p2 = m_parent->m_vertices.at(m_edges.at(current->data).upper());
1856 qint64 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(m_parent->m_vertices.at(pointIndex), p1, p2);
1857 if (d <= 0) {
1858 current = current->left;
1859 } else {
1860 result = current;
1861 current = current->right;
1862 }
1863 }
1864 return result;
1865}
1866
1867template <typename T>
1868void QTriangulator<T>::SimpleToMonotone::classifyVertex(int i)
1869{
1870 Edge &e2 = m_edges.at(i);
1871 const Edge &e1 = m_edges.at(e2.previous);
1872
1873 bool startOrSplit = (e1.pointingUp && !e2.pointingUp);
1874 bool endOrMerge = (!e1.pointingUp && e2.pointingUp);
1875
1876 const QPodPoint &p1 = m_parent->m_vertices.at(e1.from);
1877 const QPodPoint &p2 = m_parent->m_vertices.at(e2.from);
1878 const QPodPoint &p3 = m_parent->m_vertices.at(e2.to);
1879 qint64 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(p1, p2, p3);
1880 Q_ASSERT(d != 0 || (!startOrSplit && !endOrMerge));
1881
1882 e2.type = RegularVertex;
1883
1884 if (m_clockwiseOrder) {
1885 if (startOrSplit)
1886 e2.type = (d < 0 ? SplitVertex : StartVertex);
1887 else if (endOrMerge)
1888 e2.type = (d < 0 ? MergeVertex : EndVertex);
1889 } else {
1890 if (startOrSplit)
1891 e2.type = (d > 0 ? SplitVertex : StartVertex);
1892 else if (endOrMerge)
1893 e2.type = (d > 0 ? MergeVertex : EndVertex);
1894 }
1895}
1896
1897template <typename T>
1898void QTriangulator<T>::SimpleToMonotone::classifyVertices()
1899{
1900 for (int i = 0; i < m_edges.size(); ++i)
1901 classifyVertex(i);
1902}
1903
1904template <typename T>
1905bool QTriangulator<T>::SimpleToMonotone::pointIsInSector(const QPodPoint &p, const QPodPoint &v1, const QPodPoint &v2, const QPodPoint &v3)
1906{
1907 bool leftOfPreviousEdge = !qPointIsLeftOfLine(p, v2, v1);
1908 bool leftOfNextEdge = !qPointIsLeftOfLine(p, v3, v2);
1909
1910 if (qPointIsLeftOfLine(v1, v2, v3))
1911 return leftOfPreviousEdge && leftOfNextEdge;
1912 else
1913 return leftOfPreviousEdge || leftOfNextEdge;
1914}
1915
1916template <typename T>
1917bool QTriangulator<T>::SimpleToMonotone::pointIsInSector(int vertex, int sector)
1918{
1919 const QPodPoint &center = m_parent->m_vertices.at(m_edges.at(sector).from);
1920 // Handle degenerate edges.
1921 while (m_parent->m_vertices.at(m_edges.at(vertex).from) == center)
1922 vertex = m_edges.at(vertex).next;
1923 int next = m_edges.at(sector).next;
1924 while (m_parent->m_vertices.at(m_edges.at(next).from) == center)
1925 next = m_edges.at(next).next;
1926 int previous = m_edges.at(sector).previous;
1927 while (m_parent->m_vertices.at(m_edges.at(previous).from) == center)
1928 previous = m_edges.at(previous).previous;
1929
1930 const QPodPoint &p = m_parent->m_vertices.at(m_edges.at(vertex).from);
1931 const QPodPoint &v1 = m_parent->m_vertices.at(m_edges.at(previous).from);
1932 const QPodPoint &v3 = m_parent->m_vertices.at(m_edges.at(next).from);
1933 if (m_clockwiseOrder)
1934 return pointIsInSector(p, v3, center, v1);
1935 else
1936 return pointIsInSector(p, v1, center, v3);
1937}
1938
1939template <typename T>
1940int QTriangulator<T>::SimpleToMonotone::findSector(int edge, int vertex)
1941{
1942 while (!pointIsInSector(vertex, edge)) {
1943 edge = m_edges.at(m_edges.at(edge).previous).twin;
1944 Q_ASSERT(edge != -1);
1945 }
1946 return edge;
1947}
1948
1949template <typename T>
1950void QTriangulator<T>::SimpleToMonotone::createDiagonal(int lower, int upper)
1951{
1952 lower = findSector(lower, upper);
1953 upper = findSector(upper, lower);
1954
1955 int prevLower = m_edges.at(lower).previous;
1956 int prevUpper = m_edges.at(upper).previous;
1957
1958 Edge e = {};
1959
1960 e.twin = m_edges.size() + 1;
1961 e.next = upper;
1962 e.previous = prevLower;
1963 e.from = m_edges.at(lower).from;
1964 e.to = m_edges.at(upper).from;
1965 m_edges.at(upper).previous = m_edges.at(prevLower).next = int(m_edges.size());
1966 m_edges.add(e);
1967
1968 e.twin = m_edges.size() - 1;
1969 e.next = lower;
1970 e.previous = prevUpper;
1971 e.from = m_edges.at(upper).from;
1972 e.to = m_edges.at(lower).from;
1973 m_edges.at(lower).previous = m_edges.at(prevUpper).next = int(m_edges.size());
1974 m_edges.add(e);
1975}
1976
1977template <typename T>
1978void QTriangulator<T>::SimpleToMonotone::monotoneDecomposition()
1979{
1980 if (m_edges.isEmpty())
1981 return;
1982
1983 Q_ASSERT(!m_edgeList.root);
1984 QDataBuffer<std::pair<int, int> > diagonals(m_upperVertex.size());
1985
1986 int i = 0;
1987 for (int index = 1; index < m_edges.size(); ++index) {
1988 if (m_parent->m_vertices.at(m_edges.at(index).from) < m_parent->m_vertices.at(m_edges.at(i).from))
1989 i = index;
1990 }
1991 Q_ASSERT(i < m_edges.size());
1992 int j = m_edges.at(i).previous;
1993 Q_ASSERT(j < m_edges.size());
1994 m_clockwiseOrder = qPointIsLeftOfLine(m_parent->m_vertices.at((quint32)m_edges.at(i).from),
1995 m_parent->m_vertices.at((quint32)m_edges.at(j).from), m_parent->m_vertices.at((quint32)m_edges.at(i).to));
1996
1997 classifyVertices();
1998 fillPriorityQueue();
1999
2000 // debug: set helpers explicitly (shouldn't be necessary)
2001 //for (int i = 0; i < m_edges.size(); ++i)
2002 // m_edges.at(i).helper = m_edges.at(i).upper();
2003
2004 while (!m_upperVertex.isEmpty()) {
2005 i = m_upperVertex.last();
2006 Q_ASSERT(i < m_edges.size());
2007 m_upperVertex.pop_back();
2008 j = m_edges.at(i).previous;
2009 Q_ASSERT(j < m_edges.size());
2010
2011 QRBTree<int>::Node *leftEdgeNode = nullptr;
2012
2013 switch (m_edges.at(i).type) {
2014 case RegularVertex:
2015 // If polygon interior is to the right of the vertex...
2016 if (m_edges.at(i).pointingUp == m_clockwiseOrder) {
2017 if (m_edges.at(i).node) {
2018 Q_ASSERT(!m_edges.at(j).node);
2019 if (m_edges.at(m_edges.at(i).helper).type == MergeVertex)
2020 diagonals.add(std::pair<int, int>(i, m_edges.at(i).helper));
2021 m_edges.at(j).node = m_edges.at(i).node;
2022 m_edges.at(i).node = nullptr;
2023 m_edges.at(j).node->data = j;
2024 m_edges.at(j).helper = i;
2025 } else if (m_edges.at(j).node) {
2026 Q_ASSERT(!m_edges.at(i).node);
2027 if (m_edges.at(m_edges.at(j).helper).type == MergeVertex)
2028 diagonals.add(std::pair<int, int>(i, m_edges.at(j).helper));
2029 m_edges.at(i).node = m_edges.at(j).node;
2030 m_edges.at(j).node = nullptr;
2031 m_edges.at(i).node->data = i;
2032 m_edges.at(i).helper = i;
2033 } else {
2034 qWarning("Inconsistent polygon. (#1)");
2035 }
2036 } else {
2037 leftEdgeNode = searchEdgeLeftOfPoint(m_edges.at(i).from);
2038 if (leftEdgeNode) {
2039 if (m_edges.at(m_edges.at(leftEdgeNode->data).helper).type == MergeVertex)
2040 diagonals.add(std::pair<int, int>(i, m_edges.at(leftEdgeNode->data).helper));
2041 m_edges.at(leftEdgeNode->data).helper = i;
2042 } else {
2043 qWarning("Inconsistent polygon. (#2)");
2044 }
2045 }
2046 break;
2047 case SplitVertex:
2048 leftEdgeNode = searchEdgeLeftOfPoint(m_edges.at(i).from);
2049 if (leftEdgeNode) {
2050 diagonals.add(std::pair<int, int>(i, m_edges.at(leftEdgeNode->data).helper));
2051 m_edges.at(leftEdgeNode->data).helper = i;
2052 } else {
2053 qWarning("Inconsistent polygon. (#3)");
2054 }
2055 Q_FALLTHROUGH();
2056 case StartVertex:
2057 if (m_clockwiseOrder) {
2058 leftEdgeNode = searchEdgeLeftOfEdge(j);
2059 QRBTree<int>::Node *node = m_edgeList.newNode();
2060 node->data = j;
2061 m_edges.at(j).node = node;
2062 m_edges.at(j).helper = i;
2063 m_edgeList.attachAfter(leftEdgeNode, node);
2064 Q_ASSERT(m_edgeList.validate());
2065 } else {
2066 leftEdgeNode = searchEdgeLeftOfEdge(i);
2067 QRBTree<int>::Node *node = m_edgeList.newNode();
2068 node->data = i;
2069 m_edges.at(i).node = node;
2070 m_edges.at(i).helper = i;
2071 m_edgeList.attachAfter(leftEdgeNode, node);
2072 Q_ASSERT(m_edgeList.validate());
2073 }
2074 break;
2075 case MergeVertex:
2076 leftEdgeNode = searchEdgeLeftOfPoint(m_edges.at(i).from);
2077 if (leftEdgeNode) {
2078 if (m_edges.at(m_edges.at(leftEdgeNode->data).helper).type == MergeVertex)
2079 diagonals.add(std::pair<int, int>(i, m_edges.at(leftEdgeNode->data).helper));
2080 m_edges.at(leftEdgeNode->data).helper = i;
2081 } else {
2082 qWarning("Inconsistent polygon. (#4)");
2083 }
2084 Q_FALLTHROUGH();
2085 case EndVertex:
2086 if (m_clockwiseOrder) {
2087 if (m_edges.at(m_edges.at(i).helper).type == MergeVertex)
2088 diagonals.add(std::pair<int, int>(i, m_edges.at(i).helper));
2089 if (m_edges.at(i).node) {
2090 m_edgeList.deleteNode(m_edges.at(i).node);
2091 Q_ASSERT(m_edgeList.validate());
2092 } else {
2093 qWarning("Inconsistent polygon. (#5)");
2094 }
2095 } else {
2096 if (m_edges.at(m_edges.at(j).helper).type == MergeVertex)
2097 diagonals.add(std::pair<int, int>(i, m_edges.at(j).helper));
2098 if (m_edges.at(j).node) {
2099 m_edgeList.deleteNode(m_edges.at(j).node);
2100 Q_ASSERT(m_edgeList.validate());
2101 } else {
2102 qWarning("Inconsistent polygon. (#6)");
2103 }
2104 }
2105 break;
2106 }
2107 }
2108
2109 for (int i = 0; i < diagonals.size(); ++i)
2110 createDiagonal(diagonals.at(i).first, diagonals.at(i).second);
2111}
2112
2113template <typename T>
2114bool QTriangulator<T>::SimpleToMonotone::CompareVertices::operator () (int i, int j) const
2115{
2116 if (m_parent->m_edges.at(i).from == m_parent->m_edges.at(j).from)
2117 return m_parent->m_edges.at(i).type > m_parent->m_edges.at(j).type;
2118 return m_parent->m_parent->m_vertices.at(m_parent->m_edges.at(i).from) >
2119 m_parent->m_parent->m_vertices.at(m_parent->m_edges.at(j).from);
2120}
2121
2122//============================================================================//
2123// QTriangulator::MonotoneToTriangles //
2124//============================================================================//
2125template <typename T>
2127{
2128 QList<T> result;
2129 QDataBuffer<int> stack(m_parent->m_indices.size());
2130 m_first = 0;
2131 // Require at least three more indices.
2132 while (m_first + 3 <= m_parent->m_indices.size()) {
2133 m_length = 0;
2134 while (m_parent->m_indices.at(m_first + m_length) != T(-1)) { // Q_TRIANGULATE_END_OF_POLYGON
2135 ++m_length;
2136 Q_ASSERT(m_first + m_length < m_parent->m_indices.size());
2137 }
2138 if (m_length < 3) {
2139 m_first += m_length + 1;
2140 continue;
2141 }
2142
2143 int minimum = 0;
2144 while (less(next(minimum), minimum))
2145 minimum = next(minimum);
2146 while (less(previous(minimum), minimum))
2147 minimum = previous(minimum);
2148
2149 stack.reset();
2150 stack.add(minimum);
2151 int left = previous(minimum);
2152 int right = next(minimum);
2153 bool stackIsOnLeftSide;
2154 bool clockwiseOrder = leftOfEdge(minimum, left, right);
2155
2156 if (less(left, right)) {
2157 stack.add(left);
2158 left = previous(left);
2159 stackIsOnLeftSide = true;
2160 } else {
2161 stack.add(right);
2162 right = next(right);
2163 stackIsOnLeftSide = false;
2164 }
2165
2166 for (int count = 0; count + 2 < m_length; ++count)
2167 {
2168 Q_ASSERT(stack.size() >= 2);
2169 if (less(left, right)) {
2170 if (stackIsOnLeftSide == false) {
2171 for (int i = 0; i + 1 < stack.size(); ++i) {
2172 result.push_back(indices(stack.at(i + 1)));
2173 result.push_back(indices(left));
2174 result.push_back(indices(stack.at(i)));
2175 }
2176 stack.first() = stack.last();
2177 stack.resize(1);
2178 } else {
2179 while (stack.size() >= 2 && (clockwiseOrder ^ !leftOfEdge(left, stack.at(stack.size() - 2), stack.last()))) {
2180 result.push_back(indices(stack.at(stack.size() - 2)));
2181 result.push_back(indices(left));
2182 result.push_back(indices(stack.last()));
2183 stack.pop_back();
2184 }
2185 }
2186 stack.add(left);
2187 left = previous(left);
2188 stackIsOnLeftSide = true;
2189 } else {
2190 if (stackIsOnLeftSide == true) {
2191 for (int i = 0; i + 1 < stack.size(); ++i) {
2192 result.push_back(indices(stack.at(i)));
2193 result.push_back(indices(right));
2194 result.push_back(indices(stack.at(i + 1)));
2195 }
2196 stack.first() = stack.last();
2197 stack.resize(1);
2198 } else {
2199 while (stack.size() >= 2 && (clockwiseOrder ^ !leftOfEdge(right, stack.last(), stack.at(stack.size() - 2)))) {
2200 result.push_back(indices(stack.last()));
2201 result.push_back(indices(right));
2202 result.push_back(indices(stack.at(stack.size() - 2)));
2203 stack.pop_back();
2204 }
2205 }
2206 stack.add(right);
2207 right = next(right);
2208 stackIsOnLeftSide = false;
2209 }
2210 }
2211
2212 m_first += m_length + 1;
2213 }
2214 m_parent->m_indices = result;
2215}
2216
2217//============================================================================//
2218// qTriangulate //
2219//============================================================================//
2220
2221Q_GUI_EXPORT QTriangleSet qTriangulate(const qreal *polygon,
2222 int count, uint hint, const QTransform &matrix,
2223 bool allowUintIndices)
2224{
2225 QTriangleSet triangleSet;
2226 if (allowUintIndices) {
2227 QTriangulator<quint32> triangulator;
2228 triangulator.initialize(polygon, count, hint, matrix);
2229 QVertexSet<quint32> vertexSet = triangulator.triangulate();
2230 triangleSet.vertices = vertexSet.vertices;
2231 triangleSet.indices.setDataUint(vertexSet.indices);
2232
2233 } else {
2234 QTriangulator<quint16> triangulator;
2235 triangulator.initialize(polygon, count, hint, matrix);
2236 QVertexSet<quint16> vertexSet = triangulator.triangulate();
2237 triangleSet.vertices = vertexSet.vertices;
2238 triangleSet.indices.setDataUshort(vertexSet.indices);
2239 }
2240 return triangleSet;
2241}
2242
2243Q_GUI_EXPORT QTriangleSet qTriangulate(const QVectorPath &path,
2244 const QTransform &matrix, qreal lod, bool allowUintIndices)
2245{
2246 QTriangleSet triangleSet;
2247 // For now systems that support 32-bit index values will always get 32-bit
2248 // index values. This is not necessary ideal since 16-bit would be enough in
2249 // many cases. TODO revisit this at a later point.
2250 if (allowUintIndices) {
2251 QTriangulator<quint32> triangulator;
2252 triangulator.initialize(path, matrix, lod);
2253 QVertexSet<quint32> vertexSet = triangulator.triangulate();
2254 triangleSet.vertices = vertexSet.vertices;
2255 triangleSet.indices.setDataUint(vertexSet.indices);
2256 } else {
2257 QTriangulator<quint16> triangulator;
2258 triangulator.initialize(path, matrix, lod);
2259 QVertexSet<quint16> vertexSet = triangulator.triangulate();
2260 triangleSet.vertices = vertexSet.vertices;
2261 triangleSet.indices.setDataUshort(vertexSet.indices);
2262 }
2263 return triangleSet;
2264}
2265
2266QTriangleSet qTriangulate(const QPainterPath &path,
2267 const QTransform &matrix, qreal lod, bool allowUintIndices)
2268{
2269 QTriangleSet triangleSet;
2270 if (allowUintIndices) {
2271 QTriangulator<quint32> triangulator;
2272 triangulator.initialize(path, matrix, lod);
2273 QVertexSet<quint32> vertexSet = triangulator.triangulate();
2274 triangleSet.vertices = vertexSet.vertices;
2275 triangleSet.indices.setDataUint(vertexSet.indices);
2276 } else {
2277 QTriangulator<quint16> triangulator;
2278 triangulator.initialize(path, matrix, lod);
2279 QVertexSet<quint16> vertexSet = triangulator.triangulate();
2280 triangleSet.vertices = vertexSet.vertices;
2281 triangleSet.indices.setDataUshort(vertexSet.indices);
2282 }
2283 return triangleSet;
2284}
2285
2286QPolylineSet qPolyline(const QVectorPath &path,
2287 const QTransform &matrix, qreal lod, bool allowUintIndices)
2288{
2289 QPolylineSet polyLineSet;
2290 if (allowUintIndices) {
2291 QTriangulator<quint32> triangulator;
2292 triangulator.initialize(path, matrix, lod);
2293 QVertexSet<quint32> vertexSet = triangulator.polyline();
2294 polyLineSet.vertices = vertexSet.vertices;
2295 polyLineSet.indices.setDataUint(vertexSet.indices);
2296 } else {
2297 QTriangulator<quint16> triangulator;
2298 triangulator.initialize(path, matrix, lod);
2299 QVertexSet<quint16> vertexSet = triangulator.polyline();
2300 polyLineSet.vertices = vertexSet.vertices;
2301 polyLineSet.indices.setDataUshort(vertexSet.indices);
2302 }
2303 return polyLineSet;
2304}
2305
2306QPolylineSet qPolyline(const QPainterPath &path,
2307 const QTransform &matrix, qreal lod, bool allowUintIndices)
2308{
2309 QPolylineSet polyLineSet;
2310 if (allowUintIndices) {
2311 QTriangulator<quint32> triangulator;
2312 triangulator.initialize(path, matrix, lod);
2313 QVertexSet<quint32> vertexSet = triangulator.polyline();
2314 polyLineSet.vertices = vertexSet.vertices;
2315 polyLineSet.indices.setDataUint(vertexSet.indices);
2316 } else {
2317 QTriangulator<quint16> triangulator;
2318 triangulator.initialize(path, matrix, lod);
2319 QVertexSet<quint16> vertexSet = triangulator.polyline();
2320 polyLineSet.vertices = vertexSet.vertices;
2321 polyLineSet.indices.setDataUshort(vertexSet.indices);
2322 }
2323 return polyLineSet;
2324}
2325
2326QT_END_NAMESPACE
2327
2328#undef Q_FIXED_POINT_SCALE
bool isValid() const
void insert(quint64 key)
bool contains(quint64 key) const
void push(const T &x)
bool isEmpty() const
bool empty() const
const T & top() const
int size() const
ComplexToSimple(QTriangulator< T > *parent)
MonotoneToTriangles(QTriangulator< T > *parent)
SimpleToMonotone(QTriangulator< T > *parent)
QVarLengthArray< int, 6 > ShortArray
void initialize(const qreal *polygon, int count, uint hint, const QTransform &matrix)
QVertexSet< T > polyline()
void initialize(const QVectorPath &path, const QTransform &matrix, qreal lod)
QVertexSet< T > triangulate()
Combined button and popup list for selecting options.
#define Q_FIXED_POINT_SCALE
static int primeForCount(int count)
static QIntersectionPoint qIntersectionPoint(const QPodPoint &u1, const QPodPoint &u2, const QPodPoint &v1, const QPodPoint &v2)
static int compare(quint64 a, quint64 b)
static QIntersectionPoint qIntersectionPoint(const QPodPoint &point)
static QFraction qFraction(quint64 n, quint64 d)
static qint64 qCross(const QPodPoint &u, const QPodPoint &v)
QPolylineSet qPolyline(const QVectorPath &path, const QTransform &matrix, qreal lod, bool allowUintIndices)
QTriangleSet qTriangulate(const QPainterPath &path, const QTransform &matrix, qreal lod, bool allowUintIndices)
static quint64 gcd(quint64 x, quint64 y)
static int qCompareFractions(quint64 a, quint64 b, quint64 c, quint64 d)
static qint64 qPointDistanceFromLine(const QPodPoint &p, const QPodPoint &v1, const QPodPoint &v2)
static bool qPointIsLeftOfLine(const QPodPoint &p, const QPodPoint &v1, const QPodPoint &v2)
bool operator<=(const QFraction &other) const
bool isValid() const
bool operator!=(const QFraction &other) const
bool operator>(const QFraction &other) const
bool operator<(const QFraction &other) const
quint64 denominator
bool operator>=(const QFraction &other) const
quint64 numerator
bool operator==(const QFraction &other) const
bool operator<(const QIntersectionPoint &other) const
bool operator>(const QIntersectionPoint &other) const
bool isOnLine(const QPodPoint &u, const QPodPoint &v) const
bool operator>=(const QIntersectionPoint &other) const
QPodPoint round() const
bool operator<=(const QIntersectionPoint &other) const
bool operator==(const QIntersectionPoint &other) const
bool operator!=(const QIntersectionPoint &other) const
bool isAccurate() const
bool operator>=(const QPodPoint &other) const
QPodPoint & operator+=(const QPodPoint &other)
QPodPoint operator-(const QPodPoint &other) const
QPodPoint operator+(const QPodPoint &other) const
bool operator!=(const QPodPoint &other) const
QPodPoint & operator-=(const QPodPoint &other)
bool operator<=(const QPodPoint &other) const
bool operator>(const QPodPoint &other) const
bool operator<(const QPodPoint &other) const
bool operator==(const QPodPoint &other) const