aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/concavepaths.cpp15
-rw-r--r--src/gpu/GrTessellator.cpp340
2 files changed, 188 insertions, 167 deletions
diff --git a/gm/concavepaths.cpp b/gm/concavepaths.cpp
index 890f6c0855..fe8a1418ab 100644
--- a/gm/concavepaths.cpp
+++ b/gm/concavepaths.cpp
@@ -159,6 +159,20 @@ void test_star(SkCanvas* canvas, const SkPaint& paint) {
canvas->restore();
}
+// Exercise a case where the intersection is below a bottom edge.
+void test_twist(SkCanvas* canvas, const SkPaint& paint) {
+ SkPath path;
+ canvas->save();
+ path.moveTo( 0.5, 6);
+ path.lineTo(5.8070392608642578125, 6.4612660408020019531);
+ path.lineTo(-2.9186885356903076172, 2.811046600341796875);
+ path.lineTo(0.49999994039535522461, -1.4124038219451904297);
+ canvas->translate(420, 220);
+ canvas->scale(10, 10);
+ canvas->drawPath(path, paint);
+ canvas->restore();
+}
+
// Stairstep with repeated vert (intersection)
void test_stairstep(SkCanvas* canvas, const SkPaint& paint) {
SkPath path;
@@ -409,6 +423,7 @@ DEF_SIMPLE_GM(concavepaths, canvas, 500, 600) {
test_fast_forward(canvas, paint);
test_hole(canvas, paint);
test_star(canvas, paint);
+ test_twist(canvas, paint);
test_inversion_repeat_vertex(canvas, paint);
test_stairstep(canvas, paint);
test_stairstep2(canvas, paint);
diff --git a/src/gpu/GrTessellator.cpp b/src/gpu/GrTessellator.cpp
index de14afe40e..6e9665f7c7 100644
--- a/src/gpu/GrTessellator.cpp
+++ b/src/gpu/GrTessellator.cpp
@@ -50,17 +50,15 @@
* line-sweep algorithm, but due to floating point inaccuracy, the intersection points are
* not exact and may violate the mesh topology or active edge list ordering. We
* accommodate this by adjusting the topology of the mesh and AEL to match the intersection
- * points. This occurs in three ways:
+ * points. This occurs in two ways:
*
* A) Intersections may cause a shortened edge to no longer be ordered with respect to its
* neighbouring edges at the top or bottom vertex. This is handled by merging the
* edges (merge_collinear_edges()).
* B) Intersections may cause an edge to violate the left-to-right ordering of the
- * active edge list. This is handled by splitting the neighbour edge on the
- * intersected vertex (cleanup_active_edges()).
- * C) Shortening an edge may cause an active edge to become inactive or an inactive edge
- * to become active. This is handled by removing or inserting the edge in the active
- * edge list (fix_active_state()).
+ * active edge list. This is handled by detecting potential violati0ns and rewinding
+ * the active edge list to the vertex before they occur (rewind() during merging,
+ * rewind_if_necessary() during splitting).
*
* The tessellation steps (5) and (6) are based on "Triangulating Simple Polygons and
* Equivalent Problems" (Fournier and Montuno); also a line-sweep algorithm. Note that it
@@ -145,25 +143,26 @@ struct Vertex {
: fPoint(point), fPrev(nullptr), fNext(nullptr)
, fFirstEdgeAbove(nullptr), fLastEdgeAbove(nullptr)
, fFirstEdgeBelow(nullptr), fLastEdgeBelow(nullptr)
+ , fLeftEnclosingEdge(nullptr), fRightEnclosingEdge(nullptr)
, fPartner(nullptr)
- , fProcessed(false)
, fAlpha(alpha)
#if LOGGING_ENABLED
, fID (-1.0f)
#endif
{}
- SkPoint fPoint; // Vertex position
- Vertex* fPrev; // Linked list of contours, then Y-sorted vertices.
- Vertex* fNext; // "
- Edge* fFirstEdgeAbove; // Linked list of edges above this vertex.
- Edge* fLastEdgeAbove; // "
- Edge* fFirstEdgeBelow; // Linked list of edges below this vertex.
- Edge* fLastEdgeBelow; // "
- Vertex* fPartner; // Corresponding inner or outer vertex (for AA).
- bool fProcessed; // Has this vertex been seen in simplify()?
+ SkPoint fPoint; // Vertex position
+ Vertex* fPrev; // Linked list of contours, then Y-sorted vertices.
+ Vertex* fNext; // "
+ Edge* fFirstEdgeAbove; // Linked list of edges above this vertex.
+ Edge* fLastEdgeAbove; // "
+ Edge* fFirstEdgeBelow; // Linked list of edges below this vertex.
+ Edge* fLastEdgeBelow; // "
+ Edge* fLeftEnclosingEdge; // Nearest edge in the AEL left of this vertex.
+ Edge* fRightEnclosingEdge; // Nearest edge in the AEL right of this vertex.
+ Vertex* fPartner; // Corresponding inner or outer vertex (for AA).
uint8_t fAlpha;
#if LOGGING_ENABLED
- float fID; // Identifier used for logging.
+ float fID; // Identifier used for logging.
#endif
};
@@ -312,7 +311,7 @@ struct Line {
* "edge below" a vertex as well as for the active edge list is handled by isLeftOf()/isRightOf().
* Note that an Edge will give occasionally dist() != 0 for its own endpoints (because floating
* point). For speed, that case is only tested by the callers that require it (e.g.,
- * cleanup_active_edges()). Edges also handle checking for intersection with other edges.
+ * rewind_if_necessary()). Edges also handle checking for intersection with other edges.
* Currently, this converts the edges to the parametric form, in order to avoid doing a division
* until an intersection has been confirmed. This is slightly slower in the "found" case, but
* a lot faster in the "not found" case.
@@ -808,40 +807,6 @@ void find_enclosing_edges(Vertex* v, EdgeList* edges, Edge** left, Edge** right)
*right = next;
}
-void find_enclosing_edges(Edge* edge, EdgeList* edges, Comparator& c, Edge** left, Edge** right) {
- Edge* prev = nullptr;
- Edge* next;
- for (next = edges->fHead; next != nullptr; next = next->fRight) {
- if ((c.sweep_lt(next->fTop->fPoint, edge->fTop->fPoint) && next->isRightOf(edge->fTop)) ||
- (c.sweep_lt(edge->fTop->fPoint, next->fTop->fPoint) && edge->isLeftOf(next->fTop)) ||
- (c.sweep_lt(edge->fBottom->fPoint, next->fBottom->fPoint) &&
- next->isRightOf(edge->fBottom)) ||
- (c.sweep_lt(next->fBottom->fPoint, edge->fBottom->fPoint) &&
- edge->isLeftOf(next->fBottom))) {
- break;
- }
- prev = next;
- }
- *left = prev;
- *right = next;
-}
-
-void fix_active_state(Edge* edge, EdgeList* activeEdges, Comparator& c) {
- if (!activeEdges) {
- return;
- }
- if (activeEdges->contains(edge)) {
- if (edge->fBottom->fProcessed || !edge->fTop->fProcessed) {
- remove_edge(edge, activeEdges);
- }
- } else if (edge->fTop->fProcessed && !edge->fBottom->fProcessed) {
- Edge* left;
- Edge* right;
- find_enclosing_edges(edge, activeEdges, c, &left, &right);
- insert_edge(edge, left, activeEdges);
- }
-}
-
void insert_edge_above(Edge* edge, Vertex* v, Comparator& c) {
if (edge->fTop->fPoint == edge->fBottom->fPoint ||
c.sweep_lt(edge->fBottom->fPoint, edge->fTop->fPoint)) {
@@ -898,80 +863,137 @@ void disconnect(Edge* edge)
remove_edge_below(edge);
}
-void erase_edge(Edge* edge, EdgeList* edges) {
- LOG("erasing edge (%g -> %g)\n", edge->fTop->fID, edge->fBottom->fID);
- disconnect(edge);
- if (edges && edges->contains(edge)) {
- remove_edge(edge, edges);
+void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Vertex** current, Comparator& c);
+
+void rewind(EdgeList* activeEdges, Vertex** current, Vertex* dst, Comparator& c) {
+ if (!current || *current == dst || c.sweep_lt((*current)->fPoint, dst->fPoint)) {
+ return;
}
+ Vertex* v = *current;
+ LOG("rewinding active edges from vertex %g to vertex %g\n", v->fID, dst->fID);
+ while (v != dst) {
+ v = v->fPrev;
+ for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
+ remove_edge(e, activeEdges);
+ }
+ Edge* leftEdge = v->fLeftEnclosingEdge;
+ for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
+ insert_edge(e, leftEdge, activeEdges);
+ leftEdge = e;
+ }
+ }
+ *current = v;
}
-void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Comparator& c);
+void rewind_if_necessary(Edge* edge, EdgeList* activeEdges, Vertex** current, Comparator& c) {
+ if (!activeEdges || !current) {
+ return;
+ }
+ Vertex* top = edge->fTop;
+ Vertex* bottom = edge->fBottom;
+ if (edge->fLeft) {
+ Vertex* leftTop = edge->fLeft->fTop;
+ Vertex* leftBottom = edge->fLeft->fBottom;
+ if (c.sweep_lt(leftTop->fPoint, top->fPoint) && !edge->fLeft->isLeftOf(top)) {
+ rewind(activeEdges, current, leftTop, c);
+ } else if (c.sweep_lt(top->fPoint, leftTop->fPoint) && !edge->isRightOf(leftTop)) {
+ rewind(activeEdges, current, top, c);
+ } else if (c.sweep_lt(bottom->fPoint, leftBottom->fPoint) &&
+ !edge->fLeft->isLeftOf(bottom)) {
+ rewind(activeEdges, current, leftTop, c);
+ } else if (c.sweep_lt(leftBottom->fPoint, bottom->fPoint) && !edge->isRightOf(leftBottom)) {
+ rewind(activeEdges, current, top, c);
+ }
+ }
+ if (edge->fRight) {
+ Vertex* rightTop = edge->fRight->fTop;
+ Vertex* rightBottom = edge->fRight->fBottom;
+ if (c.sweep_lt(rightTop->fPoint, top->fPoint) && !edge->fRight->isRightOf(top)) {
+ rewind(activeEdges, current, rightTop, c);
+ } else if (c.sweep_lt(top->fPoint, rightTop->fPoint) && !edge->isLeftOf(rightTop)) {
+ rewind(activeEdges, current, top, c);
+ } else if (c.sweep_lt(bottom->fPoint, rightBottom->fPoint) &&
+ !edge->fRight->isRightOf(bottom)) {
+ rewind(activeEdges, current, rightTop, c);
+ } else if (c.sweep_lt(rightBottom->fPoint, bottom->fPoint) &&
+ !edge->isLeftOf(rightBottom)) {
+ rewind(activeEdges, current, top, c);
+ }
+ }
+}
-void set_top(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c) {
+void set_top(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, Comparator& c) {
remove_edge_below(edge);
edge->fTop = v;
edge->recompute();
insert_edge_below(edge, v, c);
- fix_active_state(edge, activeEdges, c);
- merge_collinear_edges(edge, activeEdges, c);
+ rewind_if_necessary(edge, activeEdges, current, c);
+ merge_collinear_edges(edge, activeEdges, current, c);
}
-void set_bottom(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c) {
+void set_bottom(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, Comparator& c) {
remove_edge_above(edge);
edge->fBottom = v;
edge->recompute();
insert_edge_above(edge, v, c);
- fix_active_state(edge, activeEdges, c);
- merge_collinear_edges(edge, activeEdges, c);
+ rewind_if_necessary(edge, activeEdges, current, c);
+ merge_collinear_edges(edge, activeEdges, current, c);
}
-void merge_edges_above(Edge* edge, Edge* other, EdgeList* activeEdges, Comparator& c) {
+void merge_edges_above(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current,
+ Comparator& c) {
if (coincident(edge->fTop->fPoint, other->fTop->fPoint)) {
LOG("merging coincident above edges (%g, %g) -> (%g, %g)\n",
edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
+ rewind(activeEdges, current, edge->fTop, c);
other->fWinding += edge->fWinding;
- erase_edge(edge, activeEdges);
+ disconnect(edge);
} else if (c.sweep_lt(edge->fTop->fPoint, other->fTop->fPoint)) {
+ rewind(activeEdges, current, edge->fTop, c);
other->fWinding += edge->fWinding;
- set_bottom(edge, other->fTop, activeEdges, c);
+ set_bottom(edge, other->fTop, activeEdges, current, c);
} else {
+ rewind(activeEdges, current, other->fTop, c);
edge->fWinding += other->fWinding;
- set_bottom(other, edge->fTop, activeEdges, c);
+ set_bottom(other, edge->fTop, activeEdges, current, c);
}
}
-void merge_edges_below(Edge* edge, Edge* other, EdgeList* activeEdges, Comparator& c) {
+void merge_edges_below(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current,
+ Comparator& c) {
if (coincident(edge->fBottom->fPoint, other->fBottom->fPoint)) {
LOG("merging coincident below edges (%g, %g) -> (%g, %g)\n",
edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
+ rewind(activeEdges, current, edge->fTop, c);
other->fWinding += edge->fWinding;
- erase_edge(edge, activeEdges);
+ disconnect(edge);
} else if (c.sweep_lt(edge->fBottom->fPoint, other->fBottom->fPoint)) {
+ rewind(activeEdges, current, other->fTop, c);
edge->fWinding += other->fWinding;
- set_top(other, edge->fBottom, activeEdges, c);
+ set_top(other, edge->fBottom, activeEdges, current, c);
} else {
+ rewind(activeEdges, current, edge->fTop, c);
other->fWinding += edge->fWinding;
- set_top(edge, other->fBottom, activeEdges, c);
+ set_top(edge, other->fBottom, activeEdges, current, c);
}
}
-void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Comparator& c) {
+void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Vertex** current, Comparator& c) {
for (;;) {
if (edge->fPrevEdgeAbove && (edge->fTop == edge->fPrevEdgeAbove->fTop ||
!edge->fPrevEdgeAbove->isLeftOf(edge->fTop))) {
- merge_edges_above(edge, edge->fPrevEdgeAbove, activeEdges, c);
+ merge_edges_above(edge, edge->fPrevEdgeAbove, activeEdges, current, c);
} else if (edge->fNextEdgeAbove && (edge->fTop == edge->fNextEdgeAbove->fTop ||
!edge->isLeftOf(edge->fNextEdgeAbove->fTop))) {
- merge_edges_above(edge, edge->fNextEdgeAbove, activeEdges, c);
+ merge_edges_above(edge, edge->fNextEdgeAbove, activeEdges, current, c);
} else if (edge->fPrevEdgeBelow && (edge->fBottom == edge->fPrevEdgeBelow->fBottom ||
!edge->fPrevEdgeBelow->isLeftOf(edge->fBottom))) {
- merge_edges_below(edge, edge->fPrevEdgeBelow, activeEdges, c);
+ merge_edges_below(edge, edge->fPrevEdgeBelow, activeEdges, current, c);
} else if (edge->fNextEdgeBelow && (edge->fBottom == edge->fNextEdgeBelow->fBottom ||
!edge->isLeftOf(edge->fNextEdgeBelow->fBottom))) {
- merge_edges_below(edge, edge->fNextEdgeBelow, activeEdges, c);
+ merge_edges_below(edge, edge->fNextEdgeBelow, activeEdges, current, c);
} else {
break;
}
@@ -982,59 +1004,30 @@ void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Comparator& c) {
SkASSERT(!edge->fNextEdgeBelow || edge->fNextEdgeBelow->isRightOf(edge->fBottom));
}
-void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c, SkArenaAlloc& alloc);
-
-void cleanup_active_edges(Edge* edge, EdgeList* activeEdges, Comparator& c, SkArenaAlloc& alloc) {
- Vertex* top = edge->fTop;
- Vertex* bottom = edge->fBottom;
- if (edge->fLeft) {
- Vertex* leftTop = edge->fLeft->fTop;
- Vertex* leftBottom = edge->fLeft->fBottom;
- if (c.sweep_lt(leftTop->fPoint, top->fPoint) && !edge->fLeft->isLeftOf(top)) {
- split_edge(edge->fLeft, edge->fTop, activeEdges, c, alloc);
- } else if (c.sweep_lt(top->fPoint, leftTop->fPoint) && !edge->isRightOf(leftTop)) {
- split_edge(edge, leftTop, activeEdges, c, alloc);
- } else if (c.sweep_lt(bottom->fPoint, leftBottom->fPoint) &&
- !edge->fLeft->isLeftOf(bottom)) {
- split_edge(edge->fLeft, bottom, activeEdges, c, alloc);
- } else if (c.sweep_lt(leftBottom->fPoint, bottom->fPoint) && !edge->isRightOf(leftBottom)) {
- split_edge(edge, leftBottom, activeEdges, c, alloc);
- }
- }
- if (edge->fRight) {
- Vertex* rightTop = edge->fRight->fTop;
- Vertex* rightBottom = edge->fRight->fBottom;
- if (c.sweep_lt(rightTop->fPoint, top->fPoint) && !edge->fRight->isRightOf(top)) {
- split_edge(edge->fRight, top, activeEdges, c, alloc);
- } else if (c.sweep_lt(top->fPoint, rightTop->fPoint) && !edge->isLeftOf(rightTop)) {
- split_edge(edge, rightTop, activeEdges, c, alloc);
- } else if (c.sweep_lt(bottom->fPoint, rightBottom->fPoint) &&
- !edge->fRight->isRightOf(bottom)) {
- split_edge(edge->fRight, bottom, activeEdges, c, alloc);
- } else if (c.sweep_lt(rightBottom->fPoint, bottom->fPoint) &&
- !edge->isLeftOf(rightBottom)) {
- split_edge(edge, rightBottom, activeEdges, c, alloc);
- }
- }
-}
-
-void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c, SkArenaAlloc& alloc) {
+void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, Comparator& c,
+ SkArenaAlloc& alloc) {
LOG("splitting edge (%g -> %g) at vertex %g (%g, %g)\n",
edge->fTop->fID, edge->fBottom->fID,
v->fID, v->fPoint.fX, v->fPoint.fY);
+ Vertex* top;
+ Vertex* bottom;
if (c.sweep_lt(v->fPoint, edge->fTop->fPoint)) {
- set_top(edge, v, activeEdges, c);
+ top = v;
+ bottom = edge->fTop;
+ set_top(edge, v, activeEdges, current, c);
} else if (c.sweep_lt(edge->fBottom->fPoint, v->fPoint)) {
- set_bottom(edge, v, activeEdges, c);
+ top = edge->fBottom;
+ bottom = v;
+ set_bottom(edge, v, activeEdges, current, c);
} else {
- Edge* newEdge = alloc.make<Edge>(v, edge->fBottom, edge->fWinding, edge->fType);
- insert_edge_below(newEdge, v, c);
- insert_edge_above(newEdge, edge->fBottom, c);
- set_bottom(edge, v, activeEdges, c);
- cleanup_active_edges(edge, activeEdges, c, alloc);
- fix_active_state(newEdge, activeEdges, c);
- merge_collinear_edges(newEdge, activeEdges, c);
+ top = v;
+ bottom = edge->fBottom;
+ set_bottom(edge, v, activeEdges, current, c);
}
+ Edge* newEdge = alloc.make<Edge>(top, bottom, edge->fWinding, edge->fType);
+ insert_edge_below(newEdge, top, c);
+ insert_edge_above(newEdge, bottom, c);
+ merge_collinear_edges(newEdge, activeEdges, current, c);
}
Edge* connect(Vertex* prev, Vertex* next, Edge::Type type, Comparator& c, SkArenaAlloc& alloc,
@@ -1043,7 +1036,7 @@ Edge* connect(Vertex* prev, Vertex* next, Edge::Type type, Comparator& c, SkAren
insert_edge_below(edge, edge->fTop, c);
insert_edge_above(edge, edge->fBottom, c);
edge->fWinding *= winding_scale;
- merge_collinear_edges(edge, nullptr, c);
+ merge_collinear_edges(edge, nullptr, nullptr, c);
return edge;
}
@@ -1057,12 +1050,12 @@ void merge_vertices(Vertex* src, Vertex* dst, VertexList* mesh, Comparator& c,
}
for (Edge* edge = src->fFirstEdgeAbove; edge;) {
Edge* next = edge->fNextEdgeAbove;
- set_bottom(edge, dst, nullptr, c);
+ set_bottom(edge, dst, nullptr, nullptr, c);
edge = next;
}
for (Edge* edge = src->fFirstEdgeBelow; edge;) {
Edge* next = edge->fNextEdgeBelow;
- set_top(edge, dst, nullptr, c);
+ set_top(edge, dst, nullptr, nullptr, c);
edge = next;
}
mesh->remove(src);
@@ -1079,61 +1072,69 @@ uint8_t max_edge_alpha(Edge* a, Edge* b) {
}
}
-Vertex* check_for_intersection(Edge* edge, Edge* other, EdgeList* activeEdges, Comparator& c,
- SkArenaAlloc& alloc) {
+bool check_for_intersection(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current,
+ Comparator& c, SkArenaAlloc& alloc) {
if (!edge || !other) {
- return nullptr;
+ return false;
}
SkPoint p;
uint8_t alpha;
if (edge->intersect(*other, &p, &alpha)) {
Vertex* v;
LOG("found intersection, pt is %g, %g\n", p.fX, p.fY);
- if (p == edge->fTop->fPoint || c.sweep_lt(p, edge->fTop->fPoint)) {
- split_edge(other, edge->fTop, activeEdges, c, alloc);
+ Vertex* top = *current;
+ // If the intersection point is above the current vertex, rewind to the vertex above the
+ // intersection.
+ while (c.sweep_lt(p, top->fPoint) && top->fPrev) {
+ top = top->fPrev;
+ }
+ rewind(activeEdges, current, top, c);
+ if (p == edge->fTop->fPoint) {
+ split_edge(other, edge->fTop, activeEdges, current, c, alloc);
v = edge->fTop;
- } else if (p == edge->fBottom->fPoint || c.sweep_lt(edge->fBottom->fPoint, p)) {
- split_edge(other, edge->fBottom, activeEdges, c, alloc);
+ } else if (p == edge->fBottom->fPoint) {
+ split_edge(other, edge->fBottom, activeEdges, current, c, alloc);
v = edge->fBottom;
- } else if (p == other->fTop->fPoint || c.sweep_lt(p, other->fTop->fPoint)) {
- split_edge(edge, other->fTop, activeEdges, c, alloc);
+ } else if (p == other->fTop->fPoint) {
+ split_edge(edge, other->fTop, activeEdges, current, c, alloc);
v = other->fTop;
- } else if (p == other->fBottom->fPoint || c.sweep_lt(other->fBottom->fPoint, p)) {
- split_edge(edge, other->fBottom, activeEdges, c, alloc);
+ } else if (p == other->fBottom->fPoint) {
+ split_edge(edge, other->fBottom, activeEdges, current, c, alloc);
v = other->fBottom;
} else {
- Vertex* nextV = edge->fTop;
- while (c.sweep_lt(p, nextV->fPoint)) {
- nextV = nextV->fPrev;
- }
- while (c.sweep_lt(nextV->fPoint, p)) {
+ Vertex* prevV = top;
+ Vertex* nextV = top->fNext;
+ while (nextV && c.sweep_lt(nextV->fPoint, p)) {
+ prevV = nextV;
nextV = nextV->fNext;
}
- Vertex* prevV = nextV->fPrev;
- if (coincident(prevV->fPoint, p)) {
+ if (prevV && coincident(prevV->fPoint, p)) {
v = prevV;
- } else if (coincident(nextV->fPoint, p)) {
+ } else if (nextV && coincident(nextV->fPoint, p)) {
v = nextV;
} else {
v = alloc.make<Vertex>(p, alpha);
- LOG("inserting between %g (%g, %g) and %g (%g, %g)\n",
- prevV->fID, prevV->fPoint.fX, prevV->fPoint.fY,
- nextV->fID, nextV->fPoint.fX, nextV->fPoint.fY);
#if LOGGING_ENABLED
- v->fID = (nextV->fID + prevV->fID) * 0.5f;
+ float prevID = prevV ? prevV->fID : 0.0f;
+ float nextID = nextV ? nextV->fID : prevV->fID + 1.0f;
+ v->fID = (prevID + nextID) * 0.5f;
#endif
v->fPrev = prevV;
v->fNext = nextV;
- prevV->fNext = v;
- nextV->fPrev = v;
+ if (prevV) {
+ prevV->fNext = v;
+ }
+ if (nextV) {
+ nextV->fPrev = v;
+ }
}
- split_edge(edge, v, activeEdges, c, alloc);
- split_edge(other, v, activeEdges, c, alloc);
+ split_edge(edge, v, activeEdges, current, c, alloc);
+ split_edge(other, v, activeEdges, current, c, alloc);
}
v->fAlpha = SkTMax(v->fAlpha, alpha);
- return v;
+ return true;
}
- return nullptr;
+ return false;
}
void sanitize_contours(VertexList* contours, int contourCnt, bool approximate) {
@@ -1224,6 +1225,12 @@ void sorted_merge(VertexList* front, VertexList* back, VertexList* result, Compa
} else {
sorted_merge<sweep_lt_vert>(front, back, result);
}
+#if LOGGING_ENABLED
+ float id = 0.0f;
+ for (Vertex* v = result->fHead; v; v = v->fNext) {
+ v->fID = id++;
+ }
+#endif
}
// Stage 3: sort the vertices by increasing sweep direction.
@@ -1265,37 +1272,37 @@ void simplify(const VertexList& vertices, Comparator& c, SkArenaAlloc& alloc) {
if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
continue;
}
-#if LOGGING_ENABLED
- LOG("\nvertex %g: (%g,%g), alpha %d\n", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
-#endif
Edge* leftEnclosingEdge;
Edge* rightEnclosingEdge;
bool restartChecks;
do {
+ LOG("\nvertex %g: (%g,%g), alpha %d\n", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
restartChecks = false;
find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
if (rightEnclosingEdge && !rightEnclosingEdge->isRightOf(v)) {
- split_edge(rightEnclosingEdge, v, &activeEdges, c, alloc);
+ split_edge(rightEnclosingEdge, v, &activeEdges, &v, c, alloc);
restartChecks = true;
continue;
}
+ SkASSERT(!rightEnclosingEdge || rightEnclosingEdge->isRightOf(v));
+ v->fLeftEnclosingEdge = leftEnclosingEdge;
+ v->fRightEnclosingEdge = rightEnclosingEdge;
if (v->fFirstEdgeBelow) {
for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) {
- if (check_for_intersection(edge, leftEnclosingEdge, &activeEdges, c, alloc)) {
+ if (check_for_intersection(edge, leftEnclosingEdge, &activeEdges, &v, c,
+ alloc)) {
restartChecks = true;
break;
}
- if (check_for_intersection(edge, rightEnclosingEdge, &activeEdges, c, alloc)) {
+ if (check_for_intersection(edge, rightEnclosingEdge, &activeEdges, &v, c,
+ alloc)) {
restartChecks = true;
break;
}
}
} else {
- if (Vertex* pv = check_for_intersection(leftEnclosingEdge, rightEnclosingEdge,
- &activeEdges, c, alloc)) {
- if (c.sweep_lt(pv->fPoint, v->fPoint)) {
- v = pv;
- }
+ if (check_for_intersection(leftEnclosingEdge, rightEnclosingEdge,
+ &activeEdges, &v, c, alloc)) {
restartChecks = true;
}
@@ -1315,7 +1322,6 @@ void simplify(const VertexList& vertices, Comparator& c, SkArenaAlloc& alloc) {
insert_edge(e, leftEdge, &activeEdges);
leftEdge = e;
}
- v->fProcessed = true;
}
}