• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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