/* * Copyright 2018 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file.
*/ #include"include/core/SkPath.h" #include"include/core/SkPathBuilder.h" #include"include/core/SkPathTypes.h" #include"include/core/SkPoint.h" #include"include/core/SkRect.h" #include"include/core/SkScalar.h" #include"include/core/SkTypes.h" #include"include/pathops/SkPathOps.h" #include"include/private/base/SkMacros.h" #include"src/core/SkPathPriv.h" #include"src/pathops/SkPathOpsConic.h" #include"src/pathops/SkPathOpsCubic.h" #include"src/pathops/SkPathOpsCurve.h" #include"src/pathops/SkPathOpsPoint.h" #include"src/pathops/SkPathOpsQuad.h" #include"src/pathops/SkPathOpsTypes.h"
#include <algorithm> #include <vector>
using std::vector;
struct Contour { enumclass Direction { // SkPathDirection doesn't have 'none' state
kCCW = -1,
kNone,
kCW,
};
Contour(const SkRect& bounds, int lastStart, int verbStart)
: fBounds(bounds)
, fVerbStart(lastStart)
, fVerbEnd(verbStart) {
}
static Contour::Direction to_direction(SkScalar dy) { return dy > 0 ? Contour::Direction::kCCW : dy < 0 ? Contour::Direction::kCW :
Contour::Direction::kNone;
}
staticint contains_edge(SkPoint pts[4], SkPath::Verb verb, SkScalar weight, const SkPoint& edge) {
SkRect bounds;
bounds.setBounds(pts, kPtCount[verb] + 1); if (bounds.fTop > edge.fY) { return 0;
} if (bounds.fBottom <= edge.fY) { // check to see if y is at line end to avoid double counting return 0;
} if (bounds.fLeft >= edge.fX) { return 0;
} int winding = 0; double tVals[3];
Contour::Direction directions[3]; // must intersect horz ray with curve in case it intersects more than once int count = (*CurveIntercept[verb * 2])(pts, weight, edge.fY, tVals);
SkASSERT(between(0, count, 3)); // remove results to the right of edge for (int index = 0; index < count; ) {
SkScalar intersectX = (*CurvePointAtT[verb])(pts, weight, tVals[index]).fX; if (intersectX < edge.fX) {
++index; continue;
} if (intersectX > edge.fX) {
tVals[index] = tVals[--count]; continue;
} // if intersect x equals edge x, we need to determine if pts is to the left or right of edge if (pts[0].fX < edge.fX && pts[kPtCount[verb]].fX < edge.fX) {
++index; continue;
} // TODO : other cases need discriminating. need op angle code to figure it out // example: edge ends 45 degree diagonal going up. If pts is to the left of edge, keep. // if pts is to the right of edge, discard. With code as is, can't distiguish the two cases.
tVals[index] = tVals[--count];
} // use first derivative to determine if intersection is contributing +1 or -1 to winding for (int index = 0; index < count; ++index) {
directions[index] = to_direction((*CurveSlopeAtT[verb])(pts, weight, tVals[index]).fY);
} for (int index = 0; index < count; ++index) { // skip intersections that end at edge and go up if (zero_or_one(tVals[index]) && Contour::Direction::kCCW != directions[index]) { continue;
}
winding += (int) directions[index];
} return winding; // note winding indicates containership, not contour direction
}
int nextEdge(Contour& contour, Edge edge) {
SkPath::Iter iter(fPath, true);
SkPoint pts[4];
SkPath::Verb verb; int verbCount = -1; int winding = 0; do {
verb = iter.next(pts); if (++verbCount < contour.fVerbStart) { continue;
} if (verbCount >= contour.fVerbEnd) { continue;
} if (SkPath::kLine_Verb > verb || verb > SkPath::kCubic_Verb) { continue;
} bool horizontal = true; for (int index = 1; index <= kPtCount[verb]; ++index) { if (pts[0].fY != pts[index].fY) {
horizontal = false; break;
}
} if (horizontal) { continue;
} if (edge == Edge::kCompare) {
winding += contains_edge(pts, verb, conic_weight(iter, verb), contour.fMinXY); continue;
}
SkASSERT(edge == Edge::kInitial);
SkPoint minXY = left_edge(pts, verb, conic_weight(iter, verb)); if (minXY.fX > contour.fMinXY.fX) { continue;
} if (minXY.fX == contour.fMinXY.fX) { if (minXY.fY != contour.fMinXY.fY) { continue;
}
}
contour.fMinXY = minXY;
} while (SkPath::kDone_Verb != verb); return winding;
}
bool containerContains(Contour& contour, Contour& test) { // find outside point on lesser contour // arbitrarily, choose non-horizontal edge where point <= bounds left // note that if leftmost point is control point, may need tight bounds // to find edge with minimum-x if (SK_ScalarMax == test.fMinXY.fX) {
this->nextEdge(test, Edge::kInitial);
} // find all edges on greater equal or to the left of one on lesser
contour.fMinXY = test.fMinXY; int winding = this->nextEdge(contour, Edge::kCompare); // if edge is up, mark contour cw, otherwise, ccw // sum of greater edges direction should be cw, 0, ccw
test.fContained = winding != 0; return -1 <= winding && winding <= 1;
}
void inParent(Contour& contour, Contour& parent) { // move contour into sibling list contained by parent for (auto test : parent.fChildren) { if (test->fBounds.contains(contour.fBounds)) {
inParent(contour, *test); return;
}
} // move parent's children into contour's children if contained by contour for (auto iter = parent.fChildren.begin(); iter != parent.fChildren.end(); ) { if (contour.fBounds.contains((*iter)->fBounds)) {
contour.fChildren.push_back(*iter);
iter = parent.fChildren.erase(iter); continue;
}
++iter;
}
parent.fChildren.push_back(&contour);
}
bool checkContainerChildren(Contour* parent, Contour* child) { for (auto grandChild : child->fChildren) { if (!checkContainerChildren(child, grandChild)) { returnfalse;
}
} if (parent) { if (!containerContains(*parent, *child)) { returnfalse;
}
} returntrue;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.