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