OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkChunkAlloc.h" | 8 #include "SkChunkAlloc.h" |
9 #include "SkPathOpsBounds.h" | 9 #include "SkPathOpsBounds.h" |
10 #include "SkPathOpsRect.h" | 10 #include "SkPathOpsRect.h" |
11 #include "SkIntersections.h" | 11 #include "SkIntersections.h" |
12 #include "SkTSort.h" | 12 #include "SkTSort.h" |
13 | 13 |
| 14 #ifdef SK_DEBUG |
| 15 typedef uint8_t SkOpDebugBool; |
| 16 #else |
| 17 typedef bool SkOpDebugBool; |
| 18 #endif |
| 19 |
14 /* TCurve and OppCurve are one of { SkDQuadratic, SkDConic, SkDCubic } */ | 20 /* TCurve and OppCurve are one of { SkDQuadratic, SkDConic, SkDCubic } */ |
15 template<typename TCurve, typename OppCurve> | 21 template<typename TCurve, typename OppCurve> |
16 class SkTCoincident { | 22 class SkTCoincident { |
17 public: | 23 public: |
18 SkTCoincident() { | 24 SkTCoincident() { |
19 this->init(); | 25 this->init(); |
20 } | 26 } |
21 | 27 |
| 28 void debugInit() { |
| 29 #ifdef SK_DEBUG |
| 30 this->fPerpPt.fX = this->fPerpPt.fY = SK_ScalarNaN; |
| 31 this->fPerpT = SK_ScalarNaN; |
| 32 this->fCoincident = 0xFF; |
| 33 #endif |
| 34 } |
| 35 |
| 36 char dumpIsCoincidentStr() const; |
22 void dump() const; | 37 void dump() const; |
23 | 38 |
24 bool isCoincident() const { | 39 bool isCoincident() const { |
25 return fCoincident; | 40 SkASSERT(!!fCoincident == fCoincident); |
| 41 return SkToBool(fCoincident); |
26 } | 42 } |
27 | 43 |
28 void init() { | 44 void init() { |
29 fPerpT = -1; | 45 fPerpT = -1; |
30 fCoincident = false; | 46 fCoincident = false; |
31 fPerpPt.fX = fPerpPt.fY = SK_ScalarNaN; | 47 fPerpPt.fX = fPerpPt.fY = SK_ScalarNaN; |
32 } | 48 } |
33 | 49 |
34 void markCoincident() { | 50 void markCoincident() { |
35 if (!fCoincident) { | 51 if (!fCoincident) { |
36 fPerpT = -1; | 52 fPerpT = -1; |
37 } | 53 } |
38 fCoincident = true; | 54 fCoincident = true; |
39 } | 55 } |
40 | 56 |
41 const SkDPoint& perpPt() const { | 57 const SkDPoint& perpPt() const { |
42 return fPerpPt; | 58 return fPerpPt; |
43 } | 59 } |
44 | 60 |
45 double perpT() const { | 61 double perpT() const { |
46 return fPerpT; | 62 return fPerpT; |
47 } | 63 } |
48 | 64 |
49 void setPerp(const TCurve& c1, double t, const SkDPoint& cPt, const OppCurve
& ); | 65 void setPerp(const TCurve& c1, double t, const SkDPoint& cPt, const OppCurve
& ); |
50 | 66 |
51 private: | 67 private: |
52 SkDPoint fPerpPt; | 68 SkDPoint fPerpPt; |
53 double fPerpT; // perpendicular intersection on opposite curve | 69 double fPerpT; // perpendicular intersection on opposite curve |
54 bool fCoincident; | 70 SkOpDebugBool fCoincident; |
55 }; | 71 }; |
56 | 72 |
57 template<typename TCurve, typename OppCurve> class SkTSect; | 73 template<typename TCurve, typename OppCurve> class SkTSect; |
58 template<typename TCurve, typename OppCurve> class SkTSpan; | 74 template<typename TCurve, typename OppCurve> class SkTSpan; |
59 | 75 |
60 template<typename TCurve, typename OppCurve> | 76 template<typename TCurve, typename OppCurve> |
61 struct SkTSpanBounded { | 77 struct SkTSpanBounded { |
62 SkTSpan<TCurve, OppCurve>* fBounded; | 78 SkTSpan<TCurve, OppCurve>* fBounded; |
63 SkTSpanBounded* fNext; | 79 SkTSpanBounded* fNext; |
64 }; | 80 }; |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
178 TCurve fPart; | 194 TCurve fPart; |
179 SkTCoincident<TCurve, OppCurve> fCoinStart; | 195 SkTCoincident<TCurve, OppCurve> fCoinStart; |
180 SkTCoincident<TCurve, OppCurve> fCoinEnd; | 196 SkTCoincident<TCurve, OppCurve> fCoinEnd; |
181 SkTSpanBounded<OppCurve, TCurve>* fBounded; | 197 SkTSpanBounded<OppCurve, TCurve>* fBounded; |
182 SkTSpan* fPrev; | 198 SkTSpan* fPrev; |
183 SkTSpan* fNext; | 199 SkTSpan* fNext; |
184 SkDRect fBounds; | 200 SkDRect fBounds; |
185 double fStartT; | 201 double fStartT; |
186 double fEndT; | 202 double fEndT; |
187 double fBoundsMax; | 203 double fBoundsMax; |
188 bool fCollapsed; | 204 SkOpDebugBool fCollapsed; |
189 bool fHasPerp; | 205 SkOpDebugBool fHasPerp; |
190 bool fIsLinear; | 206 SkOpDebugBool fIsLinear; |
191 bool fIsLine; | 207 SkOpDebugBool fIsLine; |
192 bool fDeleted; | 208 SkOpDebugBool fDeleted; |
193 SkDEBUGCODE_(SkTSect<TCurve, OppCurve>* fDebugSect); | 209 SkDEBUGCODE_(SkTSect<TCurve, OppCurve>* fDebugSect); |
194 PATH_OPS_DEBUG_T_SECT_CODE(int fID); | 210 PATH_OPS_DEBUG_T_SECT_CODE(int fID); |
195 friend class SkTSect<TCurve, OppCurve>; | 211 friend class SkTSect<TCurve, OppCurve>; |
196 friend class SkTSect<OppCurve, TCurve>; | 212 friend class SkTSect<OppCurve, TCurve>; |
197 friend class SkTSpan<OppCurve, TCurve>; | 213 friend class SkTSpan<OppCurve, TCurve>; |
198 }; | 214 }; |
199 | 215 |
200 template<typename TCurve, typename OppCurve> | 216 template<typename TCurve, typename OppCurve> |
201 class SkTSect { | 217 class SkTSect { |
202 public: | 218 public: |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
262 void dumpCommonCurves(const SkTSpan<TCurve, OppCurve>* ) const; | 278 void dumpCommonCurves(const SkTSpan<TCurve, OppCurve>* ) const; |
263 static int EndsEqual(const SkTSect* sect1, const SkTSect<OppCurve, TCurve>*
sect2, | 279 static int EndsEqual(const SkTSect* sect1, const SkTSect<OppCurve, TCurve>*
sect2, |
264 SkIntersections* ); | 280 SkIntersections* ); |
265 SkTSpan<TCurve, OppCurve>* extractCoincident(SkTSect<OppCurve, TCurve>* sect
2, | 281 SkTSpan<TCurve, OppCurve>* extractCoincident(SkTSect<OppCurve, TCurve>* sect
2, |
266 SkTSpan<TCurve, OppCurve>* fir
st, | 282 SkTSpan<TCurve, OppCurve>* fir
st, |
267 SkTSpan<TCurve, OppCurve>* las
t); | 283 SkTSpan<TCurve, OppCurve>* las
t); |
268 SkTSpan<TCurve, OppCurve>* findCoincidentRun(SkTSpan<TCurve, OppCurve>* firs
t, | 284 SkTSpan<TCurve, OppCurve>* findCoincidentRun(SkTSpan<TCurve, OppCurve>* firs
t, |
269 SkTSpan<TCurve, OppCurve>** la
stPtr); | 285 SkTSpan<TCurve, OppCurve>** la
stPtr); |
270 int intersects(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* o
pp, | 286 int intersects(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* o
pp, |
271 SkTSpan<OppCurve, TCurve>* oppSpan, int* oppResult); | 287 SkTSpan<OppCurve, TCurve>* oppSpan, int* oppResult); |
| 288 bool isParallel(const SkDLine& thisLine, const SkTSect<OppCurve, TCurve>* op
p) const; |
272 int linesIntersect(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve
>* opp, | 289 int linesIntersect(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve
>* opp, |
273 SkTSpan<OppCurve, TCurve>* oppSpan, SkIntersections* ); | 290 SkTSpan<OppCurve, TCurve>* oppSpan, SkIntersections* ); |
274 void markSpanGone(SkTSpan<TCurve, OppCurve>* span); | 291 void markSpanGone(SkTSpan<TCurve, OppCurve>* span); |
275 bool matchedDirection(double t, const SkTSect<OppCurve, TCurve>* sect2, doub
le t2) const; | 292 bool matchedDirection(double t, const SkTSect<OppCurve, TCurve>* sect2, doub
le t2) const; |
276 void matchedDirCheck(double t, const SkTSect<OppCurve, TCurve>* sect2, doubl
e t2, | 293 void matchedDirCheck(double t, const SkTSect<OppCurve, TCurve>* sect2, doubl
e t2, |
277 bool* calcMatched, bool* oppMatched) const; | 294 bool* calcMatched, bool* oppMatched) const; |
278 void mergeCoincidence(SkTSect<OppCurve, TCurve>* sect2); | 295 void mergeCoincidence(SkTSect<OppCurve, TCurve>* sect2); |
279 SkTSpan<TCurve, OppCurve>* prev(SkTSpan<TCurve, OppCurve>* ) const; | 296 SkTSpan<TCurve, OppCurve>* prev(SkTSpan<TCurve, OppCurve>* ) const; |
280 void removeByPerpendicular(SkTSect<OppCurve, TCurve>* opp); | 297 void removeByPerpendicular(SkTSect<OppCurve, TCurve>* opp); |
281 void recoverCollapsed(); | 298 void recoverCollapsed(); |
(...skipping 539 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
821 { | 838 { |
822 fHead = addOne(); | 839 fHead = addOne(); |
823 fHead->init(c); | 840 fHead->init(c); |
824 } | 841 } |
825 | 842 |
826 template<typename TCurve, typename OppCurve> | 843 template<typename TCurve, typename OppCurve> |
827 SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::addOne() { | 844 SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::addOne() { |
828 SkTSpan<TCurve, OppCurve>* result; | 845 SkTSpan<TCurve, OppCurve>* result; |
829 if (fDeleted) { | 846 if (fDeleted) { |
830 result = fDeleted; | 847 result = fDeleted; |
831 result->reset(); | |
832 fDeleted = result->fNext; | 848 fDeleted = result->fNext; |
833 } else { | 849 } else { |
834 result = new (fHeap.allocThrow(sizeof(SkTSpan<TCurve, OppCurve>)))( | 850 result = new (fHeap.allocThrow(sizeof(SkTSpan<TCurve, OppCurve>)))( |
835 SkTSpan<TCurve, OppCurve>); | 851 SkTSpan<TCurve, OppCurve>); |
836 result->fBounded = nullptr; | |
837 #if DEBUG_T_SECT | 852 #if DEBUG_T_SECT |
838 ++fDebugAllocatedCount; | 853 ++fDebugAllocatedCount; |
839 #endif | 854 #endif |
840 } | 855 } |
| 856 result->reset(); |
841 result->fHasPerp = false; | 857 result->fHasPerp = false; |
842 result->fDeleted = false; | 858 result->fDeleted = false; |
843 ++fActiveCount; | 859 ++fActiveCount; |
844 PATH_OPS_DEBUG_T_SECT_CODE(result->fID = fDebugCount++ * 2 + fID); | 860 PATH_OPS_DEBUG_T_SECT_CODE(result->fID = fDebugCount++ * 2 + fID); |
845 SkDEBUGCODE(result->fDebugSect = this); | 861 SkDEBUGCODE(result->fDebugSect = this); |
| 862 #ifdef SK_DEBUG |
| 863 result->fPart.debugInit(); |
| 864 result->fCoinStart.debugInit(); |
| 865 result->fCoinEnd.debugInit(); |
| 866 result->fPrev = result->fNext = nullptr; |
| 867 result->fBounds.debugInit(); |
| 868 result->fStartT = result->fEndT = result->fBoundsMax = SK_ScalarNaN; |
| 869 result->fCollapsed = result->fIsLinear = result->fIsLine = 0xFF; |
| 870 #endif |
846 return result; | 871 return result; |
847 } | 872 } |
848 | 873 |
849 template<typename TCurve, typename OppCurve> | 874 template<typename TCurve, typename OppCurve> |
850 bool SkTSect<TCurve, OppCurve>::binarySearchCoin(SkTSect<OppCurve, TCurve>* sect
2, double tStart, | 875 bool SkTSect<TCurve, OppCurve>::binarySearchCoin(SkTSect<OppCurve, TCurve>* sect
2, double tStart, |
851 double tStep, double* resultT, double* oppT) { | 876 double tStep, double* resultT, double* oppT) { |
852 SkTSpan<TCurve, OppCurve> work; | 877 SkTSpan<TCurve, OppCurve> work; |
853 double result = work.fStartT = work.fEndT = tStart; | 878 double result = work.fStartT = work.fEndT = tStart; |
854 SkDEBUGCODE(work.fDebugSect = this); | 879 SkDEBUGCODE(work.fDebugSect = this); |
855 SkDPoint last = fCurve.ptAtT(tStart); | 880 SkDPoint last = fCurve.ptAtT(tStart); |
(...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1270 span->fStartT = span->fEndT = i[0][0]; | 1295 span->fStartT = span->fEndT = i[0][0]; |
1271 oppSpan->fStartT = oppSpan->fEndT = i[1][0]; | 1296 oppSpan->fStartT = oppSpan->fEndT = i[1][0]; |
1272 return *oppResult = 2; | 1297 return *oppResult = 2; |
1273 } | 1298 } |
1274 if (span->fIsLinear || oppSpan->fIsLinear) { | 1299 if (span->fIsLinear || oppSpan->fIsLinear) { |
1275 return *oppResult = (int) span->linearsIntersect(oppSpan); | 1300 return *oppResult = (int) span->linearsIntersect(oppSpan); |
1276 } | 1301 } |
1277 return *oppResult = 1; | 1302 return *oppResult = 1; |
1278 } | 1303 } |
1279 | 1304 |
| 1305 template<typename TCurve> |
| 1306 static bool is_parallel(const SkDLine& thisLine, const TCurve& opp) { |
| 1307 if (!opp.IsConic()) { |
| 1308 return false; // FIXME : breaks a lot of stuff now |
| 1309 } |
| 1310 int finds = 0; |
| 1311 SkDLine thisPerp; |
| 1312 thisPerp.fPts[0].fX = thisLine.fPts[1].fX + (thisLine.fPts[1].fY - thisLine.
fPts[0].fY); |
| 1313 thisPerp.fPts[0].fY = thisLine.fPts[1].fY + (thisLine.fPts[0].fX - thisLine.
fPts[1].fX); |
| 1314 thisPerp.fPts[1] = thisLine.fPts[1]; |
| 1315 SkIntersections perpRayI; |
| 1316 perpRayI.intersectRay(opp, thisPerp); |
| 1317 for (int pIndex = 0; pIndex < perpRayI.used(); ++pIndex) { |
| 1318 finds += perpRayI.pt(pIndex).approximatelyEqual(thisPerp.fPts[1]); |
| 1319 } |
| 1320 thisPerp.fPts[1].fX = thisLine.fPts[0].fX + (thisLine.fPts[1].fY - thisLine.
fPts[0].fY); |
| 1321 thisPerp.fPts[1].fY = thisLine.fPts[0].fY + (thisLine.fPts[0].fX - thisLine.
fPts[1].fX); |
| 1322 thisPerp.fPts[0] = thisLine.fPts[0]; |
| 1323 perpRayI.intersectRay(opp, thisPerp); |
| 1324 for (int pIndex = 0; pIndex < perpRayI.used(); ++pIndex) { |
| 1325 finds += perpRayI.pt(pIndex).approximatelyEqual(thisPerp.fPts[0]); |
| 1326 } |
| 1327 return finds >= 2; |
| 1328 } |
| 1329 |
1280 // while the intersection points are sufficiently far apart: | 1330 // while the intersection points are sufficiently far apart: |
1281 // construct the tangent lines from the intersections | 1331 // construct the tangent lines from the intersections |
1282 // find the point where the tangent line intersects the opposite curve | 1332 // find the point where the tangent line intersects the opposite curve |
1283 template<typename TCurve, typename OppCurve> | 1333 template<typename TCurve, typename OppCurve> |
1284 int SkTSect<TCurve, OppCurve>::linesIntersect(SkTSpan<TCurve, OppCurve>* span, | 1334 int SkTSect<TCurve, OppCurve>::linesIntersect(SkTSpan<TCurve, OppCurve>* span, |
1285 SkTSect<OppCurve, TCurve>* opp, | 1335 SkTSect<OppCurve, TCurve>* opp, |
1286 SkTSpan<OppCurve, TCurve>* oppSpan, SkIntersections* i) { | 1336 SkTSpan<OppCurve, TCurve>* oppSpan, SkIntersections* i) { |
1287 SkIntersections thisRayI, oppRayI; | 1337 SkIntersections thisRayI, oppRayI; |
1288 SkDLine thisLine = {{ span->fPart[0], span->fPart[TCurve::kPointLast] }}; | 1338 SkDLine thisLine = {{ span->fPart[0], span->fPart[TCurve::kPointLast] }}; |
1289 SkDLine oppLine = {{ oppSpan->fPart[0], oppSpan->fPart[OppCurve::kPointLast]
}}; | 1339 SkDLine oppLine = {{ oppSpan->fPart[0], oppSpan->fPart[OppCurve::kPointLast]
}}; |
1290 int loopCount = 0; | 1340 int loopCount = 0; |
1291 double bestDistSq = DBL_MAX; | 1341 double bestDistSq = DBL_MAX; |
1292 if (!thisRayI.intersectRay(opp->fCurve, thisLine)) { | 1342 if (!thisRayI.intersectRay(opp->fCurve, thisLine)) { |
1293 return 0; | 1343 return 0; |
1294 } | 1344 } |
1295 if (!oppRayI.intersectRay(this->fCurve, oppLine)) { | 1345 if (!oppRayI.intersectRay(this->fCurve, oppLine)) { |
1296 return 0; | 1346 return 0; |
1297 } | 1347 } |
1298 // if the ends of each line intersect the opposite curve, the lines are coin
cident | 1348 // if the ends of each line intersect the opposite curve, the lines are coin
cident |
1299 if (thisRayI.used() > 1) { | 1349 if (thisRayI.used() > 1) { |
1300 int ptMatches = 0; | 1350 int ptMatches = 0; |
1301 for (int tIndex = 0; tIndex < thisRayI.used(); ++tIndex) { | 1351 for (int tIndex = 0; tIndex < thisRayI.used(); ++tIndex) { |
1302 for (int lIndex = 0; lIndex < (int) SK_ARRAY_COUNT(thisLine.fPts); +
+lIndex) { | 1352 for (int lIndex = 0; lIndex < (int) SK_ARRAY_COUNT(thisLine.fPts); +
+lIndex) { |
1303 ptMatches += thisRayI.pt(tIndex).approximatelyEqual(thisLine.fPt
s[lIndex]); | 1353 ptMatches += thisRayI.pt(tIndex).approximatelyEqual(thisLine.fPt
s[lIndex]); |
1304 } | 1354 } |
1305 } | 1355 } |
1306 if (ptMatches == 2) { | 1356 if (ptMatches == 2 || is_parallel(thisLine, opp->fCurve)) { |
1307 return 2; | 1357 return 2; |
1308 } | 1358 } |
1309 } | 1359 } |
1310 if (oppRayI.used() > 1) { | 1360 if (oppRayI.used() > 1) { |
1311 int ptMatches = 0; | 1361 int ptMatches = 0; |
1312 for (int oIndex = 0; oIndex < oppRayI.used(); ++oIndex) { | 1362 for (int oIndex = 0; oIndex < oppRayI.used(); ++oIndex) { |
1313 for (int lIndex = 0; lIndex < (int) SK_ARRAY_COUNT(thisLine.fPts); +
+lIndex) { | 1363 for (int lIndex = 0; lIndex < (int) SK_ARRAY_COUNT(thisLine.fPts); +
+lIndex) { |
1314 ptMatches += oppRayI.pt(oIndex).approximatelyEqual(oppLine.fPts[
lIndex]); | 1364 ptMatches += oppRayI.pt(oIndex).approximatelyEqual(oppLine.fPts[
lIndex]); |
1315 } | 1365 } |
1316 } | 1366 } |
1317 if (ptMatches == 2) { | 1367 if (ptMatches == 2|| is_parallel(oppLine, this->fCurve)) { |
1318 return 2; | 1368 return 2; |
1319 } | 1369 } |
1320 } | 1370 } |
1321 do { | 1371 do { |
1322 // pick the closest pair of points | 1372 // pick the closest pair of points |
1323 double closest = DBL_MAX; | 1373 double closest = DBL_MAX; |
1324 int closeIndex SK_INIT_TO_AVOID_WARNING; | 1374 int closeIndex SK_INIT_TO_AVOID_WARNING; |
1325 int oppCloseIndex SK_INIT_TO_AVOID_WARNING; | 1375 int oppCloseIndex SK_INIT_TO_AVOID_WARNING; |
1326 for (int index = 0; index < oppRayI.used(); ++index) { | 1376 for (int index = 0; index < oppRayI.used(); ++index) { |
1327 if (!roughly_between(span->fStartT, oppRayI[0][index], span->fEndT))
{ | 1377 if (!roughly_between(span->fStartT, oppRayI[0][index], span->fEndT))
{ |
(...skipping 846 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2174 } else if (intersections->isCoincident(index + 1)) { | 2224 } else if (intersections->isCoincident(index + 1)) { |
2175 intersections->removeOne(index + 1); | 2225 intersections->removeOne(index + 1); |
2176 --last; | 2226 --last; |
2177 } else { | 2227 } else { |
2178 intersections->setCoincident(index++); | 2228 intersections->setCoincident(index++); |
2179 } | 2229 } |
2180 intersections->setCoincident(index); | 2230 intersections->setCoincident(index); |
2181 } | 2231 } |
2182 SkASSERT(intersections->used() <= TCurve::kMaxIntersections); | 2232 SkASSERT(intersections->used() <= TCurve::kMaxIntersections); |
2183 } | 2233 } |
OLD | NEW |