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