fix tiger b
The tiger tests have uncovered numerous bugs. This CL fixes the last of them. If a pair of curves do not intersect, but have one or both ends very close to the opposite curve, consider that an intersection. TBR=reed@google.com BUG=skia:5131 GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2356363003 Review-Url: https://codereview.chromium.org/2356363003
This commit is contained in:
parent
eafe9d1577
commit
6c3b9cdcb0
@ -29,6 +29,7 @@
|
||||
'../tests/PathOpsBuildUseTest.cpp',
|
||||
'../tests/PathOpsConicIntersectionTest.cpp',
|
||||
'../tests/PathOpsConicLineIntersectionTest.cpp',
|
||||
'../tests/PathOpsConicQuadIntersectionTest.cpp',
|
||||
'../tests/PathOpsCubicConicIntersectionTest.cpp',
|
||||
'../tests/PathOpsCubicIntersectionTest.cpp',
|
||||
'../tests/PathOpsCubicIntersectionTestData.cpp',
|
||||
|
@ -841,11 +841,11 @@ void SkOpAngle::setSpans() {
|
||||
}
|
||||
const SkOpSegment* segment = fStart->segment();
|
||||
const SkPoint* pts = segment->pts();
|
||||
SkDEBUGCODE(fPart.fCurve.fVerb = SkPath::kCubic_Verb);
|
||||
SkDEBUGCODE(fPart.fCurve.fVerb = SkPath::kCubic_Verb); // required for SkDCurve debug check
|
||||
SkDEBUGCODE(fPart.fCurve[2].fX = fPart.fCurve[2].fY = fPart.fCurve[3].fX = fPart.fCurve[3].fY
|
||||
= SK_ScalarNaN);
|
||||
SkDEBUGCODE(fPart.fCurve.fVerb = segment->verb());
|
||||
segment->subDivide(fStart, fEnd, &fPart.fCurve);
|
||||
= SK_ScalarNaN); // make the non-line part uninitialized
|
||||
SkDEBUGCODE(fPart.fCurve.fVerb = segment->verb()); // set the curve type for real
|
||||
segment->subDivide(fStart, fEnd, &fPart.fCurve); // set at least the line part if not more
|
||||
fOriginalCurvePart = fPart.fCurve;
|
||||
const SkPath::Verb verb = segment->verb();
|
||||
fPart.setCurveHullSweep(verb);
|
||||
|
@ -1216,7 +1216,7 @@ bool SkOpCoincidence::apply() {
|
||||
}
|
||||
windValue = oppValue = 0;
|
||||
}
|
||||
#if DEBUG_COINCIDENCE
|
||||
#if 0 && DEBUG_COINCIDENCE
|
||||
SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", segment->debugID(),
|
||||
start->debugID(), windValue, oppValue);
|
||||
SkDebugf("seg=%d span=%d windValue=%d oppValue=%d\n", oSegment->debugID(),
|
||||
|
@ -168,6 +168,8 @@ public:
|
||||
return SkDEBUGRELEASE(fGlobalState->debugAngle(id), nullptr);
|
||||
}
|
||||
|
||||
void debugCheckBetween() const;
|
||||
|
||||
#if DEBUG_COINCIDENCE_VERBOSE
|
||||
void debugCheckValid(const char* id, SkPathOpsDebug::GlitchLog* log) const;
|
||||
#endif
|
||||
|
@ -371,7 +371,7 @@ void SkPathOpsDebug::CheckHealth(SkOpContourHead* contourList, const char* id) {
|
||||
SkDebugf("\n");
|
||||
}
|
||||
contourList->globalState()->debugSetCheckHealth(false);
|
||||
#if 0 && DEBUG_ACTIVE_SPANS
|
||||
#if 01 && DEBUG_ACTIVE_SPANS
|
||||
SkDebugf("active after %s:\n", id);
|
||||
ShowActiveSpans(contourList);
|
||||
#endif
|
||||
@ -1846,11 +1846,9 @@ void SkOpCoincidence::debugMarkCollapsed(const char* id, SkPathOpsDebug::GlitchL
|
||||
#endif
|
||||
|
||||
void SkCoincidentSpans::debugShow() const {
|
||||
SkDebugf("%s - id=%d t=%1.9g tEnd=%1.9g\n", __FUNCTION__,
|
||||
coinPtTStart()->segment()->debugID(),
|
||||
SkDebugf("coinSpan - id=%d t=%1.9g tEnd=%1.9g\n", coinPtTStart()->segment()->debugID(),
|
||||
coinPtTStart()->fT, coinPtTEnd()->fT);
|
||||
SkDebugf("%s + id=%d t=%1.9g tEnd=%1.9g\n", __FUNCTION__,
|
||||
oppPtTStart()->segment()->debugID(),
|
||||
SkDebugf("coinSpan + id=%d t=%1.9g tEnd=%1.9g\n", oppPtTStart()->segment()->debugID(),
|
||||
oppPtTStart()->fT, oppPtTEnd()->fT);
|
||||
}
|
||||
|
||||
@ -1865,7 +1863,7 @@ void SkOpCoincidence::debugShowCoincidence() const {
|
||||
}
|
||||
|
||||
#if DEBUG_COINCIDENCE
|
||||
static void DebugValidate(const SkOpSpanBase* next, const SkOpSpanBase* end,
|
||||
static void DebugCheckBetween(const SkOpSpanBase* next, const SkOpSpanBase* end,
|
||||
double oStart, double oEnd, const SkOpSegment* oSegment,
|
||||
const char* id, SkPathOpsDebug::GlitchLog* log) {
|
||||
SkASSERT(next != end);
|
||||
@ -1986,12 +1984,6 @@ static void DebugValidate(const SkCoincidentSpans* head, const SkCoincidentSpans
|
||||
SkASSERT(coin->coinPtTEnd()->span()->ptT() == coin->coinPtTEnd());
|
||||
SkASSERT(coin->oppPtTStart()->span()->ptT() == coin->oppPtTStart());
|
||||
SkASSERT(coin->oppPtTEnd()->span()->ptT() == coin->oppPtTEnd());
|
||||
DebugValidate(coin->coinPtTStart()->span(), coin->coinPtTEnd()->span(),
|
||||
coin->oppPtTStart()->fT, coin->oppPtTEnd()->fT, coin->oppPtTStart()->segment(),
|
||||
id, log);
|
||||
DebugValidate(coin->oppPtTStart()->span(), coin->oppPtTEnd()->span(),
|
||||
coin->coinPtTStart()->fT, coin->coinPtTEnd()->fT, coin->coinPtTStart()->segment(),
|
||||
id, log);
|
||||
coin = coin->next();
|
||||
}
|
||||
DebugCheckOverlapTop(head, opt, id, log);
|
||||
@ -2000,14 +1992,39 @@ static void DebugValidate(const SkCoincidentSpans* head, const SkCoincidentSpans
|
||||
|
||||
void SkOpCoincidence::debugValidate() const {
|
||||
#if DEBUG_COINCIDENCE
|
||||
// if (fGlobalState->debugCheckHealth()) {
|
||||
// return;
|
||||
// }
|
||||
DebugValidate(fHead, fTop, nullptr, nullptr);
|
||||
DebugValidate(fTop, nullptr, nullptr, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DEBUG_COINCIDENCE
|
||||
static void DebugCheckBetween(const SkCoincidentSpans* head, const SkCoincidentSpans* opt,
|
||||
const char* id, SkPathOpsDebug::GlitchLog* log) {
|
||||
// look for pts inside coincident spans that are not inside the opposite spans
|
||||
const SkCoincidentSpans* coin = head;
|
||||
while (coin) {
|
||||
DebugCheckBetween(coin->coinPtTStart()->span(), coin->coinPtTEnd()->span(),
|
||||
coin->oppPtTStart()->fT, coin->oppPtTEnd()->fT, coin->oppPtTStart()->segment(),
|
||||
id, log);
|
||||
DebugCheckBetween(coin->oppPtTStart()->span(), coin->oppPtTEnd()->span(),
|
||||
coin->coinPtTStart()->fT, coin->coinPtTEnd()->fT, coin->coinPtTStart()->segment(),
|
||||
id, log);
|
||||
coin = coin->next();
|
||||
}
|
||||
DebugCheckOverlapTop(head, opt, id, log);
|
||||
}
|
||||
#endif
|
||||
|
||||
void SkOpCoincidence::debugCheckBetween() const {
|
||||
#if DEBUG_COINCIDENCE
|
||||
if (fGlobalState->debugCheckHealth()) {
|
||||
return;
|
||||
}
|
||||
DebugCheckBetween(fHead, fTop, nullptr, nullptr);
|
||||
DebugCheckBetween(fTop, nullptr, nullptr, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DEBUG_COINCIDENCE_VERBOSE
|
||||
void SkOpCoincidence::debugCheckValid(const char* id, SkPathOpsDebug::GlitchLog* log) const {
|
||||
DebugValidate(fHead, fTop, id, log);
|
||||
|
@ -77,7 +77,7 @@
|
||||
#define DEBUG_ALIGNMENT 0
|
||||
#define DEBUG_ANGLE 1
|
||||
#define DEBUG_ASSEMBLE 1
|
||||
#define DEBUG_COINCIDENCE 1
|
||||
#define DEBUG_COINCIDENCE 01
|
||||
#define DEBUG_COINCIDENCE_ORDER 0 // tight arc quads may generate out-of-order coincdence spans
|
||||
#define DEBUG_COINCIDENCE_VERBOSE 0
|
||||
#define DEBUG_CUBIC_BINARY_SEARCH 0
|
||||
|
@ -31,29 +31,29 @@ public:
|
||||
#ifdef SK_DEBUG
|
||||
this->fPerpPt.fX = this->fPerpPt.fY = SK_ScalarNaN;
|
||||
this->fPerpT = SK_ScalarNaN;
|
||||
this->fCoincident = 0xFF;
|
||||
this->fMatch = 0xFF;
|
||||
#endif
|
||||
}
|
||||
|
||||
char dumpIsCoincidentStr() const;
|
||||
void dump() const;
|
||||
|
||||
bool isCoincident() const {
|
||||
SkASSERT(!!fCoincident == fCoincident);
|
||||
return SkToBool(fCoincident);
|
||||
bool isMatch() const {
|
||||
SkASSERT(!!fMatch == fMatch);
|
||||
return SkToBool(fMatch);
|
||||
}
|
||||
|
||||
void init() {
|
||||
fPerpT = -1;
|
||||
fCoincident = false;
|
||||
fMatch = false;
|
||||
fPerpPt.fX = fPerpPt.fY = SK_ScalarNaN;
|
||||
}
|
||||
|
||||
void markCoincident() {
|
||||
if (!fCoincident) {
|
||||
if (!fMatch) {
|
||||
fPerpT = -1;
|
||||
}
|
||||
fCoincident = true;
|
||||
fMatch = true;
|
||||
}
|
||||
|
||||
const SkDPoint& perpPt() const {
|
||||
@ -69,7 +69,7 @@ public:
|
||||
private:
|
||||
SkDPoint fPerpPt;
|
||||
double fPerpT; // perpendicular intersection on opposite curve
|
||||
SkOpDebugBool fCoincident;
|
||||
SkOpDebugBool fMatch;
|
||||
};
|
||||
|
||||
template<typename TCurve, typename OppCurve> class SkTSect;
|
||||
@ -330,6 +330,8 @@ private:
|
||||
SkTSpan<TCurve, OppCurve>* fCoincident;
|
||||
SkTSpan<TCurve, OppCurve>* fDeleted;
|
||||
int fActiveCount;
|
||||
bool fRemovedStartT;
|
||||
bool fRemovedEndT;
|
||||
SkDEBUGCODE(SkOpGlobalState* fDebugGlobalState);
|
||||
SkDEBUGCODE(SkTSect<OppCurve, TCurve>* fOppSect);
|
||||
PATH_OPS_DEBUG_T_SECT_CODE(int fID);
|
||||
@ -372,9 +374,9 @@ void SkTCoincident<TCurve, OppCurve>::setPerp(const TCurve& c1, double t,
|
||||
t, cPt.fX, cPt.fY,
|
||||
cPt.approximatelyEqual(fPerpPt) ? "==" : "!=", fPerpT, fPerpPt.fX, fPerpPt.fY);
|
||||
#endif
|
||||
fCoincident = cPt.approximatelyEqual(fPerpPt);
|
||||
fMatch = cPt.approximatelyEqual(fPerpPt);
|
||||
#if DEBUG_T_SECT
|
||||
if (fCoincident) {
|
||||
if (fMatch) {
|
||||
SkDebugf(""); // allow setting breakpoint
|
||||
}
|
||||
#endif
|
||||
@ -801,11 +803,11 @@ void SkTSpan<TCurve, OppCurve>::validate() const {
|
||||
SkASSERT(fStartT <= fEndT);
|
||||
SkASSERT(fBounded || fCollapsed == 0xFF);
|
||||
if (fHasPerp) {
|
||||
if (fCoinStart.isCoincident()) {
|
||||
if (fCoinStart.isMatch()) {
|
||||
validatePerpT(fCoinStart.perpT());
|
||||
validatePerpPt(fCoinStart.perpT(), fCoinStart.perpPt());
|
||||
}
|
||||
if (fCoinEnd.isCoincident()) {
|
||||
if (fCoinEnd.isMatch()) {
|
||||
validatePerpT(fCoinEnd.perpT());
|
||||
validatePerpPt(fCoinEnd.perpT(), fCoinEnd.perpPt());
|
||||
}
|
||||
@ -926,7 +928,7 @@ bool SkTSect<TCurve, OppCurve>::binarySearchCoin(SkTSect<OppCurve, TCurve>* sect
|
||||
}
|
||||
last = work.fPart[0];
|
||||
work.fCoinStart.setPerp(fCurve, work.fStartT, last, opp);
|
||||
if (work.fCoinStart.isCoincident()) {
|
||||
if (work.fCoinStart.isMatch()) {
|
||||
#if DEBUG_T_SECT
|
||||
work.validatePerpPt(work.fCoinStart.perpT(), work.fCoinStart.perpPt());
|
||||
#endif
|
||||
@ -1083,7 +1085,7 @@ void SkTSect<TCurve, OppCurve>::computePerpendiculars(SkTSect<OppCurve, TCurve>*
|
||||
} else {
|
||||
work->fCoinStart.setPerp(fCurve, work->fStartT, work->fPart[0], opp);
|
||||
}
|
||||
if (work->fCoinStart.isCoincident()) {
|
||||
if (work->fCoinStart.isMatch()) {
|
||||
double perpT = work->fCoinStart.perpT();
|
||||
if (sect2->coincidentHasT(perpT)) {
|
||||
work->fCoinStart.init();
|
||||
@ -1092,7 +1094,7 @@ void SkTSect<TCurve, OppCurve>::computePerpendiculars(SkTSect<OppCurve, TCurve>*
|
||||
}
|
||||
}
|
||||
work->fCoinEnd.setPerp(fCurve, work->fEndT, work->fPart[TCurve::kPointLast], opp);
|
||||
if (work->fCoinEnd.isCoincident()) {
|
||||
if (work->fCoinEnd.isMatch()) {
|
||||
double perpT = work->fCoinEnd.perpT();
|
||||
if (sect2->coincidentHasT(perpT)) {
|
||||
work->fCoinEnd.init();
|
||||
@ -1175,9 +1177,9 @@ bool SkTSect<TCurve, OppCurve>::extractCoincident(
|
||||
double oppStartT SK_INIT_TO_AVOID_WARNING;
|
||||
double oppEndT SK_INIT_TO_AVOID_WARNING;
|
||||
SkTSpan<TCurve, OppCurve>* prev = first->fPrev;
|
||||
SkASSERT(first->fCoinStart.isCoincident());
|
||||
SkASSERT(first->fCoinStart.isMatch());
|
||||
SkTSpan<OppCurve, TCurve>* oppFirst = first->findOppT(first->fCoinStart.perpT());
|
||||
SkOPASSERT(last->fCoinEnd.isCoincident());
|
||||
SkOPASSERT(last->fCoinEnd.isMatch());
|
||||
bool oppMatched = first->fCoinStart.perpT() < first->fCoinEnd.perpT();
|
||||
double coinStart;
|
||||
SkDEBUGCODE(double coinEnd);
|
||||
@ -1208,7 +1210,7 @@ bool SkTSect<TCurve, OppCurve>::extractCoincident(
|
||||
}
|
||||
// FIXME: incomplete : if we're not at the end, find end of coin
|
||||
SkTSpan<OppCurve, TCurve>* oppLast;
|
||||
SkOPASSERT(last->fCoinEnd.isCoincident());
|
||||
SkOPASSERT(last->fCoinEnd.isMatch());
|
||||
oppLast = last->findOppT(last->fCoinEnd.perpT());
|
||||
SkDEBUGCODE(coinEnd = last->fEndT);
|
||||
#ifdef SK_DEBUG
|
||||
@ -1279,13 +1281,13 @@ SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::findCoincidentRun(
|
||||
first = nullptr;
|
||||
// find the first fully coincident span
|
||||
do {
|
||||
if (work->fCoinStart.isCoincident()) {
|
||||
if (work->fCoinStart.isMatch()) {
|
||||
#if DEBUG_T_SECT
|
||||
work->validatePerpT(work->fCoinStart.perpT());
|
||||
work->validatePerpPt(work->fCoinStart.perpT(), work->fCoinStart.perpPt());
|
||||
#endif
|
||||
SkASSERT(work->hasOppT(work->fCoinStart.perpT()));
|
||||
if (!work->fCoinEnd.isCoincident()) {
|
||||
if (!work->fCoinEnd.isMatch()) {
|
||||
break;
|
||||
}
|
||||
lastCandidate = work;
|
||||
@ -1532,7 +1534,7 @@ int SkTSect<TCurve, OppCurve>::linesIntersect(SkTSpan<TCurve, OppCurve>* span,
|
||||
workPt = fCurve.ptAtT(workT);
|
||||
coinW.setPerp(fCurve, workT, workPt, opp->fCurve);
|
||||
double perpT = coinW.perpT();
|
||||
if (coinW.isCoincident() ? !between(oppSpan->fStartT, perpT, oppSpan->fEndT) : perpT < 0) {
|
||||
if (coinW.isMatch() ? !between(oppSpan->fStartT, perpT, oppSpan->fEndT) : perpT < 0) {
|
||||
continue;
|
||||
}
|
||||
SkDVector perpW = workPt - coinW.perpPt();
|
||||
@ -1628,7 +1630,7 @@ void SkTSect<TCurve, OppCurve>::mergeCoincidence(SkTSect<OppCurve, TCurve>* sect
|
||||
SkDPoint midPt = fCurve.ptAtT(midT);
|
||||
SkTCoincident<TCurve, OppCurve> coin;
|
||||
coin.setPerp(fCurve, midT, midPt, sect2->fCurve);
|
||||
if (coin.isCoincident()) {
|
||||
if (coin.isMatch()) {
|
||||
smaller->fEndT = larger->fEndT;
|
||||
smaller->fCoinEnd = larger->fCoinEnd;
|
||||
if (largerPrior) {
|
||||
@ -1728,6 +1730,12 @@ void SkTSect<TCurve, OppCurve>::removeCoincident(SkTSpan<TCurve, OppCurve>* span
|
||||
|
||||
template<typename TCurve, typename OppCurve>
|
||||
bool SkTSect<TCurve, OppCurve>::removeSpan(SkTSpan<TCurve, OppCurve>* span) {
|
||||
if (!span->fStartT) {
|
||||
fRemovedStartT = true;
|
||||
}
|
||||
if (1 == span->fEndT) {
|
||||
fRemovedEndT = true;
|
||||
}
|
||||
this->unlinkSpan(span);
|
||||
return this->markSpanGone(span);
|
||||
}
|
||||
@ -2126,6 +2134,8 @@ void SkTSect<TCurve, OppCurve>::BinarySearch(SkTSect<TCurve, OppCurve>* sect1,
|
||||
break;
|
||||
}
|
||||
SkTSpan<OppCurve, TCurve>* largest2 = sect2->boundsMax();
|
||||
sect1->fRemovedStartT = sect1->fRemovedEndT = false;
|
||||
sect2->fRemovedStartT = sect2->fRemovedEndT = false;
|
||||
// split it
|
||||
if (!largest2 || (largest1 && (largest1->fBoundsMax > largest2->fBoundsMax
|
||||
|| (!largest1->fCollapsed && largest2->fCollapsed)))) {
|
||||
@ -2214,10 +2224,10 @@ void SkTSect<TCurve, OppCurve>::BinarySearch(SkTSect<TCurve, OppCurve>* sect1,
|
||||
}
|
||||
SkASSERT(sect2->fCoincident); // courtesy check : coincidence only looks at sect 1
|
||||
do {
|
||||
if (!coincident->fCoinStart.isCoincident()) {
|
||||
if (!coincident->fCoinStart.isMatch()) {
|
||||
continue;
|
||||
}
|
||||
if (!coincident->fCoinEnd.isCoincident()) {
|
||||
if (!coincident->fCoinEnd.isMatch()) {
|
||||
continue;
|
||||
}
|
||||
int index = intersections->insertCoincident(coincident->fStartT,
|
||||
@ -2231,6 +2241,35 @@ void SkTSect<TCurve, OppCurve>::BinarySearch(SkTSect<TCurve, OppCurve>* sect1,
|
||||
}
|
||||
int zeroOneSet = EndsEqual(sect1, sect2, intersections);
|
||||
if (!sect1->fHead || !sect2->fHead) {
|
||||
// if the final iteration contains an end (0 or 1),
|
||||
if (sect1->fRemovedStartT && !(zeroOneSet & kZeroS1Set)) {
|
||||
SkTCoincident<TCurve, OppCurve> perp; // intersect perpendicular with opposite curve
|
||||
perp.setPerp(sect1->fCurve, 0, sect1->fCurve.fPts[0], sect2->fCurve);
|
||||
if (perp.isMatch()) {
|
||||
intersections->insert(0, perp.perpT(), perp.perpPt());
|
||||
}
|
||||
}
|
||||
if (sect1->fRemovedEndT && !(zeroOneSet & kOneS1Set)) {
|
||||
SkTCoincident<TCurve, OppCurve> perp;
|
||||
perp.setPerp(sect1->fCurve, 1, sect1->fCurve.fPts[TCurve::kPointLast], sect2->fCurve);
|
||||
if (perp.isMatch()) {
|
||||
intersections->insert(1, perp.perpT(), perp.perpPt());
|
||||
}
|
||||
}
|
||||
if (sect2->fRemovedStartT && !(zeroOneSet & kZeroS2Set)) {
|
||||
SkTCoincident<OppCurve, TCurve> perp;
|
||||
perp.setPerp(sect2->fCurve, 0, sect2->fCurve.fPts[0], sect1->fCurve);
|
||||
if (perp.isMatch()) {
|
||||
intersections->insert(perp.perpT(), 0, perp.perpPt());
|
||||
}
|
||||
}
|
||||
if (sect2->fRemovedEndT && !(zeroOneSet & kOneS2Set)) {
|
||||
SkTCoincident<OppCurve, TCurve> perp;
|
||||
perp.setPerp(sect2->fCurve, 1, sect2->fCurve.fPts[OppCurve::kPointLast], sect1->fCurve);
|
||||
if (perp.isMatch()) {
|
||||
intersections->insert(perp.perpT(), 1, perp.perpPt());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
sect1->recoverCollapsed();
|
||||
@ -2279,7 +2318,7 @@ void SkTSect<TCurve, OppCurve>::BinarySearch(SkTSect<TCurve, OppCurve>* sect1,
|
||||
}
|
||||
SkClosestSect<TCurve, OppCurve> closest;
|
||||
do {
|
||||
while (result1 && result1->fCoinStart.isCoincident() && result1->fCoinEnd.isCoincident()) {
|
||||
while (result1 && result1->fCoinStart.isMatch() && result1->fCoinEnd.isMatch()) {
|
||||
result1 = result1->fNext;
|
||||
}
|
||||
if (!result1) {
|
||||
@ -2305,7 +2344,7 @@ void SkTSect<TCurve, OppCurve>::BinarySearch(SkTSect<TCurve, OppCurve>* sect1,
|
||||
// intersect perpendicular with opposite curve
|
||||
SkTCoincident<TCurve, OppCurve> perp;
|
||||
perp.setPerp(sect1->fCurve, midT, midPt, sect2->fCurve);
|
||||
if (!perp.isCoincident()) {
|
||||
if (!perp.isMatch()) {
|
||||
++index;
|
||||
continue;
|
||||
}
|
||||
|
69
tests/PathOpsConicQuadIntersectionTest.cpp
Normal file
69
tests/PathOpsConicQuadIntersectionTest.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#include "PathOpsTestCommon.h"
|
||||
#include "SkIntersections.h"
|
||||
#include "SkPathOpsConic.h"
|
||||
#include "SkPathOpsQuad.h"
|
||||
#include "SkReduceOrder.h"
|
||||
#include "Test.h"
|
||||
|
||||
static struct conicQuad {
|
||||
SkDConic conic;
|
||||
SkDQuad quad;
|
||||
} conicQuadTests[] = {
|
||||
{{{{{494.348663,224.583771}, {494.365143,224.633194}, {494.376404,224.684067}}}, 0.998645842f},
|
||||
{{{494.30481,224.474213}, {494.334961,224.538284}, {494.355774,224.605927}}}},
|
||||
|
||||
{{{{{494.348663,224.583771}, {494.365143,224.633194}, {494.376404,224.684067}}}, 0.998645842f},
|
||||
{{{494.355774f, 224.605927f}, {494.363708f, 224.631714f}, {494.370148f, 224.657471f}}}},
|
||||
};
|
||||
|
||||
static const int conicQuadTests_count = (int) SK_ARRAY_COUNT(conicQuadTests);
|
||||
|
||||
static void conicQuadIntersection(skiatest::Reporter* reporter, int index) {
|
||||
const SkDConic& conic = conicQuadTests[index].conic;
|
||||
SkASSERT(ValidConic(conic));
|
||||
const SkDQuad& quad = conicQuadTests[index].quad;
|
||||
SkASSERT(ValidQuad(quad));
|
||||
SkReduceOrder reduce1;
|
||||
SkReduceOrder reduce2;
|
||||
int order1 = reduce2.reduce(conic.fPts);
|
||||
int order2 = reduce1.reduce(quad);
|
||||
if (order2 != 3) {
|
||||
SkDebugf("[%d] conic order=%d\n", index, order1);
|
||||
REPORTER_ASSERT(reporter, 0);
|
||||
}
|
||||
if (order1 != 3) {
|
||||
SkDebugf("[%d] quad order=%d\n", index, order2);
|
||||
REPORTER_ASSERT(reporter, 0);
|
||||
}
|
||||
SkIntersections i;
|
||||
int roots = i.intersect(conic, quad);
|
||||
for (int pt = 0; pt < roots; ++pt) {
|
||||
double tt1 = i[0][pt];
|
||||
SkDPoint xy1 = conic.ptAtT(tt1);
|
||||
double tt2 = i[1][pt];
|
||||
SkDPoint xy2 = quad.ptAtT(tt2);
|
||||
if (!xy1.approximatelyEqual(xy2)) {
|
||||
SkDebugf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
|
||||
__FUNCTION__, index, pt, tt1, xy1.fX, xy1.fY, tt2, xy2.fX, xy2.fY);
|
||||
}
|
||||
REPORTER_ASSERT(reporter, xy1.approximatelyEqual(xy2));
|
||||
}
|
||||
reporter->bumpTestCount();
|
||||
}
|
||||
|
||||
DEF_TEST(PathOpsConicQuadIntersection, reporter) {
|
||||
for (int index = 0; index < conicQuadTests_count; ++index) {
|
||||
conicQuadIntersection(reporter, index);
|
||||
reporter->bumpTestCount();
|
||||
}
|
||||
}
|
||||
|
||||
DEF_TEST(PathOpsConicQuadIntersectionOneOff, reporter) {
|
||||
conicQuadIntersection(reporter, 1);
|
||||
}
|
@ -404,10 +404,10 @@ static void oneOff(skiatest::Reporter* reporter, const SkDCubic& cubic1, const S
|
||||
SkDebugf("sect%d,\n", index);
|
||||
}
|
||||
#endif
|
||||
if (coin && intersections.used() != 2) {
|
||||
if (coin && intersections.used() < 2) {
|
||||
SkDebugf("");
|
||||
}
|
||||
REPORTER_ASSERT(reporter, !coin || intersections.used() == 2);
|
||||
REPORTER_ASSERT(reporter, !coin || intersections.used() >= 2);
|
||||
double tt1, tt2;
|
||||
SkDPoint xy1, xy2;
|
||||
for (int pt3 = 0; pt3 < intersections.used(); ++pt3) {
|
||||
|
@ -5331,7 +5331,7 @@ static void tiger8b_h_1(skiatest::Reporter* reporter, const char* filename) {
|
||||
#if DEBUG_UNDER_DEVELOPMENT // tiger
|
||||
return;
|
||||
#endif
|
||||
uint64_t testlines = 0x000000201304b4a3; // best so far: 0x000000201304b4a3
|
||||
uint64_t testlines = 0x000000000f27b9e3; // best so far: 0x000000201304b4a3
|
||||
tiger8b_x(reporter, filename, testlines);
|
||||
}
|
||||
|
||||
@ -5870,7 +5870,7 @@ static void testQuads73(skiatest::Reporter* reporter, const char* filename) {
|
||||
}
|
||||
|
||||
static void (*skipTest)(skiatest::Reporter* , const char* filename) = 0;
|
||||
static void (*firstTest)(skiatest::Reporter* , const char* filename) = 0;
|
||||
static void (*firstTest)(skiatest::Reporter* , const char* filename) = tiger8b_h_1;
|
||||
static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
|
||||
|
||||
static TestDesc tests[] = {
|
||||
|
@ -9,16 +9,16 @@
|
||||
|
||||
template<typename TCurve, typename OppCurve>
|
||||
char SkTCoincident<TCurve, OppCurve>::dumpIsCoincidentStr() const {
|
||||
if (!!fCoincident != fCoincident) {
|
||||
if (!!fMatch != fMatch) {
|
||||
return '?';
|
||||
}
|
||||
return fCoincident ? '*' : 0;
|
||||
return fMatch ? '*' : 0;
|
||||
}
|
||||
|
||||
template<typename TCurve, typename OppCurve>
|
||||
void SkTCoincident<TCurve, OppCurve>::dump() const {
|
||||
SkDebugf("t=%1.9g pt=(%1.9g,%1.9g)%s\n", fPerpT, fPerpPt.fX, fPerpPt.fY,
|
||||
fCoincident ? " coincident" : "");
|
||||
fMatch ? " match" : "");
|
||||
}
|
||||
|
||||
template<typename TCurve, typename OppCurve>
|
||||
|
@ -6,42 +6,17 @@
|
||||
<title></title>
|
||||
<div style="height:0">
|
||||
|
||||
<div id="perp">
|
||||
{{{130.0427549999999997, 11417.41309999999976}, {130.2331240000000037, 11418.3192999999992}, {131.0370790000000056, 11419}, {132, 11419}}},
|
||||
{{{132, 11419}, {130.8954319999999996, 11419}, {130, 11418.10449999999946}, {130, 11417}}},
|
||||
<div id="cubics">
|
||||
{{{317, 711}, {322.522857666015625, 711}, {327, 715.4771728515625}, {327, 721}}},
|
||||
{{{324.071075439453125, 713.928955078125}, {324.4051513671875, 714.26300048828125}, {324.715667724609375, 714.62060546875}, {325, 714.9990234375}}},
|
||||
</div>
|
||||
|
||||
<div id="quads">
|
||||
{{{-0.001019871095195412636, -0.008523519150912761688}, {-0.005396408028900623322, -0.005396373569965362549}, {-0.02855382487177848816, -0.02855364233255386353}}},
|
||||
{{{-0.004567248281091451645, -0.01482933573424816132}, {-0.01142475008964538574, -0.01140109263360500336}, {-0.02852955088019371033, -0.02847047336399555206}}},
|
||||
</div>
|
||||
|
||||
<div id="both">
|
||||
{{fX=0.000000000 fY=0.000000000 }, {fX=494.350159 fY=228.773712 }, {fX=493.191650 fY=226.887451 }}
|
||||
{{fX=0.000000000 fY=0.000000000 } {fX=492.680206 fY=228.000900 } {fX=493.193817 fY=226.897568 }
|
||||
{{fX=493.193817 fY=226.897568 } {fX=493.195557 fY=226.893829 } {fX=493.191650 fY=226.887451 }
|
||||
</div>
|
||||
|
||||
<div id="startguy">
|
||||
{{fX=0.000000000 fY=0.000000000 }, {fX=494.350159 fY=228.773712 }, {fX=493.191650 fY=226.887451 }}
|
||||
{{fX=0.000000000 fY=0.000000000 }, {fX=494.350159 fY=228.773712 }, {fX=493.191650 fY=226.887451 }}
|
||||
</div>
|
||||
|
||||
<div id="splitted">
|
||||
{{fX=0.000000000 fY=0.000000000 } {fX=492.680206 fY=228.000900 } {fX=493.193817 fY=226.897568 }
|
||||
{{fX=493.193817 fY=226.897568 } {fX=493.195557 fY=226.893829 } {fX=493.191650 fY=226.887451 }
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var testDivs = [
|
||||
perp,
|
||||
quads,
|
||||
both,
|
||||
startguy,
|
||||
splitted
|
||||
cubics
|
||||
];
|
||||
|
||||
var decimal_places = 3;
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user