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

Unified Diff: src/pathops/SkPathOpsPostSect.cpp

Issue 853223002: new files for pathops geometric intersection (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: remove visualizer tool so cl contains only pure adds Created 5 years, 11 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/SkPathOpsCubicSect.h ('k') | src/pathops/SkPathOpsQuadSect.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/pathops/SkPathOpsPostSect.cpp
diff --git a/src/pathops/SkPathOpsPostSect.cpp b/src/pathops/SkPathOpsPostSect.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..15a1900ce3b1ad48a8a62768d5564379873cda51
--- /dev/null
+++ b/src/pathops/SkPathOpsPostSect.cpp
@@ -0,0 +1,502 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkOpCoincidence.h"
+#include "SkOpContour.h"
+#include "SkOpSegment.h"
+#include "SkPathWriter.h"
+
+bool SkOpPtT::alias() const {
+ return this->span()->ptT() != this;
+}
+
+SkOpContour* SkOpPtT::contour() const {
+ return segment()->contour();
+}
+
+SkOpDebugState* SkOpPtT::debugState() const {
+ return PATH_OPS_DEBUG_RELEASE(contour()->debugState(), NULL);
+}
+
+void SkOpPtT::init(SkOpSpanBase* span, double t, const SkPoint& pt, bool duplicate) {
+ fT = t;
+ fPt = pt;
+ fSpan = span;
+ fNext = this;
+ fDuplicatePt = duplicate;
+ fDeleted = false;
+ PATH_OPS_DEBUG_CODE(fID = ++span->debugState()->fPtTID);
+}
+
+bool SkOpPtT::onEnd() const {
+ const SkOpSpanBase* span = this->span();
+ if (span->ptT() != this) {
+ return false;
+ }
+ const SkOpSegment* segment = this->segment();
+ return span == segment->head() || span == segment->tail();
+}
+
+SkOpPtT* SkOpPtT::remove() {
+ SkOpPtT* prev = this;
+ do {
+ SkOpPtT* next = prev->fNext;
+ if (next == this) {
+ prev->removeNext();
+ fDeleted = true;
+ return prev;
+ }
+ prev = next;
+ } while (prev != this);
+ SkASSERT(0);
+ return NULL;
+}
+
+void SkOpPtT::removeNext() {
+ SkASSERT(this->fNext);
+ SkOpPtT* next = this->fNext;
+ this->fNext = next->fNext;
+ SkOpSpanBase* span = next->span();
+ next->setDeleted();
+ if (span->ptT() == next) {
+ span->upCast()->detach();
+ }
+}
+
+const SkOpSegment* SkOpPtT::segment() const {
+ return span()->segment();
+}
+
+SkOpSegment* SkOpPtT::segment() {
+ return span()->segment();
+}
+
+// find the starting or ending span with an existing loop of angles
+// OPTIMIZE? remove the spans pointing to windValue==0 here or earlier?
+// FIXME? assert that only one other span has a valid windValue or oppValue
+void SkOpSpanBase::addSimpleAngle(bool checkFrom, SkChunkAlloc* allocator) {
+ SkOpAngle* angle;
+ if (checkFrom) {
+ SkASSERT(this->final());
+ if (this->fromAngle()) {
+ SkASSERT(this->fromAngle()->loopCount() == 2);
+ return;
+ }
+ angle = this->segment()->addEndSpan(allocator);
+ } else {
+ SkASSERT(this->t() == 0);
+ SkOpSpan* span = this->upCast();
+ if (span->toAngle()) {
+ SkASSERT(span->toAngle()->loopCount() == 2);
+ SkASSERT(!span->fromAngle());
+ span->setFromAngle(span->toAngle()->next());
+ return;
+ }
+ angle = this->segment()->addStartSpan(allocator);
+ }
+ SkOpPtT* ptT = this->ptT();
+ SkOpSpanBase* oSpanBase;
+ SkOpSpan* oSpan;
+ SkOpSegment* other;
+ do {
+ ptT = ptT->next();
+ oSpanBase = ptT->span();
+ oSpan = oSpanBase->upCastable();
+ other = oSpanBase->segment();
+ if (oSpan && oSpan->windValue()) {
+ break;
+ }
+ if (oSpanBase->t() == 0) {
+ continue;
+ }
+ SkOpSpan* oFromSpan = oSpanBase->prev();
+ SkASSERT(oFromSpan->t() < 1);
+ if (oFromSpan->windValue()) {
+ break;
+ }
+ } while (ptT != this->ptT());
+ SkOpAngle* oAngle;
+ if (checkFrom) {
+ oAngle = other->addStartSpan(allocator);
+ SkASSERT(oSpan && !oSpan->final());
+ SkASSERT(oAngle == oSpan->toAngle());
+ } else {
+ oAngle = other->addEndSpan(allocator);
+ SkASSERT(oAngle == oSpanBase->fromAngle());
+ }
+ angle->insert(oAngle);
+}
+
+void SkOpSpanBase::align() {
+ if (this->fAligned) {
+ return;
+ }
+ SkASSERT(!zero_or_one(this->fPtT.fT));
+ SkASSERT(this->fPtT.next());
+ // if a linked pt/t pair has a t of zero or one, use it as the base for alignment
+ SkOpPtT* ptT = &this->fPtT, * stopPtT = ptT;
+ while ((ptT = ptT->next()) != stopPtT) {
+ if (zero_or_one(ptT->fT)) {
+ SkOpSegment* segment = ptT->segment();
+ SkASSERT(this->segment() != segment);
+ SkASSERT(segment->head()->ptT() == ptT || segment->tail()->ptT() == ptT);
+ if (ptT->fT) {
+ segment->tail()->alignEnd(1, segment->lastPt());
+ } else {
+ segment->head()->alignEnd(0, segment->pts()[0]);
+ }
+ return;
+ }
+ }
+ alignInner();
+ this->fAligned = true;
+}
+
+
+// FIXME: delete spans that collapse
+// delete segments that collapse
+// delete contours that collapse
+void SkOpSpanBase::alignEnd(double t, const SkPoint& pt) {
+ SkASSERT(zero_or_one(t));
+ SkOpSegment* segment = this->segment();
+ SkASSERT(t ? segment->lastPt() == pt : segment->pts()[0] == pt);
+ alignInner();
+ *segment->writablePt(!!t) = pt;
+ SkOpPtT* ptT = &this->fPtT;
+ SkASSERT(t == ptT->fT);
+ SkASSERT(pt == ptT->fPt);
+ SkOpPtT* test = ptT, * stopPtT = ptT;
+ while ((test = test->next()) != stopPtT) {
+ SkOpSegment* other = test->segment();
+ if (other == this->segment()) {
+ continue;
+ }
+ if (!zero_or_one(test->fT)) {
+ continue;
+ }
+ *other->writablePt(!!test->fT) = pt;
+ }
+ this->fAligned = true;
+}
+
+void SkOpSpanBase::alignInner() {
+ // force the spans to share points and t values
+ SkOpPtT* ptT = &this->fPtT, * stopPtT = ptT;
+ const SkPoint& pt = ptT->fPt;
+ do {
+ ptT->fPt = pt;
+ const SkOpSpanBase* span = ptT->span();
+ SkOpPtT* test = ptT;
+ do {
+ SkOpPtT* prev = test;
+ if ((test = test->next()) == stopPtT) {
+ break;
+ }
+ if (span == test->span() && !span->segment()->ptsDisjoint(*ptT, *test)) {
+ // omit aliases that alignment makes redundant
+ if ((!ptT->alias() || test->alias()) && (ptT->onEnd() || !test->onEnd())) {
+ SkASSERT(test->alias());
+ prev->removeNext();
+ test = prev;
+ } else {
+ SkASSERT(ptT->alias());
+ stopPtT = ptT = ptT->remove();
+ break;
+ }
+ }
+ } while (true);
+ } while ((ptT = ptT->next()) != stopPtT);
+}
+
+bool SkOpSpanBase::contains(const SkOpSpanBase* span) const {
+ const SkOpPtT* start = &fPtT;
+ const SkOpPtT* check = &span->fPtT;
+ SkASSERT(start != check);
+ const SkOpPtT* walk = start;
+ while ((walk = walk->next()) != start) {
+ if (walk == check) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool SkOpSpanBase::containsCoinEnd(const SkOpSegment* segment) const {
+ SkASSERT(this->segment() != segment);
+ const SkOpSpanBase* next = this;
+ while ((next = next->fCoinEnd) != this) {
+ if (next->segment() == segment) {
+ return true;
+ }
+ }
+ return false;
+}
+
+SkOpContour* SkOpSpanBase::contour() const {
+ return segment()->contour();
+}
+
+SkOpDebugState* SkOpSpanBase::debugState() const {
+ return PATH_OPS_DEBUG_RELEASE(contour()->debugState(), NULL);
+}
+
+void SkOpSpanBase::initBase(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) {
+ fSegment = segment;
+ fPtT.init(this, t, pt, false);
+ fCoinEnd = this;
+ fFromAngle = NULL;
+ fPrev = prev;
+ fAligned = true;
+ fChased = false;
+ PATH_OPS_DEBUG_CODE(fCount = 1);
+ PATH_OPS_DEBUG_CODE(fID = ++debugState()->fSpanID);
+}
+
+// this pair of spans share a common t value or point; merge them and eliminate duplicates
+// this does not compute the best t or pt value; this merely moves all data into a single list
+void SkOpSpanBase::merge(SkOpSpan* span) {
+ SkOpPtT* spanPtT = span->ptT();
+ SkASSERT(this->t() != spanPtT->fT);
+ SkASSERT(!zero_or_one(spanPtT->fT));
+ span->detach();
+ SkOpPtT* remainder = spanPtT->next();
+ ptT()->insert(spanPtT);
+ while (remainder != spanPtT) {
+ SkOpPtT* next = remainder->next();
+ SkOpPtT* compare = spanPtT->next();
+ while (compare != spanPtT) {
+ SkOpPtT* nextC = compare->next();
+ if (nextC->span() == remainder->span() && nextC->fT == remainder->fT) {
+ goto tryNextRemainder;
+ }
+ compare = nextC;
+ }
+ spanPtT->insert(remainder);
+tryNextRemainder:
+ remainder = next;
+ }
+}
+
+void SkOpSpanBase::mergeBaseAttributes(SkOpSpanBase* span) {
+ SkASSERT(!span->fChased);
+ SkASSERT(!span->fFromAngle);
+ if (this->upCastable() && span->upCastable()) {
+ this->upCast()->mergeAttributes(span->upCast());
+ }
+}
+
+void SkOpSpan::applyCoincidence(SkOpSpan* opp) {
+ SkASSERT(!final());
+ SkASSERT(0); // incomplete
+}
+
+bool SkOpSpan::containsCoincidence(const SkOpSegment* segment) const {
+ SkASSERT(this->segment() != segment);
+ const SkOpSpan* next = this;
+ while ((next = next->fCoincident) != this) {
+ if (next->segment() == segment) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void SkOpSpan::detach() {
+ SkASSERT(!final());
+ SkOpSpan* prev = this->prev();
+ SkASSERT(prev);
+ SkOpSpanBase* next = this->next();
+ SkASSERT(next);
+ prev->setNext(next);
+ next->setPrev(prev);
+ this->segment()->detach(this);
+ this->ptT()->setDeleted();
+}
+
+void SkOpSpan::init(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) {
+ SkASSERT(t != 1);
+ initBase(segment, prev, t, pt);
+ fCoincident = this;
+ fToAngle = NULL;
+ fWindSum = fOppSum = SK_MinS32;
+ fWindValue = 1;
+ fOppValue = 0;
+ fChased = fDone = false;
+ segment->bumpCount();
+}
+
+void SkOpSpan::mergeAttributes(SkOpSpan* span) {
+ SkASSERT(!span->fToAngle);
+ if (span->fCoincident) {
+ this->insertCoincidence(span);
+ }
+}
+
+void SkOpCoincidence::add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart,
+ SkOpPtT* oppPtTEnd, bool flipped, SkChunkAlloc* allocator) {
+ SkCoincidentSpans* coinRec = SkOpTAllocator<SkCoincidentSpans>::Allocate(allocator);
+ SkOpSpanBase* coinEnd = coinPtTEnd->span();
+ SkOpSpanBase* oppEnd = oppPtTEnd->span();
+ SkOpSpan* coinStart = coinPtTStart->span()->upCast();
+ SkASSERT(coinStart == coinStart->starter(coinEnd));
+ SkOpSpan* oppStart = (flipped ? oppPtTEnd : oppPtTStart)->span()->upCast();
+ SkASSERT(oppStart == oppStart->starter(oppEnd));
+ coinStart->insertCoincidence(oppStart);
+ coinEnd->insertCoinEnd(oppEnd);
+ coinRec->fNext = this->fHead;
+ coinRec->fCoinPtTStart = coinPtTStart;
+ coinRec->fCoinPtTEnd = coinPtTEnd;
+ coinRec->fOppPtTStart = oppPtTStart;
+ coinRec->fOppPtTEnd = oppPtTEnd;
+ coinRec->fFlipped = flipped;
+ this->fHead = coinRec;
+}
+
+bool SkOpCoincidence::contains(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart,
+ SkOpPtT* oppPtTEnd, bool flipped) {
+ SkCoincidentSpans* coin = fHead;
+ if (!coin) {
+ return false;
+ }
+ do {
+ if (coin->fCoinPtTStart == coinPtTStart && coin->fCoinPtTEnd == coinPtTEnd
+ && coin->fOppPtTStart == oppPtTStart && coin->fOppPtTEnd == oppPtTEnd
+ && coin->fFlipped == flipped) {
+ return true;
+ }
+ } while ((coin = coin->fNext));
+ return false;
+}
+
+// walk span sets in parallel, moving winding from one to the other
+void SkOpCoincidence::apply() {
+ SkCoincidentSpans* coin = fHead;
+ if (!coin) {
+ return;
+ }
+ do {
+ SkOpSpanBase* end = coin->fCoinPtTEnd->span();
+ SkOpSpan* start = coin->fCoinPtTStart->span()->upCast();
+ SkASSERT(start == start->starter(end));
+ bool flipped = coin->fFlipped;
+ SkOpSpanBase* oEnd = (flipped ? coin->fOppPtTStart : coin->fOppPtTEnd)->span();
+ SkOpSpan* oStart = (flipped ? coin->fOppPtTEnd : coin->fOppPtTStart)->span()->upCast();
+ SkASSERT(oStart == oStart->starter(oEnd));
+ SkOpSegment* segment = start->segment();
+ SkOpSegment* oSegment = oStart->segment();
+ bool operandSwap = segment->operand() != oSegment->operand();
+ if (flipped) {
+ do {
+ SkOpSpanBase* oNext = oStart->next();
+ if (oNext == oEnd) {
+ break;
+ }
+ oStart = oNext->upCast();
+ } while (true);
+ }
+ bool isXor = segment->isXor();
+ bool oppXor = oSegment->isXor();
+ do {
+ int windValue = start->windValue();
+ int oWindValue = oStart->windValue();
+ int oppValue = start->oppValue();
+ int oOppValue = oStart->oppValue();
+ // winding values are added or subtracted depending on direction and wind type
+ // same or opposite values are summed depending on the operand value
+ if (windValue >= oWindValue) {
+ if (operandSwap) {
+ SkTSwap(oWindValue, oOppValue);
+ }
+ if (flipped) {
+ windValue -= oWindValue;
+ oppValue -= oOppValue;
+ } else {
+ windValue += oWindValue;
+ oppValue += oOppValue;
+ }
+ if (isXor) {
+ windValue &= 1;
+ }
+ if (oppXor) {
+ oppValue &= 1;
+ }
+ oWindValue = oOppValue = 0;
+ } else {
+ if (operandSwap) {
+ SkTSwap(windValue, oppValue);
+ }
+ if (flipped) {
+ oWindValue -= windValue;
+ oOppValue -= oppValue;
+ } else {
+ oWindValue += windValue;
+ oOppValue += oppValue;
+ }
+ if (isXor) {
+ oOppValue &= 1;
+ }
+ if (oppXor) {
+ oWindValue &= 1;
+ }
+ windValue = oppValue = 0;
+ }
+ start->setWindValue(windValue);
+ start->setOppValue(oppValue);
+ oStart->setWindValue(oWindValue);
+ oStart->setOppValue(oOppValue);
+ if (!windValue && !oppValue) {
+ segment->markDone(start);
+ }
+ if (!oWindValue && !oOppValue) {
+ oSegment->markDone(oStart);
+ }
+ SkOpSpanBase* next = start->next();
+ SkOpSpanBase* oNext = flipped ? oStart->prev() : oStart->next();
+ if (next == end) {
+ break;
+ }
+ start = next->upCast();
+ oStart = oNext->upCast();
+ } while (true);
+ } while ((coin = coin->fNext));
+}
+
+void SkOpCoincidence::mark() {
+ SkCoincidentSpans* coin = fHead;
+ if (!coin) {
+ return;
+ }
+ do {
+ SkOpSpanBase* end = coin->fCoinPtTEnd->span();
+ SkOpSpanBase* oldEnd = end;
+ SkOpSpan* start = coin->fCoinPtTStart->span()->starter(&end);
+ SkOpSpanBase* oEnd = coin->fOppPtTEnd->span();
+ SkOpSpanBase* oOldEnd = oEnd;
+ SkOpSpanBase* oStart = coin->fOppPtTStart->span()->starter(&oEnd);
+ bool flipped = (end == oldEnd) != (oEnd == oOldEnd);
+ if (flipped) {
+ SkTSwap(oStart, oEnd);
+ }
+ SkOpSpanBase* next = start;
+ SkOpSpanBase* oNext = oStart;
+ do {
+ next = next->upCast()->next();
+ oNext = flipped ? oNext->prev() : oNext->upCast()->next();
+ if (next == end) {
+ SkASSERT(oNext == oEnd);
+ break;
+ }
+ if (!next->containsCoinEnd(oNext)) {
+ next->insertCoinEnd(oNext);
+ }
+ SkOpSpan* nextSpan = next->upCast();
+ SkOpSpan* oNextSpan = oNext->upCast();
+ if (!nextSpan->containsCoincidence(oNextSpan)) {
+ nextSpan->insertCoincidence(oNextSpan);
+ }
+ } while (true);
+ } while ((coin = coin->fNext));
+}
« no previous file with comments | « src/pathops/SkPathOpsCubicSect.h ('k') | src/pathops/SkPathOpsQuadSect.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698