Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(667)

Unified Diff: src/pathops/SkOpSegment.cpp

Issue 1037953004: add conics to path ops (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: turn off pathops specific debuggging Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/pathops/SkOpSegment.h ('k') | src/pathops/SkOpSpan.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/pathops/SkOpSegment.cpp
diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp
index c6ccf93003de931ba2fc5f72e58ff379f69b88d3..161eb33765de35bec78cc85ba9dbb736ced84480 100644
--- a/src/pathops/SkOpSegment.cpp
+++ b/src/pathops/SkOpSegment.cpp
@@ -122,8 +122,7 @@ SkPoint SkOpSegment::activeLeftTop(SkOpSpanBase** firstSpan) {
}
}
if (fVerb != SkPath::kLine_Verb && !lastDone) {
- SkPoint curveTop = (*CurveTop[SkPathOpsVerbToPoints(fVerb)])(fPts, lastT,
- span->t());
+ SkPoint curveTop = (*CurveTop[fVerb])(fPts, fWeight, lastT, span->t());
if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY
&& topPt.fX > curveTop.fX)) {
topPt = curveTop;
@@ -202,14 +201,17 @@ bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sum
void SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end,
SkPathWriter* path, bool active) const {
- SkPoint edge[4];
+ SkOpCurve edge;
const SkPoint* ePtr;
+ SkScalar eWeight;
if ((start == &fHead && end == &fTail) || (start == &fTail && end == &fHead)) {
ePtr = fPts;
+ eWeight = fWeight;
} else {
// OPTIMIZE? if not active, skip remainder and return xyAtT(end)
- subDivide(start, end, edge);
- ePtr = edge;
+ subDivide(start, end, &edge);
+ ePtr = edge.fPts;
+ eWeight = edge.fWeight;
}
if (active) {
bool reverse = ePtr == fPts && start != &fHead;
@@ -222,6 +224,9 @@ void SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end,
case SkPath::kQuad_Verb:
path->quadTo(ePtr[1], ePtr[0]);
break;
+ case SkPath::kConic_Verb:
+ path->conicTo(ePtr[1], ePtr[0], eWeight);
+ break;
case SkPath::kCubic_Verb:
path->cubicTo(ePtr[2], ePtr[1], ePtr[0]);
break;
@@ -237,6 +242,9 @@ void SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end,
case SkPath::kQuad_Verb:
path->quadTo(ePtr[1], ePtr[2]);
break;
+ case SkPath::kConic_Verb:
+ path->conicTo(ePtr[1], ePtr[2], eWeight);
+ break;
case SkPath::kCubic_Verb:
path->cubicTo(ePtr[1], ePtr[2], ePtr[3]);
break;
@@ -294,6 +302,9 @@ SkOpAngle* SkOpSegment::addSingletonAngleDown(SkOpSegment** otherPtr, SkOpAngle*
break;
}
}
+ if (!oStartSpan) {
+ return NULL;
+ }
SkOpAngle* oAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
oAngle->set(oStartSpan, oEndSpan);
oStartSpan->setToAngle(oAngle);
@@ -309,6 +320,9 @@ SkOpAngle* SkOpSegment::addSingletonAngles(int step, SkChunkAlloc* allocator) {
} else {
otherAngle = addSingletonAngleDown(&other, &angle, allocator);
}
+ if (!otherAngle) {
+ return NULL;
+ }
angle->insert(otherAngle);
return angle;
}
@@ -476,7 +490,7 @@ void SkOpSegment::checkAngleCoin(SkOpCoincidence* coincidences, SkChunkAlloc* al
// from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
bool SkOpSegment::clockwise(const SkOpSpanBase* start, const SkOpSpanBase* end, bool* swap) const {
SkASSERT(fVerb != SkPath::kLine_Verb);
- SkPoint edge[4];
+ SkOpCurve edge;
if (fVerb == SkPath::kCubic_Verb) {
double startT = start->t();
double endT = end->t();
@@ -489,22 +503,20 @@ bool SkOpSegment::clockwise(const SkOpSpanBase* start, const SkOpSpanBase* end,
double inflectionT = inflectionTs[index];
if (between(startT, inflectionT, endT)) {
if (flip) {
- if (inflectionT != endT) {
- startT = inflectionT;
+ if (!roughly_equal(inflectionT, endT)) {
+ startT = inflectionT;
}
} else {
- if (inflectionT != startT) {
+ if (!roughly_equal(inflectionT, startT)) {
endT = inflectionT;
}
}
}
}
SkDCubic part = cubic.subDivide(startT, endT);
- for (int index = 0; index < 4; ++index) {
- edge[index] = part[index].asSkPoint();
- }
+ edge.set(part);
} else {
- subDivide(start, end, edge);
+ subDivide(start, end, &edge);
}
bool sumSet = false;
int points = SkPathOpsVerbToPoints(fVerb);
@@ -516,11 +528,11 @@ bool SkOpSegment::clockwise(const SkOpSpanBase* start, const SkOpSpanBase* end,
}
if (fVerb == SkPath::kCubic_Verb) {
SkDCubic cubic;
- cubic.set(edge);
+ cubic.set(edge.fPts);
*swap = sum > 0 && !cubic.monotonicInY();
} else {
SkDQuad quad;
- quad.set(edge);
+ quad.set(edge.fPts);
*swap = sum > 0 && !quad.monotonicInY();
}
return sum <= 0;
@@ -682,8 +694,7 @@ SkOpSpan* SkOpSegment::crossedSpanY(const SkPoint& basePt, double mid, bool opp,
// OPTIMIZE: use specialty function that intersects ray with curve,
// returning t values only for curve (we don't care about t on ray)
intersections.allowNear(false);
- int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)])
- (fPts, top, bottom, basePt.fX, false);
+ int pts = (intersections.*CurveVertical[fVerb])(fPts, fWeight, top, bottom, basePt.fX, false);
if (pts == 0 || (current && pts == 1)) {
return NULL;
}
@@ -707,7 +718,7 @@ SkOpSpan* SkOpSegment::crossedSpanY(const SkPoint& basePt, double mid, bool opp,
|| approximately_greater_than_one(foundT)) {
continue;
}
- SkScalar testY = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fY;
+ SkScalar testY = (*CurvePointAtT[fVerb])(fPts, fWeight, foundT).fY;
if (approximately_negative(testY - *bestY)
|| approximately_negative(basePt.fY - testY)) {
continue;
@@ -717,7 +728,7 @@ SkOpSpan* SkOpSegment::crossedSpanY(const SkPoint& basePt, double mid, bool opp,
return NULL; // if the intersection is edge on, wait for another one
}
if (fVerb > SkPath::kLine_Verb) {
- SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fX;
+ SkScalar dx = (*CurveSlopeAtT[fVerb])(fPts, fWeight, foundT).fX;
if (approximately_zero(dx)) {
*vertical = true;
return NULL; // hit vertical, wait for another one
@@ -767,8 +778,7 @@ double SkOpSegment::distSq(double t, SkOpAngle* oppAngle) {
testPerp[1].fY -= slope.fX;
SkIntersections i;
SkOpSegment* oppSegment = oppAngle->segment();
- int oppPtCount = SkPathOpsVerbToPoints(oppSegment->verb());
- (*CurveIntersectRay[oppPtCount])(oppSegment->pts(), testPerp, &i);
+ (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weight(), testPerp, &i);
double closestDistSq = SK_ScalarInfinity;
for (int index = 0; index < i.used(); ++index) {
if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) {
@@ -1092,7 +1102,12 @@ SkOpSegment* SkOpSegment::findTop(bool firstPass, SkOpSpanBase** startPtr, SkOpS
if (!markAngle) {
markAngle = addSingletonAngles(step, allocator);
}
- markAngle->markStops();
+ if (!markAngle) {
+ return NULL;
+ }
+ if (!markAngle->markStops()) {
+ return NULL;
+ }
const SkOpAngle* baseAngle = markAngle->next() == markAngle && !isVertical() ? markAngle
: markAngle->findFirst();
if (!baseAngle) {
@@ -1161,6 +1176,7 @@ SkOpSegment* SkOpSegment::findTop(bool firstPass, SkOpSpanBase** startPtr, SkOpS
SkTSwap(*startPtr, *endPtr);
}
}
+ // FIXME: clockwise isn't reliable -- try computing swap from tangent ?
}
return leftSegment;
}
@@ -1169,10 +1185,11 @@ SkOpGlobalState* SkOpSegment::globalState() const {
return contour()->globalState();
}
-void SkOpSegment::init(SkPoint pts[], SkOpContour* contour, SkPath::Verb verb) {
+void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) {
fContour = contour;
fNext = NULL;
fPts = pts;
+ fWeight = weight;
fVerb = verb;
fCount = 0;
fDoneCount = 0;
@@ -1182,7 +1199,7 @@ void SkOpSegment::init(SkPoint pts[], SkOpContour* contour, SkPath::Verb verb) {
SkOpSpanBase* oneSpan = &fTail;
zeroSpan->setNext(oneSpan);
oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
- PATH_OPS_DEBUG_CODE(fID = globalState()->nextSegmentID());
+ SkDEBUGCODE(fID = globalState()->nextSegmentID());
}
void SkOpSegment::initWinding(SkOpSpanBase* start, SkOpSpanBase* end,
@@ -1215,7 +1232,7 @@ bool SkOpSegment::initWinding(SkOpSpanBase* start, SkOpSpanBase* end, double tHi
int winding, SkScalar hitDx, int oppWind, SkScalar hitOppDx) {
SkASSERT(this == start->segment());
SkASSERT(hitDx || !winding);
- SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
+ SkScalar dx = (*CurveSlopeAtT[fVerb])(fPts, fWeight, tHit).fX;
// SkASSERT(dx);
int windVal = start->starter(end)->windValue();
#if DEBUG_WINDING_AT_T
@@ -1249,12 +1266,10 @@ bool SkOpSegment::initWinding(SkOpSpanBase* start, SkOpSpanBase* end, double tHi
bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
SkDPoint cPt = this->dPtAtT(t);
- int pts = SkPathOpsVerbToPoints(this->verb());
- SkDVector dxdy = (*CurveDSlopeAtT[pts])(this->pts(), t);
+ SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t);
SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
SkIntersections i;
- int oppPts = SkPathOpsVerbToPoints(opp->verb());
- (*CurveIntersectRay[oppPts])(opp->pts(), perp, &i);
+ (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i);
int used = i.used();
for (int index = 0; index < used; ++index) {
if (cPt.roughlyEqual(i.pt(index))) {
@@ -1453,6 +1468,10 @@ bool SkOpSegment::monotonicInY(const SkOpSpanBase* start, const SkOpSpanBase* en
SkDQuad dst = SkDQuad::SubDivide(fPts, start->t(), end->t());
return dst.monotonicInY();
}
+ if (fVerb == SkPath::kConic_Verb) {
+ SkDConic dst = SkDConic::SubDivide(fPts, fWeight, start->t(), end->t());
+ return dst.monotonicInY();
+ }
SkASSERT(fVerb == SkPath::kCubic_Verb);
SkDCubic dst = SkDCubic::SubDivide(fPts, start->t(), end->t());
return dst.monotonicInY();
@@ -1615,18 +1634,16 @@ void SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc
&& !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
coincident = false;
SkIntersections i;
- int ptCount = SkPathOpsVerbToPoints(this->verb());
- SkVector dxdy = (*CurveSlopeAtT[ptCount])(pts(), midT);
+ SkVector dxdy = (*CurveSlopeAtT[fVerb])(this->pts(), this->weight(), midT);
SkDLine ray = {{{midPt.fX, midPt.fY},
{midPt.fX + dxdy.fY, midPt.fY - dxdy.fX}}};
- int oppPtCount = SkPathOpsVerbToPoints(opp->verb());
- (*CurveIntersectRay[oppPtCount])(opp->pts(), ray, &i);
+ (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), ray, &i);
// measure distance and see if it's small enough to denote coincidence
for (int index = 0; index < i.used(); ++index) {
SkDPoint oppPt = i.pt(index);
if (oppPt.approximatelyEqual(midPt)) {
- SkVector oppDxdy = (*CurveSlopeAtT[oppPtCount])(opp->pts(),
- i[index][0]);
+ SkVector oppDxdy = (*CurveSlopeAtT[opp->verb()])(opp->pts(),
+ opp->weight(), i[index][0]);
oppDxdy.normalize();
dxdy.normalize();
SkScalar flatness = SkScalarAbs(dxdy.cross(oppDxdy) / FLT_EPSILON);
@@ -1829,13 +1846,15 @@ void SkOpSegment::sortAngles() {
// return true if midpoints were computed
bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
- SkPoint edge[4]) const {
+ SkOpCurve* edge) const {
SkASSERT(start != end);
const SkOpPtT& startPtT = *start->ptT();
const SkOpPtT& endPtT = *end->ptT();
- edge[0] = startPtT.fPt;
+ SkDEBUGCODE(edge->fVerb = fVerb);
+ edge->fPts[0] = startPtT.fPt;
int points = SkPathOpsVerbToPoints(fVerb);
- edge[points] = endPtT.fPt;
+ edge->fPts[points] = endPtT.fPt;
+ edge->fWeight = 1;
if (fVerb == SkPath::kLine_Verb) {
return false;
}
@@ -1844,40 +1863,50 @@ bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
// don't compute midpoints if we already have them
if (fVerb == SkPath::kQuad_Verb) {
- edge[1] = fPts[1];
+ edge->fPts[1] = fPts[1];
+ return false;
+ }
+ if (fVerb == SkPath::kConic_Verb) {
+ edge->fPts[1] = fPts[1];
+ edge->fWeight = fWeight;
return false;
}
SkASSERT(fVerb == SkPath::kCubic_Verb);
if (start < end) {
- edge[1] = fPts[1];
- edge[2] = fPts[2];
+ edge->fPts[1] = fPts[1];
+ edge->fPts[2] = fPts[2];
return false;
}
- edge[1] = fPts[2];
- edge[2] = fPts[1];
+ edge->fPts[1] = fPts[2];
+ edge->fPts[2] = fPts[1];
return false;
}
- const SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[points].fX, edge[points].fY }};
+ const SkDPoint sub[2] = {{ edge->fPts[0].fX, edge->fPts[0].fY},
+ {edge->fPts[points].fX, edge->fPts[points].fY }};
if (fVerb == SkPath::kQuad_Verb) {
- edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoint();
+ edge->fPts[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoint();
+ } else if (fVerb == SkPath::kConic_Verb) {
+ edge->fPts[1] = SkDConic::SubDivide(fPts, fWeight, sub[0], sub[1],
+ startT, endT, &edge->fWeight).asSkPoint();
} else {
SkASSERT(fVerb == SkPath::kCubic_Verb);
SkDPoint ctrl[2];
SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl);
- edge[1] = ctrl[0].asSkPoint();
- edge[2] = ctrl[1].asSkPoint();
+ edge->fPts[1] = ctrl[0].asSkPoint();
+ edge->fPts[2] = ctrl[1].asSkPoint();
}
return true;
}
bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
- SkDCubic* result) const {
+ SkDCurve* edge) const {
SkASSERT(start != end);
const SkOpPtT& startPtT = *start->ptT();
const SkOpPtT& endPtT = *end->ptT();
- (*result)[0].set(startPtT.fPt);
+ SkDEBUGCODE(edge->fVerb = fVerb);
+ edge->fCubic[0].set(startPtT.fPt);
int points = SkPathOpsVerbToPoints(fVerb);
- (*result)[points].set(endPtT.fPt);
+ edge->fCubic[points].set(endPtT.fPt);
if (fVerb == SkPath::kLine_Verb) {
return false;
}
@@ -1886,33 +1915,41 @@ bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
// don't compute midpoints if we already have them
if (fVerb == SkPath::kQuad_Verb) {
- (*result)[1].set(fPts[1]);
+ edge->fLine[1].set(fPts[1]);
+ return false;
+ }
+ if (fVerb == SkPath::kConic_Verb) {
+ edge->fConic[1].set(fPts[1]);
+ edge->fConic.fWeight = fWeight;
return false;
}
SkASSERT(fVerb == SkPath::kCubic_Verb);
if (startT == 0) {
- (*result)[1].set(fPts[1]);
- (*result)[2].set(fPts[2]);
+ edge->fCubic[1].set(fPts[1]);
+ edge->fCubic[2].set(fPts[2]);
return false;
}
- (*result)[1].set(fPts[2]);
- (*result)[2].set(fPts[1]);
+ edge->fCubic[1].set(fPts[2]);
+ edge->fCubic[2].set(fPts[1]);
return false;
}
if (fVerb == SkPath::kQuad_Verb) {
- (*result)[1] = SkDQuad::SubDivide(fPts, (*result)[0], (*result)[2], startT, endT);
+ edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
+ } else if (fVerb == SkPath::kConic_Verb) {
+ edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
+ startT, endT, &edge->fConic.fWeight);
} else {
SkASSERT(fVerb == SkPath::kCubic_Verb);
- SkDCubic::SubDivide(fPts, (*result)[0], (*result)[3], startT, endT, &(*result)[1]);
+ SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
}
return true;
}
void SkOpSegment::subDivideBounds(const SkOpSpanBase* start, const SkOpSpanBase* end,
SkPathOpsBounds* bounds) const {
- SkPoint edge[4];
- subDivide(start, end, edge);
- (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge);
+ SkOpCurve edge;
+ subDivide(start, end, &edge);
+ (bounds->*SetCurveBounds[fVerb])(edge.fPts, edge.fWeight);
}
void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) {
@@ -2001,7 +2038,7 @@ int SkOpSegment::windingAtT(double tHit, const SkOpSpan* span, bool crossOpp,
debugID(), crossOpp, tHit, span->t(), winding, windVal);
#endif
// see if a + change in T results in a +/- change in X (compute x'(T))
- *dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
+ *dx = (*CurveSlopeAtT[fVerb])(fPts, fWeight, tHit).fX;
if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) {
*dx = fPts[2].fX - fPts[1].fX - *dx;
}
« no previous file with comments | « src/pathops/SkOpSegment.h ('k') | src/pathops/SkOpSpan.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698