Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
GrTriangulator.h
Go to the documentation of this file.
1/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef GrTriangulator_DEFINED
9#define GrTriangulator_DEFINED
10
11#if !defined(SK_ENABLE_OPTIMIZE_SIZE)
12
13#include "include/core/SkPath.h"
19
20#include <algorithm>
21#include <cmath>
22#include <cstdint>
23#include <tuple>
24
26enum class SkPathFillType;
27struct SkRect;
28
29#define TRIANGULATOR_LOGGING 0
30#define TRIANGULATOR_WIREFRAME 0
31
32/**
33 * Provides utility functions for converting paths to a collection of triangles.
34 */
36public:
37 constexpr static int kArenaDefaultChunkSize = 16 * 1024;
38
39 static int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
40 GrEagerVertexAllocator* vertexAllocator, bool* isLinear) {
41 if (!path.isFinite()) {
42 return 0;
43 }
45 GrTriangulator triangulator(path, &alloc);
46 auto [ polys, success ] = triangulator.pathToPolys(tolerance, clipBounds, isLinear);
47 if (!success) {
48 return 0;
49 }
50 int count = triangulator.polysToTriangles(polys, vertexAllocator);
51 return count;
52 }
53
54 // Enums used by GrTriangulator internals.
55 typedef enum { kLeft_Side, kRight_Side } Side;
56 enum class EdgeType { kInner, kOuter, kConnector };
57
58 // Structs used by GrTriangulator internals.
59 struct Vertex;
60 struct VertexList;
61 struct Line;
62 struct Edge;
63 struct EdgeList;
64 struct MonotonePoly;
65 struct Poly;
66 struct Comparator;
67
68protected:
69 GrTriangulator(const SkPath& path, SkArenaAlloc* alloc) : fPath(path), fAlloc(alloc) {}
70 virtual ~GrTriangulator() {}
71
72 // There are six stages to the basic algorithm:
73 //
74 // 1) Linearize the path contours into piecewise linear segments:
75 void pathToContours(float tolerance, const SkRect& clipBounds, VertexList* contours,
76 bool* isLinear) const;
77
78 // 2) Build a mesh of edges connecting the vertices:
79 void contoursToMesh(VertexList* contours, int contourCnt, VertexList* mesh,
80 const Comparator&);
81
82 // 3) Sort the vertices in Y (and secondarily in X):
83 static void SortedMerge(VertexList* front, VertexList* back, VertexList* result,
84 const Comparator&);
85 static void SortMesh(VertexList* vertices, const Comparator&);
86
87 // 4) Simplify the mesh by inserting new vertices at intersecting edges:
93
94 enum class BoolFail {
95 kFalse,
96 kTrue,
97 kFail
98 };
99
100 [[nodiscard]] SimplifyResult simplify(VertexList* mesh, const Comparator&);
101
102 // 5) Tessellate the simplified mesh into monotone polygons:
103 virtual std::tuple<Poly*, bool> tessellate(const VertexList& vertices, const Comparator&);
104
105 // 6) Triangulate the monotone polygons directly into a vertex buffer:
107 SkPathFillType overrideFillType,
108 skgpu::VertexWriter data) const;
109
110 // The vertex sorting in step (3) is a merge sort, since it plays well with the linked list
111 // of vertices (and the necessity of inserting new vertices on intersection).
112 //
113 // Stages (4) and (5) use an active edge list -- a list of all edges for which the
114 // sweep line has crossed the top vertex, but not the bottom vertex. It's sorted
115 // left-to-right based on the point where both edges are active (when both top vertices
116 // have been seen, so the "lower" top vertex of the two). If the top vertices are equal
117 // (shared), it's sorted based on the last point where both edges are active, so the
118 // "upper" bottom vertex.
119 //
120 // The most complex step is the simplification (4). It's based on the Bentley-Ottman
121 // line-sweep algorithm, but due to floating point inaccuracy, the intersection points are
122 // not exact and may violate the mesh topology or active edge list ordering. We
123 // accommodate this by adjusting the topology of the mesh and AEL to match the intersection
124 // points. This occurs in two ways:
125 //
126 // A) Intersections may cause a shortened edge to no longer be ordered with respect to its
127 // neighbouring edges at the top or bottom vertex. This is handled by merging the
128 // edges (mergeCollinearVertices()).
129 // B) Intersections may cause an edge to violate the left-to-right ordering of the
130 // active edge list. This is handled by detecting potential violations and rewinding
131 // the active edge list to the vertex before they occur (rewind() during merging,
132 // rewind_if_necessary() during splitting).
133 //
134 // The tessellation steps (5) and (6) are based on "Triangulating Simple Polygons and
135 // Equivalent Problems" (Fournier and Montuno); also a line-sweep algorithm. Note that it
136 // currently uses a linked list for the active edge list, rather than a 2-3 tree as the
137 // paper describes. The 2-3 tree gives O(lg N) lookups, but insertion and removal also
138 // become O(lg N). In all the test cases, it was found that the cost of frequent O(lg N)
139 // insertions and removals was greater than the cost of infrequent O(N) lookups with the
140 // linked list implementation. With the latter, all removals are O(1), and most insertions
141 // are O(1), since we know the adjacent edge in the active edge list based on the topology.
142 // Only type 2 vertices (see paper) require the O(N) lookups, and these are much less
143 // frequent. There may be other data structures worth investigating, however.
144 //
145 // Note that the orientation of the line sweep algorithms is determined by the aspect ratio of
146 // the path bounds. When the path is taller than it is wide, we sort vertices based on
147 // increasing Y coordinate, and secondarily by increasing X coordinate. When the path is wider
148 // than it is tall, we sort by increasing X coordinate, but secondarily by *decreasing* Y
149 // coordinate. This is so that the "left" and "right" orientation in the code remains correct
150 // (edges to the left are increasing in Y; edges to the right are decreasing in Y). That is, the
151 // setting rotates 90 degrees counterclockwise, rather that transposing.
152
153 // Additional helpers and driver functions.
156 skgpu::VertexWriter data) const;
158
159 Poly* makePoly(Poly** head, Vertex* v, int winding) const;
160 void appendPointToContour(const SkPoint& p, VertexList* contour) const;
161 void appendQuadraticToContour(const SkPoint[3], SkScalar toleranceSqd,
162 VertexList* contour) const;
163 void generateCubicPoints(const SkPoint&, const SkPoint&, const SkPoint&, const SkPoint&,
164 SkScalar tolSqd, VertexList* contour, int pointsLeft) const;
165 bool applyFillType(int winding) const;
166 MonotonePoly* allocateMonotonePoly(Edge* edge, Side side, int winding);
167 Edge* allocateEdge(Vertex* top, Vertex* bottom, int winding, EdgeType type);
169 [[nodiscard]] bool setTop(
170 Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, const Comparator&) const;
171 [[nodiscard]] bool setBottom(
172 Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, const Comparator&) const;
173 [[nodiscard]] bool mergeEdgesAbove(
174 Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current, const Comparator&) const;
175 [[nodiscard]] bool mergeEdgesBelow(
176 Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current, const Comparator&) const;
178 int windingScale = 1);
179 void mergeVertices(Vertex* src, Vertex* dst, VertexList* mesh, const Comparator&) const;
180 static void FindEnclosingEdges(const Vertex& v, const EdgeList& edges,
181 Edge** left, Edge** right);
182 bool mergeCollinearEdges(Edge* edge, EdgeList* activeEdges, Vertex** current,
183 const Comparator&) const;
184 BoolFail splitEdge(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
185 const Comparator&);
186 BoolFail intersectEdgePair(Edge* left, Edge* right, EdgeList* activeEdges, Vertex** current,
187 const Comparator&);
188 Vertex* makeSortedVertex(const SkPoint&, uint8_t alpha, VertexList* mesh, Vertex* reference,
189 const Comparator&) const;
190 void computeBisector(Edge* edge1, Edge* edge2, Vertex*) const;
191 BoolFail checkForIntersection(Edge* left, Edge* right, EdgeList* activeEdges, Vertex** current,
192 VertexList* mesh, const Comparator&);
193 void sanitizeContours(VertexList* contours, int contourCnt) const;
194 bool mergeCoincidentVertices(VertexList* mesh, const Comparator&) const;
195 void buildEdges(VertexList* contours, int contourCnt, VertexList* mesh,
196 const Comparator&);
197 std::tuple<Poly*, bool> contoursToPolys(VertexList* contours, int contourCnt);
198 std::tuple<Poly*, bool> pathToPolys(float tolerance, const SkRect& clipBounds,
199 bool* isLinear);
200 static int64_t CountPoints(Poly* polys, SkPathFillType overrideFillType);
202
203 // FIXME: fPath should be plumbed through function parameters instead.
207 int fNumEdges = 0;
208
209 // Internal control knobs.
211 bool fEmitCoverage = false;
214
215 // The breadcrumb triangles serve as a glue that erases T-junctions between a path's outer
216 // curves and its inner polygon triangulation. Drawing a path's outer curves, breadcrumb
217 // triangles, and inner polygon triangulation all together into the stencil buffer has the same
218 // identical rasterized effect as stenciling a classic Redbook fan.
219 //
220 // The breadcrumb triangles track all the edge splits that led from the original inner polygon
221 // edges to the final triangulation. Every time an edge splits, we emit a razor-thin breadcrumb
222 // triangle consisting of the edge's original endpoints and the split point. (We also add
223 // supplemental breadcrumb triangles to areas where abs(winding) > 1.)
224 //
225 // a
226 // /
227 // /
228 // /
229 // x <- Edge splits at x. New breadcrumb triangle is: [a, b, x].
230 // /
231 // /
232 // b
233 //
234 // The opposite-direction shared edges between the triangulation and breadcrumb triangles should
235 // all cancel out, leaving just the set of edges from the original polygon.
237 public:
238 struct Node {
241 Node* fNext = nullptr;
242 };
243 const Node* head() const { return fHead; }
244 int count() const { return fCount; }
245
246 void append(SkArenaAlloc* alloc, SkPoint a, SkPoint b, SkPoint c, int winding) {
247 if (a == b || a == c || b == c || winding == 0) {
248 return;
249 }
250 if (winding < 0) {
251 std::swap(a, b);
252 winding = -winding;
253 }
254 for (int i = 0; i < winding; ++i) {
255 SkASSERT(fTail && !(*fTail));
256 *fTail = alloc->make<Node>(a, b, c);
257 fTail = &(*fTail)->fNext;
258 }
259 fCount += winding;
260 }
261
263 SkASSERT(fTail && !(*fTail));
264 if (list.fHead) {
265 *fTail = list.fHead;
266 fTail = list.fTail;
267 fCount += list.fCount;
268 list.fHead = nullptr;
269 list.fTail = &list.fHead;
270 list.fCount = 0;
271 }
272 }
273
274 private:
275 Node* fHead = nullptr;
276 Node** fTail = &fHead;
277 int fCount = 0;
278 };
279
281};
282
283/**
284 * Vertices are used in three ways: first, the path contours are converted into a
285 * circularly-linked list of Vertices for each contour. After edge construction, the same Vertices
286 * are re-ordered by the merge sort according to the sweep_lt comparator (usually, increasing
287 * in Y) using the same fPrev/fNext pointers that were used for the contours, to avoid
288 * reallocation. Finally, MonotonePolys are built containing a circularly-linked list of
289 * Vertices. (Currently, those Vertices are newly-allocated for the MonotonePolys, since
290 * an individual Vertex from the path mesh may belong to multiple
291 * MonotonePolys, so the original Vertices cannot be re-used.
292 */
293
295 Vertex(const SkPoint& point, uint8_t alpha)
296 : fPoint(point), fPrev(nullptr), fNext(nullptr)
297 , fFirstEdgeAbove(nullptr), fLastEdgeAbove(nullptr)
298 , fFirstEdgeBelow(nullptr), fLastEdgeBelow(nullptr)
299 , fLeftEnclosingEdge(nullptr), fRightEnclosingEdge(nullptr)
300 , fPartner(nullptr)
301 , fAlpha(alpha)
302 , fSynthetic(false)
304 , fID (-1.0f)
305#endif
306 {}
307 SkPoint fPoint; // Vertex position
308 Vertex* fPrev; // Linked list of contours, then Y-sorted vertices.
310 Edge* fFirstEdgeAbove; // Linked list of edges above this vertex.
312 Edge* fFirstEdgeBelow; // Linked list of edges below this vertex.
314 Edge* fLeftEnclosingEdge; // Nearest edge in the AEL left of this vertex.
315 Edge* fRightEnclosingEdge; // Nearest edge in the AEL right of this vertex.
316 Vertex* fPartner; // Corresponding inner or outer vertex (for AA).
317 uint8_t fAlpha;
318 bool fSynthetic; // Is this a synthetic vertex?
319#if TRIANGULATOR_LOGGING
320 float fID; // Identifier used for logging.
321#endif
322 bool isConnected() const { return this->fFirstEdgeAbove || this->fFirstEdgeBelow; }
323};
324
326 VertexList() : fHead(nullptr), fTail(nullptr) {}
327 VertexList(Vertex* head, Vertex* tail) : fHead(head), fTail(tail) {}
330 void insert(Vertex* v, Vertex* prev, Vertex* next);
331 void append(Vertex* v) { insert(v, fTail, nullptr); }
332 void append(const VertexList& list) {
333 if (!list.fHead) {
334 return;
335 }
336 if (fTail) {
337 fTail->fNext = list.fHead;
338 list.fHead->fPrev = fTail;
339 } else {
340 fHead = list.fHead;
341 }
342 fTail = list.fTail;
343 }
344 void prepend(Vertex* v) { insert(v, nullptr, fHead); }
345 void remove(Vertex* v);
346 void close() {
347 if (fHead && fTail) {
348 fTail->fNext = fHead;
349 fHead->fPrev = fTail;
350 }
351 }
352#if TRIANGULATOR_LOGGING
353 void dump() const;
354#endif
355};
356
357// A line equation in implicit form. fA * x + fB * y + fC = 0, for all points (x, y) on the line.
359 Line(double a, double b, double c) : fA(a), fB(b), fC(c) {}
360 Line(Vertex* p, Vertex* q) : Line(p->fPoint, q->fPoint) {}
361 Line(const SkPoint& p, const SkPoint& q)
362 : fA(static_cast<double>(q.fY) - p.fY) // a = dY
363 , fB(static_cast<double>(p.fX) - q.fX) // b = -dX
364 , fC(static_cast<double>(p.fY) * q.fX - // c = cross(q, p)
365 static_cast<double>(p.fX) * q.fY) {}
366 double dist(const SkPoint& p) const { return fA * p.fX + fB * p.fY + fC; }
367 Line operator*(double v) const { return Line(fA * v, fB * v, fC * v); }
368 double magSq() const { return fA * fA + fB * fB; }
369 void normalize() {
370 double len = sqrt(this->magSq());
371 if (len == 0.0) {
372 return;
373 }
374 double scale = 1.0f / len;
375 fA *= scale;
376 fB *= scale;
377 fC *= scale;
378 }
379 bool nearParallel(const Line& o) const {
380 return fabs(o.fA - fA) < 0.00001 && fabs(o.fB - fB) < 0.00001;
381 }
382
383 // Compute the intersection of two (infinite) Lines.
384 bool intersect(const Line& other, SkPoint* point) const;
385 double fA, fB, fC;
386};
387
388/**
389 * An Edge joins a top Vertex to a bottom Vertex. Edge ordering for the list of "edges above" and
390 * "edge below" a vertex as well as for the active edge list is handled by isLeftOf()/isRightOf().
391 * Note that an Edge will give occasionally dist() != 0 for its own endpoints (because floating
392 * point). For speed, that case is only tested by the callers that require it (e.g.,
393 * rewind_if_necessary()). Edges also handle checking for intersection with other edges.
394 * Currently, this converts the edges to the parametric form, in order to avoid doing a division
395 * until an intersection has been confirmed. This is slightly slower in the "found" case, but
396 * a lot faster in the "not found" case.
397 *
398 * The coefficients of the line equation stored in double precision to avoid catastrophic
399 * cancellation in the isLeftOf() and isRightOf() checks. Using doubles ensures that the result is
400 * correct in float, since it's a polynomial of degree 2. The intersect() function, being
401 * degree 5, is still subject to catastrophic cancellation. We deal with that by assuming its
402 * output may be incorrect, and adjusting the mesh topology to match (see comment at the top of
403 * this file).
404 */
405
407 Edge(Vertex* top, Vertex* bottom, int winding, EdgeType type)
408 : fWinding(winding)
409 , fTop(top)
410 , fBottom(bottom)
411 , fType(type)
412 , fLeft(nullptr)
413 , fRight(nullptr)
414 , fPrevEdgeAbove(nullptr)
415 , fNextEdgeAbove(nullptr)
416 , fPrevEdgeBelow(nullptr)
417 , fNextEdgeBelow(nullptr)
418 , fLeftPoly(nullptr)
419 , fRightPoly(nullptr)
420 , fLeftPolyPrev(nullptr)
421 , fLeftPolyNext(nullptr)
422 , fRightPolyPrev(nullptr)
423 , fRightPolyNext(nullptr)
424 , fUsedInLeftPoly(false)
425 , fUsedInRightPoly(false)
426 , fLine(top, bottom) {
427 }
428 int fWinding; // 1 == edge goes downward; -1 = edge goes upward.
429 Vertex* fTop; // The top vertex in vertex-sort-order (sweep_lt).
430 Vertex* fBottom; // The bottom vertex in vertex-sort-order.
432 Edge* fLeft; // The linked list of edges in the active edge list.
434 Edge* fPrevEdgeAbove; // The linked list of edges in the bottom Vertex's "edges above".
436 Edge* fPrevEdgeBelow; // The linked list of edges in the top Vertex's "edges below".
438 Poly* fLeftPoly; // The Poly to the left of this edge, if any.
439 Poly* fRightPoly; // The Poly to the right of this edge, if any.
447
448 double dist(const SkPoint& p) const {
449 // Coerce points coincident with the vertices to have dist = 0, since converting from
450 // a double intersection point back to float storage might construct a point that's no
451 // longer on the ideal line.
452 return (p == fTop->fPoint || p == fBottom->fPoint) ? 0.0 : fLine.dist(p);
453 }
454 bool isRightOf(const Vertex& v) const { return this->dist(v.fPoint) < 0.0; }
455 bool isLeftOf(const Vertex& v) const { return this->dist(v.fPoint) > 0.0; }
457 void insertAbove(Vertex*, const Comparator&);
458 void insertBelow(Vertex*, const Comparator&);
459 void disconnect();
460 bool intersect(const Edge& other, SkPoint* p, uint8_t* alpha = nullptr) const;
461};
462
464 EdgeList() : fHead(nullptr), fTail(nullptr) {}
467 void insert(Edge* edge, Edge* prev, Edge* next);
468 bool insert(Edge* edge, Edge* prev);
469 void append(Edge* e) { insert(e, fTail, nullptr); }
470 bool remove(Edge* edge);
471 void removeAll() {
472 while (fHead) {
473 this->remove(fHead);
474 }
475 }
476 void close() {
477 if (fHead && fTail) {
478 fTail->fRight = fHead;
479 fHead->fLeft = fTail;
480 }
481 }
482 bool contains(Edge* edge) const { return edge->fLeft || edge->fRight || fHead == edge; }
483};
484
486 MonotonePoly(Edge* edge, Side side, int winding)
487 : fSide(side)
488 , fFirstEdge(nullptr)
489 , fLastEdge(nullptr)
490 , fPrev(nullptr)
491 , fNext(nullptr)
492 , fWinding(winding) {
493 this->addEdge(edge);
494 }
501 void addEdge(Edge*);
502};
503
505 Poly(Vertex* v, int winding);
506
516#if TRIANGULATOR_LOGGING
517 int fID;
518#endif
519};
520
523 Comparator(Direction direction) : fDirection(direction) {}
524 bool sweep_lt(const SkPoint& a, const SkPoint& b) const;
526};
527
528#endif // SK_ENABLE_OPTIMIZE_SIZE
529
530#endif // GrTriangulator_DEFINED
int count
#define TRIANGULATOR_LOGGING
static float next(float f)
static float prev(float f)
#define SkASSERT(cond)
Definition SkAssert.h:116
static int side(double x)
SkPathFillType
Definition SkPathTypes.h:11
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
static void dump(const float m[20], SkYUVColorSpace cs, bool rgb2yuv)
void concat(BreadcrumbTriangleList &&list)
void append(SkArenaAlloc *alloc, SkPoint a, SkPoint b, SkPoint c, int winding)
void contoursToMesh(VertexList *contours, int contourCnt, VertexList *mesh, const Comparator &)
GrTriangulator(const SkPath &path, SkArenaAlloc *alloc)
std::tuple< Poly *, bool > pathToPolys(float tolerance, const SkRect &clipBounds, bool *isLinear)
skgpu::VertexWriter emitMonotonePoly(const MonotonePoly *, skgpu::VertexWriter data) const
static int64_t CountPoints(Poly *polys, SkPathFillType overrideFillType)
static void SortMesh(VertexList *vertices, const Comparator &)
bool mergeCollinearEdges(Edge *edge, EdgeList *activeEdges, Vertex **current, const Comparator &) const
Edge * allocateEdge(Vertex *top, Vertex *bottom, int winding, EdgeType type)
bool setTop(Edge *edge, Vertex *v, EdgeList *activeEdges, Vertex **current, const Comparator &) const
bool fPreserveCollinearVertices
Edge * makeEdge(Vertex *prev, Vertex *next, EdgeType type, const Comparator &)
SkArenaAlloc *const fAlloc
void buildEdges(VertexList *contours, int contourCnt, VertexList *mesh, const Comparator &)
bool fCollectBreadcrumbTriangles
BreadcrumbTriangleList fBreadcrumbList
bool applyFillType(int winding) const
MonotonePoly * allocateMonotonePoly(Edge *edge, Side side, int winding)
SimplifyResult simplify(VertexList *mesh, const Comparator &)
virtual std::tuple< Poly *, bool > tessellate(const VertexList &vertices, const Comparator &)
Poly * makePoly(Poly **head, Vertex *v, int winding) const
static int PathToTriangles(const SkPath &path, SkScalar tolerance, const SkRect &clipBounds, GrEagerVertexAllocator *vertexAllocator, bool *isLinear)
skgpu::VertexWriter polysToTriangles(Poly *polys, SkPathFillType overrideFillType, skgpu::VertexWriter data) const
static void SortedMerge(VertexList *front, VertexList *back, VertexList *result, const Comparator &)
bool setBottom(Edge *edge, Vertex *v, EdgeList *activeEdges, Vertex **current, const Comparator &) const
bool fRoundVerticesToQuarterPixel
void pathToContours(float tolerance, const SkRect &clipBounds, VertexList *contours, bool *isLinear) const
Edge * makeConnectingEdge(Vertex *prev, Vertex *next, EdgeType, const Comparator &, int windingScale=1)
void mergeVertices(Vertex *src, Vertex *dst, VertexList *mesh, const Comparator &) const
const SkPath fPath
Vertex * makeSortedVertex(const SkPoint &, uint8_t alpha, VertexList *mesh, Vertex *reference, const Comparator &) const
skgpu::VertexWriter emitPoly(const Poly *, skgpu::VertexWriter data) const
bool mergeEdgesAbove(Edge *edge, Edge *other, EdgeList *activeEdges, Vertex **current, const Comparator &) const
void generateCubicPoints(const SkPoint &, const SkPoint &, const SkPoint &, const SkPoint &, SkScalar tolSqd, VertexList *contour, int pointsLeft) const
virtual ~GrTriangulator()
static void FindEnclosingEdges(const Vertex &v, const EdgeList &edges, Edge **left, Edge **right)
std::tuple< Poly *, bool > contoursToPolys(VertexList *contours, int contourCnt)
skgpu::VertexWriter emitTriangle(Vertex *prev, Vertex *curr, Vertex *next, int winding, skgpu::VertexWriter data) const
bool mergeCoincidentVertices(VertexList *mesh, const Comparator &) const
bool mergeEdgesBelow(Edge *edge, Edge *other, EdgeList *activeEdges, Vertex **current, const Comparator &) const
void sanitizeContours(VertexList *contours, int contourCnt) const
void appendQuadraticToContour(const SkPoint[3], SkScalar toleranceSqd, VertexList *contour) const
BoolFail intersectEdgePair(Edge *left, Edge *right, EdgeList *activeEdges, Vertex **current, const Comparator &)
BoolFail checkForIntersection(Edge *left, Edge *right, EdgeList *activeEdges, Vertex **current, VertexList *mesh, const Comparator &)
void appendPointToContour(const SkPoint &p, VertexList *contour) const
BoolFail splitEdge(Edge *edge, Vertex *v, EdgeList *activeEdges, Vertex **current, const Comparator &)
void computeBisector(Edge *edge1, Edge *edge2, Vertex *) const
static constexpr int kArenaDefaultChunkSize
auto make(Ctor &&ctor) -> decltype(ctor(nullptr))
float SkScalar
Definition extension.cpp:12
static bool b
struct MyStruct a[10]
if(end==-1)
GAsyncResult * result
Definition dart.idl:29
const Scalar scale
Node(SkPoint a, SkPoint b, SkPoint c)
bool sweep_lt(const SkPoint &a, const SkPoint &b) const
Comparator(Direction direction)
void insert(Edge *edge, Edge *prev, Edge *next)
bool contains(Edge *edge) const
void insertBelow(Vertex *, const Comparator &)
bool isLeftOf(const Vertex &v) const
void insertAbove(Vertex *, const Comparator &)
bool isRightOf(const Vertex &v) const
Edge(Vertex *top, Vertex *bottom, int winding, EdgeType type)
double dist(const SkPoint &p) const
bool intersect(const Edge &other, SkPoint *p, uint8_t *alpha=nullptr) const
bool nearParallel(const Line &o) const
double dist(const SkPoint &p) const
bool intersect(const Line &other, SkPoint *point) const
Line(Vertex *p, Vertex *q)
Line operator*(double v) const
Line(const SkPoint &p, const SkPoint &q)
Line(double a, double b, double c)
MonotonePoly(Edge *edge, Side side, int winding)
Vertex * lastVertex() const
Poly * addEdge(Edge *e, Side side, GrTriangulator *)
VertexList(Vertex *head, Vertex *tail)
void insert(Vertex *v, Vertex *prev, Vertex *next)
void append(const VertexList &list)
Vertex(const SkPoint &point, uint8_t alpha)