1 /* 2 * Copyright 2012 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 #ifndef SkIntersections_DEFINE 8 #define SkIntersections_DEFINE 9 10 #include "src/pathops/SkPathOpsConic.h" 11 #include "src/pathops/SkPathOpsCubic.h" 12 #include "src/pathops/SkPathOpsLine.h" 13 #include "src/pathops/SkPathOpsPoint.h" 14 #include "src/pathops/SkPathOpsQuad.h" 15 16 class SkIntersections { 17 public: SkIntersections(SkDEBUGCODE (SkOpGlobalState * globalState=nullptr))18 SkIntersections(SkDEBUGCODE(SkOpGlobalState* globalState = nullptr)) 19 : fSwap(0) 20 #ifdef SK_DEBUG 21 SkDEBUGPARAMS(fDebugGlobalState(globalState)) 22 , fDepth(0) 23 #endif 24 { 25 sk_bzero(fPt, sizeof(fPt)); 26 sk_bzero(fPt2, sizeof(fPt2)); 27 sk_bzero(fT, sizeof(fT)); 28 sk_bzero(fNearlySame, sizeof(fNearlySame)); 29 #if DEBUG_T_SECT_LOOP_COUNT 30 sk_bzero(fDebugLoopCount, sizeof(fDebugLoopCount)); 31 #endif 32 reset(); 33 fMax = 0; // require that the caller set the max 34 } 35 36 class TArray { 37 public: TArray(const double ts[10])38 explicit TArray(const double ts[10]) : fTArray(ts) {} 39 double operator[](int n) const { 40 return fTArray[n]; 41 } 42 const double* fTArray; 43 }; 44 TArray operator[](int n) const { return TArray(fT[n]); } 45 allowNear(bool nearAllowed)46 void allowNear(bool nearAllowed) { 47 fAllowNear = nearAllowed; 48 } 49 clearCoincidence(int index)50 void clearCoincidence(int index) { 51 SkASSERT(index >= 0); 52 int bit = 1 << index; 53 fIsCoincident[0] &= ~bit; 54 fIsCoincident[1] &= ~bit; 55 } 56 conicHorizontal(const SkPoint a[3],SkScalar weight,SkScalar left,SkScalar right,SkScalar y,bool flipped)57 int conicHorizontal(const SkPoint a[3], SkScalar weight, SkScalar left, SkScalar right, 58 SkScalar y, bool flipped) { 59 SkDConic conic; 60 conic.set(a, weight); 61 fMax = 2; 62 return horizontal(conic, left, right, y, flipped); 63 } 64 conicVertical(const SkPoint a[3],SkScalar weight,SkScalar top,SkScalar bottom,SkScalar x,bool flipped)65 int conicVertical(const SkPoint a[3], SkScalar weight, SkScalar top, SkScalar bottom, 66 SkScalar x, bool flipped) { 67 SkDConic conic; 68 conic.set(a, weight); 69 fMax = 2; 70 return vertical(conic, top, bottom, x, flipped); 71 } 72 conicLine(const SkPoint a[3],SkScalar weight,const SkPoint b[2])73 int conicLine(const SkPoint a[3], SkScalar weight, const SkPoint b[2]) { 74 SkDConic conic; 75 conic.set(a, weight); 76 SkDLine line; 77 line.set(b); 78 fMax = 3; // 2; permit small coincident segment + non-coincident intersection 79 return intersect(conic, line); 80 } 81 cubicHorizontal(const SkPoint a[4],SkScalar left,SkScalar right,SkScalar y,bool flipped)82 int cubicHorizontal(const SkPoint a[4], SkScalar left, SkScalar right, SkScalar y, 83 bool flipped) { 84 SkDCubic cubic; 85 cubic.set(a); 86 fMax = 3; 87 return horizontal(cubic, left, right, y, flipped); 88 } 89 cubicVertical(const SkPoint a[4],SkScalar top,SkScalar bottom,SkScalar x,bool flipped)90 int cubicVertical(const SkPoint a[4], SkScalar top, SkScalar bottom, SkScalar x, bool flipped) { 91 SkDCubic cubic; 92 cubic.set(a); 93 fMax = 3; 94 return vertical(cubic, top, bottom, x, flipped); 95 } 96 cubicLine(const SkPoint a[4],const SkPoint b[2])97 int cubicLine(const SkPoint a[4], const SkPoint b[2]) { 98 SkDCubic cubic; 99 cubic.set(a); 100 SkDLine line; 101 line.set(b); 102 fMax = 3; 103 return intersect(cubic, line); 104 } 105 106 #ifdef SK_DEBUG globalState()107 SkOpGlobalState* globalState() const { return fDebugGlobalState; } 108 #endif 109 hasT(double t)110 bool hasT(double t) const { 111 SkASSERT(t == 0 || t == 1); 112 return fUsed > 0 && (t == 0 ? fT[0][0] == 0 : fT[0][fUsed - 1] == 1); 113 } 114 hasOppT(double t)115 bool hasOppT(double t) const { 116 SkASSERT(t == 0 || t == 1); 117 return fUsed > 0 && (fT[1][0] == t || fT[1][fUsed - 1] == t); 118 } 119 insertSwap(double one,double two,const SkDPoint & pt)120 int insertSwap(double one, double two, const SkDPoint& pt) { 121 if (fSwap) { 122 return insert(two, one, pt); 123 } else { 124 return insert(one, two, pt); 125 } 126 } 127 isCoincident(int index)128 bool isCoincident(int index) { 129 return (fIsCoincident[0] & 1 << index) != 0; 130 } 131 lineHorizontal(const SkPoint a[2],SkScalar left,SkScalar right,SkScalar y,bool flipped)132 int lineHorizontal(const SkPoint a[2], SkScalar left, SkScalar right, SkScalar y, 133 bool flipped) { 134 SkDLine line; 135 line.set(a); 136 fMax = 2; 137 return horizontal(line, left, right, y, flipped); 138 } 139 lineVertical(const SkPoint a[2],SkScalar top,SkScalar bottom,SkScalar x,bool flipped)140 int lineVertical(const SkPoint a[2], SkScalar top, SkScalar bottom, SkScalar x, bool flipped) { 141 SkDLine line; 142 line.set(a); 143 fMax = 2; 144 return vertical(line, top, bottom, x, flipped); 145 } 146 lineLine(const SkPoint a[2],const SkPoint b[2])147 int lineLine(const SkPoint a[2], const SkPoint b[2]) { 148 SkDLine aLine, bLine; 149 aLine.set(a); 150 bLine.set(b); 151 fMax = 2; 152 return intersect(aLine, bLine); 153 } 154 nearlySame(int index)155 bool nearlySame(int index) const { 156 SkASSERT(index == 0 || index == 1); 157 return fNearlySame[index]; 158 } 159 pt(int index)160 const SkDPoint& pt(int index) const { 161 return fPt[index]; 162 } 163 pt2(int index)164 const SkDPoint& pt2(int index) const { 165 return fPt2[index]; 166 } 167 quadHorizontal(const SkPoint a[3],SkScalar left,SkScalar right,SkScalar y,bool flipped)168 int quadHorizontal(const SkPoint a[3], SkScalar left, SkScalar right, SkScalar y, 169 bool flipped) { 170 SkDQuad quad; 171 quad.set(a); 172 fMax = 2; 173 return horizontal(quad, left, right, y, flipped); 174 } 175 quadVertical(const SkPoint a[3],SkScalar top,SkScalar bottom,SkScalar x,bool flipped)176 int quadVertical(const SkPoint a[3], SkScalar top, SkScalar bottom, SkScalar x, bool flipped) { 177 SkDQuad quad; 178 quad.set(a); 179 fMax = 2; 180 return vertical(quad, top, bottom, x, flipped); 181 } 182 quadLine(const SkPoint a[3],const SkPoint b[2])183 int quadLine(const SkPoint a[3], const SkPoint b[2]) { 184 SkDQuad quad; 185 quad.set(a); 186 SkDLine line; 187 line.set(b); 188 return intersect(quad, line); 189 } 190 191 // leaves swap, max alone reset()192 void reset() { 193 fAllowNear = true; 194 fUsed = 0; 195 sk_bzero(fIsCoincident, sizeof(fIsCoincident)); 196 } 197 set(bool swap,int tIndex,double t)198 void set(bool swap, int tIndex, double t) { 199 fT[(int) swap][tIndex] = t; 200 } 201 setMax(int max)202 void setMax(int max) { 203 SkASSERT(max <= (int) SK_ARRAY_COUNT(fPt)); 204 fMax = max; 205 } 206 swap()207 void swap() { 208 fSwap ^= true; 209 } 210 swapped()211 bool swapped() const { 212 return fSwap; 213 } 214 used()215 int used() const { 216 return fUsed; 217 } 218 downDepth()219 void downDepth() { 220 SkASSERT(--fDepth >= 0); 221 } 222 unBumpT(int index)223 bool unBumpT(int index) { 224 SkASSERT(fUsed == 1); 225 fT[0][index] = fT[0][index] * (1 + BUMP_EPSILON * 2) - BUMP_EPSILON; 226 if (!between(0, fT[0][index], 1)) { 227 fUsed = 0; 228 return false; 229 } 230 return true; 231 } 232 upDepth()233 void upDepth() { 234 SkASSERT(++fDepth < 16); 235 } 236 237 void alignQuadPts(const SkPoint a[3], const SkPoint b[3]); 238 int cleanUpCoincidence(); 239 int closestTo(double rangeStart, double rangeEnd, const SkDPoint& testPt, double* dist) const; 240 void cubicInsert(double one, double two, const SkDPoint& pt, const SkDCubic& c1, 241 const SkDCubic& c2); 242 void flip(); 243 int horizontal(const SkDLine&, double left, double right, double y, bool flipped); 244 int horizontal(const SkDQuad&, double left, double right, double y, bool flipped); 245 int horizontal(const SkDQuad&, double left, double right, double y, double tRange[2]); 246 int horizontal(const SkDCubic&, double y, double tRange[3]); 247 int horizontal(const SkDConic&, double left, double right, double y, bool flipped); 248 int horizontal(const SkDCubic&, double left, double right, double y, bool flipped); 249 int horizontal(const SkDCubic&, double left, double right, double y, double tRange[3]); 250 static double HorizontalIntercept(const SkDLine& line, double y); 251 static int HorizontalIntercept(const SkDQuad& quad, SkScalar y, double* roots); 252 static int HorizontalIntercept(const SkDConic& conic, SkScalar y, double* roots); 253 // FIXME : does not respect swap 254 int insert(double one, double two, const SkDPoint& pt); 255 void insertNear(double one, double two, const SkDPoint& pt1, const SkDPoint& pt2); 256 // start if index == 0 : end if index == 1 257 int insertCoincident(double one, double two, const SkDPoint& pt); 258 int intersect(const SkDLine&, const SkDLine&); 259 int intersect(const SkDQuad&, const SkDLine&); 260 int intersect(const SkDQuad&, const SkDQuad&); 261 int intersect(const SkDConic&, const SkDLine&); 262 int intersect(const SkDConic&, const SkDQuad&); 263 int intersect(const SkDConic&, const SkDConic&); 264 int intersect(const SkDCubic&, const SkDLine&); 265 int intersect(const SkDCubic&, const SkDQuad&); 266 int intersect(const SkDCubic&, const SkDConic&); 267 int intersect(const SkDCubic&, const SkDCubic&); 268 int intersectRay(const SkDLine&, const SkDLine&); 269 int intersectRay(const SkDQuad&, const SkDLine&); 270 int intersectRay(const SkDConic&, const SkDLine&); 271 int intersectRay(const SkDCubic&, const SkDLine&); intersectRay(const SkTCurve & tCurve,const SkDLine & line)272 int intersectRay(const SkTCurve& tCurve, const SkDLine& line) { 273 return tCurve.intersectRay(this, line); 274 } 275 276 void merge(const SkIntersections& , int , const SkIntersections& , int ); 277 int mostOutside(double rangeStart, double rangeEnd, const SkDPoint& origin) const; 278 void removeOne(int index); 279 void setCoincident(int index); 280 int vertical(const SkDLine&, double top, double bottom, double x, bool flipped); 281 int vertical(const SkDQuad&, double top, double bottom, double x, bool flipped); 282 int vertical(const SkDConic&, double top, double bottom, double x, bool flipped); 283 int vertical(const SkDCubic&, double top, double bottom, double x, bool flipped); 284 static double VerticalIntercept(const SkDLine& line, double x); 285 static int VerticalIntercept(const SkDQuad& quad, SkScalar x, double* roots); 286 static int VerticalIntercept(const SkDConic& conic, SkScalar x, double* roots); 287 depth()288 int depth() const { 289 #ifdef SK_DEBUG 290 return fDepth; 291 #else 292 return 0; 293 #endif 294 } 295 296 enum DebugLoop { 297 kIterations_DebugLoop, 298 kCoinCheck_DebugLoop, 299 kComputePerp_DebugLoop, 300 }; 301 302 void debugBumpLoopCount(DebugLoop ); 303 int debugCoincidentUsed() const; 304 int debugLoopCount(DebugLoop ) const; 305 void debugResetLoopCount(); 306 void dump() const; // implemented for testing only 307 308 private: 309 bool cubicCheckCoincidence(const SkDCubic& c1, const SkDCubic& c2); 310 bool cubicExactEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cubic2); 311 void cubicNearEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cubic2, const SkDRect& ); 312 void cleanUpParallelLines(bool parallel); 313 void computePoints(const SkDLine& line, int used); 314 315 SkDPoint fPt[13]; // FIXME: since scans store points as SkPoint, this should also 316 SkDPoint fPt2[2]; // used by nearly same to store alternate intersection point 317 double fT[2][13]; 318 uint16_t fIsCoincident[2]; // bit set for each curve's coincident T 319 bool fNearlySame[2]; // true if end points nearly match 320 unsigned char fUsed; 321 unsigned char fMax; 322 bool fAllowNear; 323 bool fSwap; 324 #ifdef SK_DEBUG 325 SkOpGlobalState* fDebugGlobalState; 326 int fDepth; 327 #endif 328 #if DEBUG_T_SECT_LOOP_COUNT 329 int fDebugLoopCount[3]; 330 #endif 331 }; 332 333 #endif 334