22#define QDEBUG if (1
){} else qDebug
137 enum { default_alloc = 32 };
201 void addIntersection(
const Edge *e1,
const Edge *e2);
246 return (((qint64) ((quint64) a ^ (quint64) b)) >= 0 );
257 qint64 det = a1 * b2 - a2 * b1;
268 QDEBUG() <<
" " << r3 << r4;
269 if (r3 != 0 && r4 != 0 && sameSign( r3, r4 ))
279 QDEBUG() <<
" " << r1 << r2;
280 if (r1 != 0 && r2 != 0 && sameSign( r1, r2 ))
286 qint64 offset = det < 0 ? -det : det;
289 qint64 num = a2 * c1 - a1 * c2;
290 *y = ( num < 0 ? num - offset : num + offset ) / det;
292 *det_positive = (det > 0);
309 qint64 det = a1 * b2 - a2 * b1;
323 qint64 offset = det < 0 ? -det : det;
326 qint64 num = a2 * c1 - a1 * c2;
327 qint64 yi = ( num < 0 ? num - offset : num + offset ) / det;
330 return ((yi > y) ^ (det < 0));
371 if (!
edges || maxActiveEdges > default_alloc) {
372 max_edges = maxActiveEdges;
373 int s = qMax(maxActiveEdges + 1, default_alloc + 1);
374 edges = q_check_ptr((Edge **)realloc(edges, s*
sizeof(Edge *)));
375 edge_table = q_check_ptr((Edge *)realloc(edge_table, s*
sizeof(Edge)));
376 old = q_check_ptr((Edge **)realloc(old, s*
sizeof(Edge *)));
381 for (
int i = 0; i < maxActiveEdges; ++i)
382 edge_table[i]
.edge = i+1;
383 edge_table[maxActiveEdges]
.edge = -1;
388 if (max_edges > default_alloc) {
410 int pos = min + ((max - min + 1) >> 1);
427 int pos = min + ((max - min) >> 1);
441 for (
int i = 0; i <
size; ++i) {
443 if (item_edge == edge)
452 for (
int i = 0; i <
size; ++i) {
478 (*e)
->edge = first_unused;
479 first_unused = (*e - edge_table);
487 Edge *edge = edge_table + first_unused;
488 first_unused = edge
->edge;
489 Q_ASSERT(first_unused != -1);
509 for (
int i = pos1; i <= pos2; ++i)
534 storage = q_check_ptr((Vertex *)realloc(storage, size*
sizeof(Vertex)));
535 sorted = q_check_ptr((Vertex **)realloc(sorted, size*
sizeof(Vertex *)));
577 qreal xmin(points[0].x());
578 qreal xmax(points[0].x());
579 qreal ymin(points[0].y());
580 qreal ymax(points[0].y());
599 xmin = qMin(xmin, points[i+1].x());
600 xmax = qMax(xmax, points[i+1].x());
601 ymin = qMin(ymin, points[i+1].y());
602 ymax = qMax(ymax, points[i+1].y());
608 if (v
->x == x_next && v
->y == y_next) {
616 else if (y_prev > y_curr)
622 *maxActiveEdges += 2;
628 else if (y_prev > y_curr)
636 else if (y_curr > y_next)
643 *maxActiveEdges += 2;
652 QDEBUG() <<
"maxActiveEdges=" << *maxActiveEdges;
656 return QRectF(xmin, ymin, xmax-xmin, ymax-ymin);
699 int testListSize = 0;
705 if (testListSize > tlSize - 2) {
706 tlSize = qMax(tlSize*2, 16);
707 tl = q_check_ptr((QCoincidingEdge *)realloc(tl, tlSize*
sizeof(QCoincidingEdge)));
710 tl[testListSize]
.start = n;
712 tl[testListSize]
.used =
false;
713 tl[testListSize]
.before =
true;
717 tl[testListSize]
.start = n;
719 tl[testListSize]
.used =
false;
720 tl[testListSize]
.before =
false;
728 std::sort(tl, tl + testListSize);
731QT_WARNING_DISABLE_CLANG(
"-Wfor-loop-analysis")
732 for (
int j = 0; j < testListSize; ++j) {
736 for (
int k = j + 1; k < testListSize; ++k) {
737 if (tl[j].end->x != tl[k].end->x
738 || tl[j].end->y != tl[k].end->y
742 if (!winding || tl[j].before != tl[k].before) {
743 cancelEdges(tl[j], tl[k]);
820 QDEBUG() <<
"PROCESS INTERSECTIONS";
828 QDEBUG() <<
" swapping intersecting edges ";
841 min = qMin(edgePos, min);
842 max = qMax(edgePos, max);
858 Q_ASSERT(min != max);
859 QDEBUG() <<
"sorting between" << min <<
"and" << max <<
"xpos=" << xmin << xmax;
861 QDEBUG() <<
" adding edge on left";
865 QDEBUG() <<
" adding edge on right";
871 for (
int i = min; i <= max; ++i)
872 QDEBUG() <<
" " << scanline.edges[i]->edge <<
"at pos" << i;
874 for (
int i = min; i <= max; ++i) {
929 QDEBUG() <<
" adding edge" << start <<
"at position" << pos;
953 Q_ASSERT(v
->y == next
->y);
969static void checkLinkChain(
const QTessellatorPrivate::Intersections &intersections,
970 QTessellatorPrivate::Intersection i)
975 QTessellatorPrivate::IntersectionLink l = intersections.value(i);
979 Q_ASSERT(l.next != -1);
980 Q_ASSERT(l.prev != -1);
982 QTessellatorPrivate::Intersection i2 = i;
984 QTessellatorPrivate::IntersectionLink l2 = intersections.value(i2);
986 Q_ASSERT(l2.next != -1);
987 Q_ASSERT(l2.prev != -1);
988 Q_ASSERT(l.next == i2.edge);
989 Q_ASSERT(l2.prev == i.edge);
1004 Q_ASSERT(l
.next != -1);
1005 Q_ASSERT(l
.prev != -1);
1012 Q_ASSERT(l2
.next != -1);
1013 Q_ASSERT(l2
.prev != -1);
1039 QDEBUG() <<
" no intersection";
1047 QDEBUG() <<
" ----->>>>>> WRONG ORDER!";
1069 checkLinkChain(intersections, i1);
1070 checkLinkChain(intersections, i2);
1071 Q_ASSERT(edgeInChain(i1, i2.edge));
1074 }
else if (link1
.next == -1 || link2
.next == -1) {
1075 if (link2
.next == -1) {
1077 qSwap(link1, link2);
1079 Q_ASSERT(link1
.next == -1);
1081 checkLinkChain(intersections, i2);
1092 Q_ASSERT(link
.prev != -1);
1096 bool connected = edgeInChain(i1, i2
.edge);
1100 checkLinkChain(intersections, i1);
1101 checkLinkChain(intersections, i2);
1126 checkLinkChain(intersections, i1);
1127 checkLinkChain(intersections, i2);
1128 Q_ASSERT(edgeInChain(i1, i2.edge));
1138 QDEBUG() <<
"INTERSECTIONS";
1141 for (
int i = 0; i < scanline.size; ++i) {
1142 Edge *e = scanline.edges[i];
1143 QDEBUG() <<
" " << i << e->edge <<
"isect=(" << e->intersect_left << e->intersect_right
1153 addIntersection(e1, e2);
1157 if (intersections.constBegin().key().y == y) {
1158 QDEBUG() <<
"----------------> intersection on same line";
1159 scanline.clearMarks();
1160 scanline.processIntersections(y, &intersections);
1185 Q_ASSERT(points[0] == points[nPoints-1]);
1189 QDEBUG()<<
"POINTS:";
1190 for (
int i = 0; i < nPoints; ++i) {
1191 QDEBUG() << points[i];
1199 int maxActiveEdges = 0;
1200 QRectF br = d->collectAndSortVertices(points, &maxActiveEdges);
1204 QDEBUG() <<
"nPoints = " << nPoints <<
"using " << d->vertices.nPoints;
1205 QDEBUG()<<
"VERTICES:";
1206 for (
int i = 0; i < d->vertices.nPoints; ++i) {
1207 QDEBUG() <<
" " << i <<
": "
1208 <<
"point=" << d->vertices.position(d->vertices.sorted[i])
1209 <<
"flags=" << d->vertices.sorted[i]->flags
1210 <<
"pos=(" << Q27Dot5ToDouble(d->vertices.sorted[i]->x) <<
'/'
1211 << Q27Dot5ToDouble(d->vertices.sorted[i]->y) <<
')';
1237 QDEBUG()<<
"===== edges:";
1238 for (
int i = 0; i < d->scanline.size; ++i) {
1239 QDEBUG() <<
" " << d->scanline.edges[i]->edge
1240 <<
"p0= (" << Q27Dot5ToDouble(d->scanline.edges[i]->v0->x)
1241 <<
'/' << Q27Dot5ToDouble(d->scanline.edges[i]->v0->y)
1242 <<
") p1= (" << Q27Dot5ToDouble(d->scanline.edges[i]->v1->x)
1243 <<
'/' << Q27Dot5ToDouble(d->scanline.edges[i]->v1->y) <<
')'
1244 <<
"x=" << Q27Dot5ToDouble(d->scanline.edges[i]->positionAt(d->y))
1246 << ((i < d->scanline.size - 1)
1247 ? d->scanline.edges[i]->isLeftOf(*d->scanline.edges[i+1], d->y)
1261 Q_ASSERT(points[0] == points[nPoints-1]);
1267 for (
int i = 0; i < nPoints; ++i) {
1272 int left = 0, right = 0;
1275 for (
int i = 1; i < nPoints; ++i) {
1280 left = (top + nPoints - 1) % nPoints;
1281 right = (top + 1) % nPoints;
1284 left = (left + nPoints - 1) % nPoints;
1287 right = (right + 1) % nPoints;
1303 if (cross < 0 || (cross == 0 && dLeft
.x > 0)) {
1315 left = (left + nPoints - dir) % nPoints;
1320 right = (right + nPoints + dir) % nPoints;
1340 right = (right + nPoints + dir) % nPoints;
1346 left = (left + nPoints - dir) % nPoints;
1359 QPointF pa = a_, pb = b_;
1368 if (delta
.x == 0 && delta
.y == 0)
1371 qreal hw = 0.5 * width;
1381 Vertex bottomLeft = { a
.x - halfWidth, b
.y };
1382 Vertex bottomRight = { a
.x + halfWidth, b
.y };
1386 }
else if (delta
.y == 0) {
1397 Vertex bottomLeft = { a
.x, a
.y + halfWidth };
1398 Vertex bottomRight = { b
.x, a
.y + halfWidth };
1403 QPointF perp(pb.y() - pa.y(), pa.x() - pb.x());
1404 qreal length = qSqrt(perp.x() * perp.x() + perp.y() * perp.y());
1406 if (qFuzzyIsNull(length))
1410 perp *= hw / length;
1412 QPointF pta = pa + perp;
1413 QPointF ptb = pa - perp;
1414 QPointF ptc = pb - perp;
1415 QPointF ptd = pb + perp;
bool operator()(const Edge *e1, const Edge *e2)
void insert(int pos, const Edge &e)
int findEdgePosition(Q27Dot5 x, Q27Dot5 y) const
void markEdges(int pos1, int pos2)
int findEdge(int edge) const
void swap(int p1, int p2)
int findEdgePosition(const Edge &e) const
void init(int maxActiveEdges)
void processIntersections()
QRectF collectAndSortVertices(const QPointF *points, int *maxActiveEdges)
QMap< Intersection, IntersectionLink > Intersections
Intersections intersections
void cancelCoincidingEdges()
void emitEdges(QTessellator *tessellator)
void tessellateConvex(const QPointF *points, int nPoints)
void tessellateRect(const QPointF &a, const QPointF &b, qreal width)
QRectF tessellate(const QPointF *points, int nPoints)
virtual void addTrap(const Trapezoid &trap)=0
static bool compareVertex(const QTessellatorPrivate::Vertex *p1, const QTessellatorPrivate::Vertex *p2)
static const bool emit_clever
static void cancelEdges(QCoincidingEdge &e1, QCoincidingEdge &e2)
static const bool mark_clever
static void fillTrapezoid(Q27Dot5 y1, Q27Dot5 y2, int left, int right, const QTessellatorPrivate::Vertices &vertices, QTessellator::Trapezoid *trap)
static bool sameSign(qint64 a, qint64 b)
#define FloatToQ27Dot5(i)
#define Q27Dot5ToDouble(i)
bool operator<(const QCoincidingEdge &e2) const
QTessellatorPrivate::Vertex * start
QTessellatorPrivate::Vertex * end
Edge(const Vertices &v, int _edge)
bool intersect(const Edge &other, Q27Dot5 *y, bool *det_positive) const
bool isLeftOf(const Edge &other, Q27Dot5 y) const
Q27Dot5 positionAt(Q27Dot5 y) const
bool operator<(const Intersection &other) const
int nextPos(const Vertex *v) const
void init(int maxVertices)
int position(const Vertex *v) const
const Vertex * operator[](int i) const
Vertex * operator[](int i)
int prevPos(const Vertex *v) const
const Vertex * next(const Vertex *v) const
const Vertex * prev(const Vertex *v) const
const Vertex * bottomRight
const Vertex * bottomLeft