blob: 4821e69c4dafdc93b0b61de1f4187d70e5c9e61d [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
turk@google.com6f8491b2009-03-13 22:05:46 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2009 The Android Open Source Project
turk@google.com6f8491b2009-03-13 22:05:46 +00004 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
turk@google.com6f8491b2009-03-13 22:05:46 +00007 */
8
9
epoger@google.comec3ed6a2011-07-28 14:26:00 +000010
turk@google.com6f8491b2009-03-13 22:05:46 +000011////////////////////////////////////////////////////////////////////////////////
12// This is an implementation of the triangulation algorithm described by Alain
13// Fournier and Delfin Montuno, in "Triangulating Simple Polygons and Equivalent
14// Problems", in the ACM Transactions on Graphics, vol. 3, no. 2, April 1984,
15// pp. 153-174.
16//
17// No new vertices are created in the triangulation: triangles are constructed
18// only from the points in the original polygon, so there is no possibility for
19// cracks to develop from finite precision arithmetic.
20////////////////////////////////////////////////////////////////////////////////
21
22// TODO:
23// - RemoveDegenerateTrapezoids() was added to make the code robust, but it
24// unfortunately introduces T-vertices. Make it robust without T-vertices.
25// - It should be easy enough to detect whether the outer contour is right- or
26// left-handed by looking at the top vertex, which is available in the
27// pre-sort during trapezoidization. Use this information in angleIsConvex()
28// to allowed either handedness outer contour. In either case, though, holes
29// need to have the opposite orientation.
30// - SkTHeapSort was broken, so I wrote a bubble sort so that I could make other
31// things work. Use SkQSort() instead.
32// - The ActiveTrapezoid array does a linear search which is O(n) inefficient.
33// Use SkSearch to implement O(log n) binary search and insertion sort.
34// - There is no need to use SkTDArray for everything. Use SkAutoTMalloc for
35// everything else.
36
caryclark@google.com803eceb2012-06-06 12:09:34 +000037#include "SkConcaveToTriangles.h"
turk@google.com6f8491b2009-03-13 22:05:46 +000038#include "SkTDArray.h"
39#include "SkGeometry.h"
40#include "SkTSort.h"
41
42// This is used to prevent runaway code bugs, and can probably be removed after
43// the code has been proven robust.
44#define kMaxCount 1000
45
46#define DEBUG
47#ifdef DEBUG
48//------------------------------------------------------------------------------
49// Debugging support
50//------------------------------------------------------------------------------
51
52#include <cstdio>
53#include <stdarg.h>
54
55static int gDebugLevel = 0; // This enables debug reporting.
56
57static void DebugPrintf(const char *format, ...) {
58 if (gDebugLevel > 0) {
59 va_list ap;
60 va_start(ap, format);
61 vprintf(format, ap);
62 va_end(ap);
63 }
64}
65
66static void FailureMessage(const char *format, ...) {
67 if (1) {
68 printf("FAILURE: ");
69 va_list ap;
70 va_start(ap, format);
71 vprintf(format, ap);
72 va_end(ap);
73 }
74}
75#else // !DEBUG
76inline void DebugPrintf(const char *format, ...) {}
77inline void FailureMessage(const char *format, ...) {}
78#endif // DEBUG
79
80
81// Forward declaration.
82class Vertex;
83
84
85//------------------------------------------------------------------------------
86// The Trapezoid (actually, up to two of them) is embedded into a Vertex, whose
87// point() provides the top of the Trapezoid, whereas the bottom, and the left
88// and right edges, are stored in the Trapezoid. The edges are represented by
89// their tail point; the head is the successive point modulo the number of
90// points in the polygon. Only the Y coordinate of the top and bottom are
91// relevant.
92//------------------------------------------------------------------------------
93class Trapezoid {
94public:
95 const Vertex* left() const { return fLeft; }
96 const Vertex* right() const { return fRight; }
97 const Vertex* bottom() const { return fBottom; }
98 Vertex* left() { return fLeft; }
99 Vertex* right() { return fRight; }
100 Vertex* bottom() { return fBottom; }
101 void setLeft(Vertex *left) { fLeft = left; }
102 void setRight(Vertex *right) { fRight = right; }
103 void setBottom(Vertex *bottom) { fBottom = bottom; }
104 void nullify() { setBottom(NULL); }
105
106 bool operator<(Trapezoid &t1) { return compare(t1) < 0; }
107 bool operator>(Trapezoid &t1) { return compare(t1) > 0; }
108
109private:
110 Vertex *fLeft, *fRight, *fBottom;
111
112 // These return a number that is less than, equal to, or greater than zero
113 // depending on whether the trapezoid or point is to the left, on, or to the
114 // right.
115 SkScalar compare(const Trapezoid &t1) const;
116 SkScalar compare(const SkPoint &p) const;
117};
118
119
120//------------------------------------------------------------------------------
121// The ActiveTrapezoids are a sorted list containing the currently active
122// trapezoids, i.e. those that have the top, left, and right, but still need the
123// bottom. This could use some optimization, to reduce search time from O(n) to
124// O(log n).
125//------------------------------------------------------------------------------
126class ActiveTrapezoids {
127public:
128 ActiveTrapezoids() { fTrapezoids.setCount(0); }
129
130 size_t count() const { return fTrapezoids.count(); }
131
132 // Select an unused trapezoid from the Vertex vt, initialize it with the
133 // left and right edges, and insert it into the sorted list.
134 bool insertNewTrapezoid(Vertex *vt, Vertex *left, Vertex *right);
135
136 // Remove the specified Trapezoids from the active list.
137 void remove(Trapezoid *t);
138
139 // Determine whether the given point lies within any active trapezoid, and
140 // return a pointer to that Trapezoid.
141 bool withinActiveTrapezoid(const SkPoint &pt, Trapezoid **tp);
142
143 // Find an active trapezoid that contains the given edge.
144 Trapezoid* getTrapezoidWithEdge(const Vertex *edge);
145
146private:
147 // Insert the specified Trapezoid into the sorted list.
148 void insert(Trapezoid *t);
149
150 // The sorted list of active trapezoids. This is O(n), and would benefit
151 // a 2-3 tree o achieve O(log n).
152 SkTDArray<Trapezoid*> fTrapezoids; // Fournier suggests a 2-3 tree instead.
153};
154
155
156//------------------------------------------------------------------------------
157// The Vertex is used to communicate information between the various phases of
158// triangulation.
159//------------------------------------------------------------------------------
160class Vertex {
161public:
162 enum VertexType { MONOTONE, CONVEX, CONCAVE };
163
164 Trapezoid fTrap0;
165 Trapezoid fTrap1;
166
167 const SkPoint &point() const { return fPoint; }
168 void setPoint(const SkPoint &point) { fPoint = point; }
169
170 // The next and previous vertices around the polygon.
171 Vertex *next() { return fNext; }
172 Vertex *prev() { return fPrev; }
173 const Vertex *next() const { return fNext; }
174 const Vertex *prev() const { return fPrev; }
175 void setNext(Vertex *next) { fNext = next; }
176 void setPrev(Vertex *prev) { fPrev = prev; }
177
178 void setDone(bool done) { fDone = done; }
179 bool done() const { return fDone; }
180
181 // Trapezoid accessors return non-null for any complete trapezoids.
182 void trapezoids(Trapezoid **trap0, Trapezoid **trap1) {
183 *trap0 = (fTrap0.bottom() != NULL) ? &fTrap0 : NULL;
184 *trap1 = (fTrap1.bottom() != NULL) ? &fTrap1 : NULL;
185 }
186
187 // Eliminate a trapezoid.
188 void nullifyTrapezoid() {
189 if (fTrap1.bottom() != NULL) {
190 DebugPrintf("Unexpected non-null second trapezoid.\n");
191 fTrap1.nullify();
192 return;
193 }
194 fTrap0.nullify();
195 }
196
197 // Determine whether the edge specified by this Vertex shares the given top
198 // and bottom.
199 bool shareEdge(Vertex *top, Vertex *bottom);
200
201 // Determines whether the angle specified by { prev, this, next } is convex.
202 // Note that collinear is considered to be convex.
203 bool angleIsConvex();
204
205 // Remove this Vertex from the { prev, next } linked list.
206 void delink() {
207 Vertex *p = prev(),
208 *n = next();
209 p->setNext(n);
210 n->setPrev(p);
211 }
212
213 // Return a number that is less than, equal to, or greater than zero
214 // depending on whether the point is to the left, on, or to the right of the
215 // edge that has this Vertex as a base.
216 SkScalar compare(const SkPoint &pt) const;
217
218 // Classify the vertex, and return its sorted edges.
219 VertexType classify(Vertex **e0, Vertex **e1);
220
221 // This helps determine unimonotonicity.
222 Vertex *diagonal();
223
224private:
225 SkPoint fPoint;
226 Vertex *fNext;
227 Vertex *fPrev;
228 bool fDone;
229};
230
231
232bool Vertex::angleIsConvex() {
233 SkPoint vPrev = prev()->point() - point(),
234 vNext = next()->point() - point();
235 // TODO(turk): There might be overflow in fixed-point.
236 return SkPoint::CrossProduct(vNext, vPrev) >= 0;
237}
238
239
240bool Vertex::shareEdge(Vertex *top, Vertex *bottom) {
241 return (((this == top) && (this->next() == bottom)) ||
242 ((this == bottom) && (this->next() == top)));
243}
244
245
246SkScalar Vertex::compare(const SkPoint &pt) const {
247 SkPoint ve = next()->point() - point(),
248 vp = pt - point();
249 SkScalar d;
250 if (ve.fY == 0) {
251 // Return twice the distance to the center of the horizontal edge.
252 d = ve.fX + pt.fX - next()->point().fX;
253 } else {
254 // Return the distance to the edge, scaled by the edge length.
255 d = SkPoint::CrossProduct(ve, vp);
256 if (ve.fY > 0) d = -d;
257 }
258 return d;
259}
260
261
262SkScalar Trapezoid::compare(const SkPoint &pt) const {
263 SkScalar d = left()->compare(pt);
264 if (d <= 0)
265 return d; // Left of the left edge.
266 d = right()->compare(pt);
267 if (d >= 0)
268 return d; // Right of the right edge.
269 return 0; // Somewhere between the left and the right edges.
270}
271
272
273
274SkScalar Trapezoid::compare(const Trapezoid &t1) const {
275#if 1
276 SkScalar d = left()->compare(t1.left()->point());
277 if (d == 0)
278 d = right()->compare(t1.right()->point());
279 return d;
280#else
281 SkScalar dl = left()->compare( t1.left()->point()),
282 dr = right()->compare(t1.right()->point());
283 if (dl < 0 && dr < 0)
284 return dr;
285 if (dl > 0 && dr > 0)
286 return dl;
287 return 0;
288#endif
289}
290
291
292Trapezoid* ActiveTrapezoids::getTrapezoidWithEdge(const Vertex *edge) {
293 DebugPrintf("Entering getTrapezoidWithEdge(): looking through %d\n",
294 fTrapezoids.count());
295 DebugPrintf("trying to find %p: ", edge);
296 Trapezoid **tp;
297 for (tp = fTrapezoids.begin(); tp < fTrapezoids.end(); ++tp) {
298 SkASSERT(tp != NULL);
299 SkASSERT(*tp != NULL);
300 DebugPrintf("%p and %p, ", (**tp).left(), (**tp).right());
301 if ((**tp).left() == edge || (**tp).right() == edge) {
302 DebugPrintf("\ngetTrapezoidWithEdge found the trapezoid\n");
303 return *tp;
304 }
305 }
306 DebugPrintf("getTrapezoidWithEdge found no trapezoid\n");
307 return NULL;
308}
309
310
311bool ActiveTrapezoids::insertNewTrapezoid(Vertex *vt,
312 Vertex *left,
313 Vertex *right) {
314 DebugPrintf("Inserting a trapezoid...");
315 if (vt->fTrap0.left() == NULL && vt->fTrap0.right() == NULL) {
316 vt->fTrap0.setLeft(left);
317 vt->fTrap0.setRight(right);
318 insert(&vt->fTrap0);
319 } else if (vt->fTrap1.left() == NULL && vt->fTrap1.right() == NULL) {
320 DebugPrintf("a second one...");
321 vt->fTrap1.setLeft(left);
322 vt->fTrap1.setRight(right);
323 if (vt->fTrap1 < vt->fTrap0) { // Keep trapezoids sorted.
324 remove(&vt->fTrap0);
325 Trapezoid t = vt->fTrap0;
326 vt->fTrap0 = vt->fTrap1;
327 vt->fTrap1 = t;
328 insert(&vt->fTrap0);
329 }
330 insert(&vt->fTrap1);
331 } else {
332 FailureMessage("More than 2 trapezoids requested for a vertex\n");
333 return false;
334 }
335 DebugPrintf(" done. %d incomplete trapezoids\n", fTrapezoids.count());
336 return true;
337}
338
339
340void ActiveTrapezoids::insert(Trapezoid *t) {
341 Trapezoid **tp;
342 for (tp = fTrapezoids.begin(); tp < fTrapezoids.end(); ++tp)
343 if (**tp > *t)
344 break;
345 fTrapezoids.insert(tp - fTrapezoids.begin(), 1, &t);
346 // SHOULD VERIFY THAT ALL TRAPEZOIDS ARE PROPERLY SORTED
347}
348
349
350void ActiveTrapezoids::remove(Trapezoid *t) {
351 DebugPrintf("Removing a trapezoid...");
352 for (Trapezoid **tp = fTrapezoids.begin(); tp < fTrapezoids.end(); ++tp) {
353 if (*tp == t) {
354 fTrapezoids.remove(tp - fTrapezoids.begin());
355 DebugPrintf(" done.\n");
356 return;
357 }
358 }
359 DebugPrintf(" Arghh! Panic!\n");
360 SkASSERT(t == 0); // Cannot find t in active trapezoid list.
361}
362
363
364bool ActiveTrapezoids::withinActiveTrapezoid(const SkPoint &pt,
365 Trapezoid **trap) {
366 DebugPrintf("Entering withinActiveTrapezoid()\n");
367 // This is where a good search data structure would be helpful.
368 Trapezoid **t;
369 for (t = fTrapezoids.begin(); t < fTrapezoids.end(); ++t) {
370 if ((**t).left()->compare(pt) <= 0) {
371 // The point is to the left of the left edge of this trapezoid.
372 DebugPrintf("withinActiveTrapezoid: Before a trapezoid\n");
373 *trap = *t; // Return the place where a new trapezoid would go.
374// We have a bug with the sorting -- look through everything.
375 continue;
376// return false; // Outside all trapezoids, since they are sorted.
377 }
378 // The point is to the right of the left edge of this trapezoid.
379
380 if ((**t).right()->compare(pt) < 0) {
381 // The point is to the left of the right edge.
382 DebugPrintf("withinActiveTrapezoid: Within an Active Trapezoid\n");
383 *trap = *t;
384 return true;
385 }
386 }
387
388 // The point is to the right of all trapezoids.
389 DebugPrintf("withinActiveTrapezoid: After all trapezoids\n");
390 *trap = NULL;
391 return false;
392}
393
394
395Vertex* Vertex::diagonal() {
396 Vertex *diag = NULL;
397 if (fTrap0.bottom() != NULL) {
398 if (!fTrap0.left() ->shareEdge(this, fTrap0.bottom()) &&
399 !fTrap0.right()->shareEdge(this, fTrap0.bottom())
400 ) {
401 diag = fTrap0.bottom();
402 fTrap0 = fTrap1;
403 fTrap1.nullify();
404 } else if (fTrap1.bottom() != NULL &&
405 !fTrap1.left() ->shareEdge(this, fTrap1.bottom()) &&
406 !fTrap1.right()->shareEdge(this, fTrap1.bottom())
407 ) {
408 diag = fTrap1.bottom();
409 fTrap1.nullify();
410 }
411 }
412 return diag;
413}
414
415
416// We use this to sort the edges vertically for a scan-conversion type of
417// operation.
418class VertexPtr {
419public:
420 Vertex *vt;
421};
422
423
caryclark@google.com803eceb2012-06-06 12:09:34 +0000424static bool operator<(VertexPtr &v0, VertexPtr &v1) {
turk@google.com6f8491b2009-03-13 22:05:46 +0000425 // DebugPrintf("< %p %p\n", &v0, &v1);
426 if (v0.vt->point().fY < v1.vt->point().fY) return true;
427 if (v0.vt->point().fY > v1.vt->point().fY) return false;
428 if (v0.vt->point().fX < v1.vt->point().fX) return true;
429 else return false;
430}
431
432
caryclark@google.com803eceb2012-06-06 12:09:34 +0000433#if 0 // UNUSED
434static bool operator>(VertexPtr &v0, VertexPtr &v1) {
turk@google.com6f8491b2009-03-13 22:05:46 +0000435 // DebugPrintf("> %p %p\n", &v0, &v1);
436 if (v0.vt->point().fY > v1.vt->point().fY) return true;
437 if (v0.vt->point().fY < v1.vt->point().fY) return false;
438 if (v0.vt->point().fX > v1.vt->point().fX) return true;
439 else return false;
440}
caryclark@google.com803eceb2012-06-06 12:09:34 +0000441#endif
turk@google.com6f8491b2009-03-13 22:05:46 +0000442
443static void SetVertexPoints(size_t numPts, const SkPoint *pt, Vertex *vt) {
444 for (; numPts-- != 0; ++pt, ++vt)
445 vt->setPoint(*pt);
446}
447
448
449static void InitializeVertexTopology(size_t numPts, Vertex *v1) {
450 Vertex *v0 = v1 + numPts - 1, *v_1 = v0 - 1;
451 for (; numPts-- != 0; v_1 = v0, v0 = v1++) {
452 v0->setPrev(v_1);
453 v0->setNext(v1);
454 }
455}
456
457Vertex::VertexType Vertex::classify(Vertex **e0, Vertex **e1) {
458 VertexType type;
459 SkPoint vPrev, vNext;
460 vPrev.fX = prev()->point().fX - point().fX;
461 vPrev.fY = prev()->point().fY - point().fY;
462 vNext.fX = next()->point().fX - point().fX;
463 vNext.fY = next()->point().fY - point().fY;
464
465 // This can probably be simplified, but there are enough potential bugs,
466 // we will leave it expanded until all cases are tested appropriately.
467 if (vPrev.fY < 0) {
468 if (vNext.fY > 0) {
469 // Prev comes from above, Next goes below.
470 type = MONOTONE;
471 *e0 = prev();
472 *e1 = this;
473 } else if (vNext.fY < 0) {
474 // The are both above: sort so that e0 is on the left.
475 type = CONCAVE;
476 if (SkPoint::CrossProduct(vPrev, vNext) <= 0) {
477 *e0 = this;
478 *e1 = prev();
479 } else {
480 *e0 = prev();
481 *e1 = this;
482 }
483 } else {
484 DebugPrintf("### py < 0, ny = 0\n");
485 if (vNext.fX < 0) {
486 type = CONCAVE;
487 *e0 = this; // flat to the left
488 *e1 = prev(); // concave on the right
489 } else {
490 type = CONCAVE;
491 *e0 = prev(); // concave to the left
492 *e1 = this; // flat to the right
493 }
494 }
495 } else if (vPrev.fY > 0) {
496 if (vNext.fY < 0) {
497 // Next comes from above, Prev goes below.
498 type = MONOTONE;
499 *e0 = this;
500 *e1 = prev();
501 } else if (vNext.fY > 0) {
502 // They are both below: sort so that e0 is on the left.
503 type = CONVEX;
504 if (SkPoint::CrossProduct(vPrev, vNext) <= 0) {
505 *e0 = prev();
506 *e1 = this;
507 } else {
508 *e0 = this;
509 *e1 = prev();
510 }
511 } else {
512 DebugPrintf("### py > 0, ny = 0\n");
513 if (vNext.fX < 0) {
514 type = MONOTONE;
515 *e0 = this; // flat to the left
516 *e1 = prev(); // convex on the right - try monotone first
517 } else {
518 type = MONOTONE;
519 *e0 = prev(); // convex to the left - try monotone first
520 *e1 = this; // flat to the right
521 }
522 }
523 } else { // vPrev.fY == 0
524 if (vNext.fY < 0) {
525 DebugPrintf("### py = 0, ny < 0\n");
526 if (vPrev.fX < 0) {
527 type = CONCAVE;
528 *e0 = prev(); // flat to the left
529 *e1 = this; // concave on the right
530 } else {
531 type = CONCAVE;
532 *e0 = this; // concave on the left - defer
533 *e1 = prev(); // flat to the right
534 }
535 } else if (vNext.fY > 0) {
536 DebugPrintf("### py = 0, ny > 0\n");
537 if (vPrev.fX < 0) {
538 type = MONOTONE;
539 *e0 = prev(); // flat to the left
540 *e1 = this; // convex on the right - try monotone first
541 } else {
542 type = MONOTONE;
543 *e0 = this; // convex to the left - try monotone first
544 *e1 = prev(); // flat to the right
545 }
546 } else {
547 DebugPrintf("### py = 0, ny = 0\n");
548 // First we try concave, then monotone, then convex.
549 if (vPrev.fX <= vNext.fX) {
550 type = CONCAVE;
551 *e0 = prev(); // flat to the left
552 *e1 = this; // flat to the right
553 } else {
554 type = CONCAVE;
555 *e0 = this; // flat to the left
556 *e1 = prev(); // flat to the right
557 }
558 }
559 }
560 return type;
561}
562
563
564#ifdef DEBUG
565static const char* GetVertexTypeString(Vertex::VertexType type) {
566 const char *typeStr = NULL;
567 switch (type) {
568 case Vertex::MONOTONE:
569 typeStr = "MONOTONE";
570 break;
571 case Vertex::CONCAVE:
572 typeStr = "CONCAVE";
573 break;
574 case Vertex::CONVEX:
575 typeStr = "CONVEX";
576 break;
577 }
578 return typeStr;
579}
580
581
582static void PrintVertices(size_t numPts, Vertex *vt) {
583 DebugPrintf("\nVertices:\n");
reed@android.com04225dc2009-03-20 04:59:37 +0000584 for (size_t i = 0; i < numPts; i++) {
turk@google.com6f8491b2009-03-13 22:05:46 +0000585 Vertex *e0, *e1;
586 Vertex::VertexType type = vt[i].classify(&e0, &e1);
587 DebugPrintf("%2d: (%.7g, %.7g), prev(%d), next(%d), "
588 "type(%s), left(%d), right(%d)",
589 i, vt[i].point().fX, vt[i].point().fY,
590 vt[i].prev() - vt, vt[i].next() - vt,
591 GetVertexTypeString(type), e0 - vt, e1 - vt);
592 Trapezoid *trap[2];
593 vt[i].trapezoids(trap, trap+1);
reed@android.com04225dc2009-03-20 04:59:37 +0000594 for (int j = 0; j < 2; ++j) {
595 if (trap[j] != NULL) {
turk@google.com6f8491b2009-03-13 22:05:46 +0000596 DebugPrintf(", trap(L=%d, R=%d, B=%d)",
reed@android.com04225dc2009-03-20 04:59:37 +0000597 trap[j]->left() - vt,
598 trap[j]->right() - vt,
599 trap[j]->bottom() - vt);
600 }
601 }
turk@google.com6f8491b2009-03-13 22:05:46 +0000602 DebugPrintf("\n");
603 }
604}
605
606
607static void PrintVertexPtrs(size_t numPts, VertexPtr *vp, Vertex *vtBase) {
608 DebugPrintf("\nSorted Vertices:\n");
reed@android.com04225dc2009-03-20 04:59:37 +0000609 for (size_t i = 0; i < numPts; i++) {
turk@google.com6f8491b2009-03-13 22:05:46 +0000610 Vertex *e0, *e1;
611 Vertex *vt = vp[i].vt;
612 Vertex::VertexType type = vt->classify(&e0, &e1);
613 DebugPrintf("%2d: %2d: (%.7g, %.7g), prev(%d), next(%d), "
614 "type(%s), left(%d), right(%d)",
615 i, vt - vtBase, vt->point().fX, vt->point().fY,
616 vt->prev() - vtBase, vt->next() - vtBase,
617 GetVertexTypeString(type), e0 - vtBase, e1 - vtBase);
618 Trapezoid *trap[2];
619 vt->trapezoids(trap, trap+1);
reed@android.com04225dc2009-03-20 04:59:37 +0000620 for (int j = 0; j < 2; ++j) {
621 if (trap[j] != NULL) {
turk@google.com6f8491b2009-03-13 22:05:46 +0000622 DebugPrintf(", trap(L=%d, R=%d, B=%d)",
reed@android.com04225dc2009-03-20 04:59:37 +0000623 trap[j]->left() - vtBase,
624 trap[j]->right() - vtBase,
625 trap[j]->bottom() - vtBase);
626 }
627 }
turk@google.com6f8491b2009-03-13 22:05:46 +0000628 DebugPrintf("\n");
629 }
630}
631#else // !DEBUG
632inline void PrintVertices(size_t numPts, Vertex *vt) {}
633inline void PrintVertexPtrs(size_t numPts, VertexPtr *vp, Vertex *vtBase) {}
634#endif // !DEBUG
635
636
637// SkTHeapSort is broken, so we use a bubble sort in the meantime.
638template <typename T>
639void BubbleSort(T *array, size_t count) {
640 bool sorted;
641 size_t count_1 = count - 1;
642 do {
643 sorted = true;
reed@android.com04225dc2009-03-20 04:59:37 +0000644 for (size_t i = 0; i < count_1; ++i) {
turk@google.com6f8491b2009-03-13 22:05:46 +0000645 if (array[i + 1] < array[i]) {
646 T t = array[i];
647 array[i] = array[i + 1];
648 array[i + 1] = t;
649 sorted = false;
650 }
651 }
652 } while (!sorted);
653}
654
655
656// Remove zero-height trapezoids.
657static void RemoveDegenerateTrapezoids(size_t numVt, Vertex *vt) {
658 for (; numVt-- != 0; vt++) {
659 Trapezoid *traps[2];
660 vt->trapezoids(traps, traps+1);
661 if (traps[1] != NULL &&
662 vt->point().fY >= traps[1]->bottom()->point().fY) {
663 traps[1]->nullify();
664 traps[1] = NULL;
665 }
666 if (traps[0] != NULL &&
667 vt->point().fY >= traps[0]->bottom()->point().fY) {
668 if (traps[1] != NULL) {
669 *traps[0] = *traps[1];
670 traps[1]->nullify();
671 } else {
672 traps[0]->nullify();
673 }
674 }
675 }
676}
677
678
679// Enhance the polygon with trapezoids.
caryclark@google.com803eceb2012-06-06 12:09:34 +0000680static bool ConvertPointsToVertices(size_t numPts, const SkPoint *pts, Vertex *vta) {
turk@google.com6f8491b2009-03-13 22:05:46 +0000681 DebugPrintf("ConvertPointsToVertices()\n");
682
683 // Clear everything.
684 DebugPrintf("Zeroing vertices\n");
reed@android.com4516f472009-06-29 16:25:36 +0000685 sk_bzero(vta, numPts * sizeof(*vta));
turk@google.com6f8491b2009-03-13 22:05:46 +0000686
687 // Initialize vertices.
688 DebugPrintf("Initializing vertices\n");
689 SetVertexPoints(numPts, pts, vta);
690 InitializeVertexTopology(numPts, vta);
691
692 PrintVertices(numPts, vta);
693
694 SkTDArray<VertexPtr> vtptr;
695 vtptr.setCount(numPts);
696 for (int i = numPts; i-- != 0;)
697 vtptr[i].vt = vta + i;
698 PrintVertexPtrs(vtptr.count(), vtptr.begin(), vta);
699 DebugPrintf("Sorting vertrap ptr array [%d] %p %p\n", vtptr.count(),
700 &vtptr[0], &vtptr[vtptr.count() - 1]
701 );
702// SkTHeapSort(vtptr.begin(), vtptr.count());
703 BubbleSort(vtptr.begin(), vtptr.count());
704 DebugPrintf("Done sorting\n");
705 PrintVertexPtrs(vtptr.count(), vtptr.begin(), vta);
706
707 DebugPrintf("Traversing sorted vertrap ptrs\n");
708 ActiveTrapezoids incompleteTrapezoids;
709 for (VertexPtr *vtpp = vtptr.begin(); vtpp < vtptr.end(); ++vtpp) {
710 DebugPrintf("%d: sorted vertrap %d\n",
711 vtpp - vtptr.begin(), vtpp->vt - vta);
712 Vertex *vt = vtpp->vt;
713 Vertex *e0, *e1;
714 Trapezoid *t;
715 switch (vt->classify(&e0, &e1)) {
716 case Vertex::MONOTONE:
717 monotone:
718 DebugPrintf("MONOTONE %d %d\n", e0 - vta, e1 - vta);
719 // We should find one edge.
720 t = incompleteTrapezoids.getTrapezoidWithEdge(e0);
721 if (t == NULL) { // One of the edges is flat.
722 DebugPrintf("Monotone: cannot find a trapezoid with e0: "
723 "trying convex\n");
724 goto convex;
725 }
726 t->setBottom(vt); // This trapezoid is now complete.
727 incompleteTrapezoids.remove(t);
728
729 if (e0 == t->left()) // Replace the left edge.
730 incompleteTrapezoids.insertNewTrapezoid(vt, e1, t->right());
731 else // Replace the right edge.
732 incompleteTrapezoids.insertNewTrapezoid(vt, t->left(), e1);
733 break;
734
735 case Vertex::CONVEX: // Start of a new trapezoid.
736 convex:
737 // We don't expect to find any edges.
738 DebugPrintf("CONVEX %d %d\n", e0 - vta, e1 - vta);
739 if (incompleteTrapezoids.withinActiveTrapezoid(
740 vt->point(), &t)) {
741 // Complete trapezoid.
742 SkASSERT(t != NULL);
743 t->setBottom(vt);
744 incompleteTrapezoids.remove(t);
745 // Introduce two new trapezoids.
746 incompleteTrapezoids.insertNewTrapezoid(vt, t->left(), e0);
747 incompleteTrapezoids.insertNewTrapezoid(vt, e1, t->right());
748 } else {
749 // Insert a new trapezoid.
750 incompleteTrapezoids.insertNewTrapezoid(vt, e0, e1);
751 }
752 break;
753
754 case Vertex::CONCAVE: // End of a trapezoid.
755 DebugPrintf("CONCAVE %d %d\n", e0 - vta, e1 - vta);
756 // We should find two edges.
757 t = incompleteTrapezoids.getTrapezoidWithEdge(e0);
758 if (t == NULL) {
759 DebugPrintf("Concave: cannot find a trapezoid with e0: "
760 " trying monotone\n");
761 goto monotone;
762 }
763 SkASSERT(t != NULL);
764 if (e0 == t->left() && e1 == t->right()) {
765 DebugPrintf(
766 "Concave edges belong to the same trapezoid.\n");
767 // Edges belong to the same trapezoid.
768 // Complete trapezoid & transfer it from the active list.
769 t->setBottom(vt);
770 incompleteTrapezoids.remove(t);
771 } else { // Edges belong to different trapezoids
772 DebugPrintf(
773 "Concave edges belong to different trapezoids.\n");
774 // Complete left and right trapezoids.
775 Trapezoid *s = incompleteTrapezoids.getTrapezoidWithEdge(
776 e1);
777 if (s == NULL) {
778 DebugPrintf(
779 "Concave: cannot find a trapezoid with e1: "
780 " trying monotone\n");
781 goto monotone;
782 }
783 t->setBottom(vt);
784 s->setBottom(vt);
785 incompleteTrapezoids.remove(t);
786 incompleteTrapezoids.remove(s);
787
788 // Merge the two trapezoids into one below this vertex.
789 incompleteTrapezoids.insertNewTrapezoid(vt, t->left(),
790 s->right());
791 }
792 break;
793 }
794 }
795
796 RemoveDegenerateTrapezoids(numPts, vta);
797
798 DebugPrintf("Done making trapezoids\n");
799 PrintVertexPtrs(vtptr.count(), vtptr.begin(), vta);
800
801 size_t k = incompleteTrapezoids.count();
802 if (k > 0) {
803 FailureMessage("%d incomplete trapezoids\n", k);
804 return false;
805 }
806 return true;
807}
808
809
810inline void appendTriangleAtVertex(const Vertex *v,
811 SkTDArray<SkPoint> *triangles) {
812 SkPoint *p = triangles->append(3);
813 p[0] = v->prev()->point();
814 p[1] = v->point();
815 p[2] = v->next()->point();
816 DebugPrintf(
817 "Appending triangle: { (%.7g, %.7g), (%.7g, %.7g), (%.7g, %.7g) }\n",
818 p[0].fX, p[0].fY,
819 p[1].fX, p[1].fY,
820 p[2].fX, p[2].fY
821 );
822}
823
824
825static size_t CountVertices(const Vertex *first, const Vertex *last) {
826 DebugPrintf("Counting vertices: ");
827 size_t count = 1;
828 for (; first != last; first = first->next()) {
829 ++count;
830 SkASSERT(count <= kMaxCount);
831 if (count >= kMaxCount) {
832 FailureMessage("Vertices do not seem to be in a linked chain\n");
833 break;
834 }
835 }
836 return count;
837}
838
839
caryclark@google.com803eceb2012-06-06 12:09:34 +0000840static bool operator<(const SkPoint &p0, const SkPoint &p1) {
turk@google.com6f8491b2009-03-13 22:05:46 +0000841 if (p0.fY < p1.fY) return true;
842 if (p0.fY > p1.fY) return false;
843 if (p0.fX < p1.fX) return true;
844 else return false;
845}
846
847
848static void PrintLinkedVertices(size_t n, Vertex *vertices) {
849 DebugPrintf("%d vertices:\n", n);
850 Vertex *v;
851 for (v = vertices; n-- != 0; v = v->next())
852 DebugPrintf(" (%.7g, %.7g)\n", v->point().fX, v->point().fY);
853 if (v != vertices)
854 FailureMessage("Vertices are not in a linked chain\n");
855}
856
857
858// Triangulate an unimonotone chain.
caryclark@google.com803eceb2012-06-06 12:09:34 +0000859static bool TriangulateMonotone(Vertex *first, Vertex *last,
turk@google.com6f8491b2009-03-13 22:05:46 +0000860 SkTDArray<SkPoint> *triangles) {
turk@google.com6f8491b2009-03-13 22:05:46 +0000861 DebugPrintf("TriangulateMonotone()\n");
862
863 size_t numVertices = CountVertices(first, last);
864 if (numVertices == kMaxCount) {
865 FailureMessage("Way too many vertices: %d:\n", numVertices);
866 PrintLinkedVertices(numVertices, first);
867 return false;
868 }
869
870 Vertex *start = first;
871 // First find the point with the smallest Y.
872 DebugPrintf("TriangulateMonotone: finding bottom\n");
873 int count = kMaxCount; // Maximum number of vertices.
874 for (Vertex *v = first->next(); v != first && count-- > 0; v = v->next())
875 if (v->point() < start->point())
876 start = v;
877 if (count <= 0) {
878 FailureMessage("TriangulateMonotone() was given disjoint chain\n");
879 return false; // Something went wrong.
880 }
881
882 // Start at the far end of the long edge.
883 if (start->prev()->point() < start->next()->point())
884 start = start->next();
885
886 Vertex *current = start->next();
887 while (numVertices >= 3) {
888 if (current->angleIsConvex()) {
889 DebugPrintf("Angle %p is convex\n", current);
890 // Print the vertices
891 PrintLinkedVertices(numVertices, start);
892
893 appendTriangleAtVertex(current, triangles);
894 if (triangles->count() > kMaxCount * 3) {
895 FailureMessage("An extraordinarily large number of triangles "
896 "were generated\n");
897 return false;
898 }
899 Vertex *save = current->prev();
900 current->delink();
901 current = (save == start || save == start->prev()) ? start->next()
902 : save;
903 --numVertices;
904 } else {
905 if (numVertices == 3) {
906 FailureMessage("Convexity error in TriangulateMonotone()\n");
907 appendTriangleAtVertex(current, triangles);
908 return false;
909 }
910 DebugPrintf("Angle %p is concave\n", current);
911 current = current->next();
912 }
913 }
914 return true;
915}
916
917
918// Split the polygon into sets of unimonotone chains, and eventually call
919// TriangulateMonotone() to convert them into triangles.
caryclark@google.com803eceb2012-06-06 12:09:34 +0000920static bool Triangulate(Vertex *first, Vertex *last, SkTDArray<SkPoint> *triangles) {
turk@google.com6f8491b2009-03-13 22:05:46 +0000921 DebugPrintf("Triangulate()\n");
922 Vertex *currentVertex = first;
923 while (!currentVertex->done()) {
924 currentVertex->setDone(true);
925 Vertex *bottomVertex = currentVertex->diagonal();
926 if (bottomVertex != NULL) {
927 Vertex *saveNext = currentVertex->next();
928 Vertex *savePrev = bottomVertex->prev();
929 currentVertex->setNext(bottomVertex);
930 bottomVertex->setPrev(currentVertex);
931 currentVertex->nullifyTrapezoid();
932 bool success = Triangulate(bottomVertex, currentVertex, triangles);
933 currentVertex->setDone(false);
934 bottomVertex->setDone(false);
935 currentVertex->setNext(saveNext);
936 bottomVertex->setPrev(savePrev);
937 bottomVertex->setNext(currentVertex);
938 currentVertex->setPrev(bottomVertex);
939 return Triangulate(currentVertex, bottomVertex, triangles)
940 && success;
941 } else {
942 currentVertex = currentVertex->next();
943 }
944 }
945 return TriangulateMonotone(first, last, triangles);
946}
947
948
949bool SkConcaveToTriangles(size_t numPts,
950 const SkPoint pts[],
951 SkTDArray<SkPoint> *triangles) {
952 DebugPrintf("SkConcaveToTriangles()\n");
953
954 SkTDArray<Vertex> vertices;
955 vertices.setCount(numPts);
956 if (!ConvertPointsToVertices(numPts, pts, vertices.begin()))
957 return false;
958
959 triangles->setReserve(numPts);
960 triangles->setCount(0);
961 return Triangulate(vertices.begin(), vertices.end() - 1, triangles);
962}