// please keep in sync with debugMergeMatches() // Look to see if pt-t linked list contains same segment more than once // if so, and if each pt-t is directly pointed to by spans in that segment, // merge them // keep the points, but remove spans so that the segment doesn't have 2 or more // spans pointing to the same pt-t loop at different loop elements void SkOpSpanBase::mergeMatches(SkOpSpanBase* opp) { SkOpPtT* test = &fPtT; SkOpPtT* testNext; const SkOpPtT* stop = test; do { testNext = test->next(); if (test->deleted()) { continue; } SkOpSpanBase* testBase = test->span(); SkASSERT(testBase->ptT() == test); SkOpSegment* segment = test->segment(); if (segment->done()) { continue; } SkOpPtT* inner = opp->ptT(); const SkOpPtT* innerStop = inner; do { if (inner->segment() != segment) { continue; } if (inner->deleted()) { continue; } SkOpSpanBase* innerBase = inner->span(); SkASSERT(innerBase->ptT() == inner); // when the intersection is first detected, the span base is marked if there are // more than one point in the intersection. if (!zero_or_one(inner->fT)) { innerBase->upCast()->release(test); } else { SkOPASSERT(inner->fT != test->fT); if (!zero_or_one(test->fT)) { testBase->upCast()->release(inner); } else { segment->markAllDone(); // mark segment as collapsed SkDEBUGCODE(testBase->debugSetDeleted()); test->setDeleted(); SkDEBUGCODE(innerBase->debugSetDeleted()); inner->setDeleted(); } } #ifdef SK_DEBUG // assert if another undeleted entry points to segment const SkOpPtT* debugInner = inner; while ((debugInner = debugInner->next()) != innerStop) { if (debugInner->segment() != segment) { continue; } if (debugInner->deleted()) { continue; } SkOPASSERT(0); } #endif break; } while ((inner = inner->next()) != innerStop); } while ((test = testNext) != stop); this->checkForCollapsedCoincidence(); }
// 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->release(this->ptT()); if (this->contains(span)) { SkOPASSERT(0); // check to see if this ever happens -- should have been found earlier return; // merge is already in the ptT loop } SkOpPtT* remainder = spanPtT->next(); this->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; } fSpanAdds += span->fSpanAdds; }
void SkIntersections::cleanUpParallelLines(bool parallel) { while (fUsed > 2) { removeOne(1); } if (fUsed == 2 && !parallel) { bool startMatch = fT[0][0] == 0 || zero_or_one(fT[1][0]); bool endMatch = fT[0][1] == 1 || zero_or_one(fT[1][1]); if ((!startMatch && !endMatch) || approximately_equal(fT[0][0], fT[0][1])) { SkASSERT(startMatch || endMatch); if (startMatch && endMatch && (fT[0][0] != 0 || !zero_or_one(fT[1][0])) && fT[0][1] == 1 && zero_or_one(fT[1][1])) { removeOne(0); } else { removeOne(endMatch); } } } if (fUsed == 2) { fIsCoincident[0] = fIsCoincident[1] = 0x03; } }
SkDVector SkDConic::dxdyAtT(double t) const { SkDVector result = { conic_eval_tan(&fPts[0].fX, fWeight, t), conic_eval_tan(&fPts[0].fY, fWeight, t) }; if (result.fX == 0 && result.fY == 0) { if (zero_or_one(t)) { result = fPts[2] - fPts[0]; } else { // incomplete SkDebugf("!k"); } } return result; }
SkDVector SkDQuad::dxdyAtT(double t) const { double a = t - 1; double b = 1 - 2 * t; double c = t; SkDVector result = { a * fPts[0].fX + b * fPts[1].fX + c * fPts[2].fX, a * fPts[0].fY + b * fPts[1].fY + c * fPts[2].fY }; if (result.fX == 0 && result.fY == 0) { if (zero_or_one(t)) { result = fPts[2] - fPts[0]; } else { // incomplete SkDebugf("!q"); } } return result; }
// OPTIMIZE? compute t^2, t(1-t), and (1-t)^2 and pass them to another version of derivative at t? SkDVector SkDCubic::dxdyAtT(double t) const { SkDVector result = { derivative_at_t(&fPts[0].fX, t), derivative_at_t(&fPts[0].fY, t) }; if (result.fX == 0 && result.fY == 0) { if (t == 0) { result = fPts[2] - fPts[0]; } else if (t == 1) { result = fPts[3] - fPts[1]; } else { // incomplete SkDebugf("!c"); } if (result.fX == 0 && result.fY == 0 && zero_or_one(t)) { result = fPts[3] - fPts[0]; } } return result; }