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