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