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 SkPathOpsTypes_DEFINED
8 #define SkPathOpsTypes_DEFINED
9
10 #include <float.h> // for FLT_EPSILON
11 #include <math.h> // for fabs, sqrt
12
13 #include "SkFloatingPoint.h"
14 #include "SkPath.h"
15 #include "SkPathOps.h"
16 #include "SkPathOpsDebug.h"
17 #include "SkScalar.h"
18
19 enum SkPathOpsMask {
20 kWinding_PathOpsMask = -1,
21 kNo_PathOpsMask = 0,
22 kEvenOdd_PathOpsMask = 1
23 };
24
25 class SkOpCoincidence;
26 class SkOpContour;
27 class SkOpContourHead;
28
29 class SkOpGlobalState {
30 public:
SkOpGlobalState(SkOpCoincidence * coincidence,SkOpContourHead * head)31 SkOpGlobalState(SkOpCoincidence* coincidence, SkOpContourHead* head)
32 : fCoincidence(coincidence)
33 , fContourHead(head)
34 , fWindingFailed(false)
35 , fAngleCoincidence(false)
36 #if DEBUG_VALIDATE
37 , fPhase(kIntersecting)
38 #endif
39 SkDEBUGPARAMS(fAngleID(0))
40 SkDEBUGPARAMS(fContourID(0))
41 SkDEBUGPARAMS(fPtTID(0))
42 SkDEBUGPARAMS(fSegmentID(0))
43 SkDEBUGPARAMS(fSpanID(0)) {
44 }
45
46 #if DEBUG_VALIDATE
47 enum Phase {
48 kIntersecting,
49 kWalking
50 };
51 #endif
52
53 enum {
54 kMaxWindingTries = 10
55 };
56
angleCoincidence()57 bool angleCoincidence() {
58 return fAngleCoincidence;
59 }
60
coincidence()61 SkOpCoincidence* coincidence() {
62 return fCoincidence;
63 }
64
contourHead()65 SkOpContourHead* contourHead() {
66 return fContourHead;
67 }
68
69 #ifdef SK_DEBUG
70 const struct SkOpAngle* debugAngle(int id) const;
71 SkOpContour* debugContour(int id);
72 const class SkOpPtT* debugPtT(int id) const;
73 const class SkOpSegment* debugSegment(int id) const;
74 const class SkOpSpanBase* debugSpan(int id) const;
75
nextAngleID()76 int nextAngleID() {
77 return ++fAngleID;
78 }
79
nextContourID()80 int nextContourID() {
81 return ++fContourID;
82 }
nextPtTID()83 int nextPtTID() {
84 return ++fPtTID;
85 }
86
nextSegmentID()87 int nextSegmentID() {
88 return ++fSegmentID;
89 }
90
nextSpanID()91 int nextSpanID() {
92 return ++fSpanID;
93 }
94 #endif
95
96 #if DEBUG_VALIDATE
phase()97 Phase phase() const {
98 return fPhase;
99 }
100 #endif
101
setAngleCoincidence()102 void setAngleCoincidence() {
103 fAngleCoincidence = true;
104 }
105
setContourHead(SkOpContourHead * contourHead)106 void setContourHead(SkOpContourHead* contourHead) {
107 fContourHead = contourHead;
108 }
109
110 #if DEBUG_VALIDATE
setPhase(Phase phase)111 void setPhase(Phase phase) {
112 SkASSERT(fPhase != phase);
113 fPhase = phase;
114 }
115 #endif
116
117 // called in very rare cases where angles are sorted incorrectly -- signfies op will fail
setWindingFailed()118 void setWindingFailed() {
119 fWindingFailed = true;
120 }
121
windingFailed()122 bool windingFailed() const {
123 return fWindingFailed;
124 }
125
126 private:
127 SkOpCoincidence* fCoincidence;
128 SkOpContourHead* fContourHead;
129 bool fWindingFailed;
130 bool fAngleCoincidence;
131 #if DEBUG_VALIDATE
132 Phase fPhase;
133 #endif
134 #ifdef SK_DEBUG
135 int fAngleID;
136 int fContourID;
137 int fPtTID;
138 int fSegmentID;
139 int fSpanID;
140 #endif
141 };
142
143 // Use Almost Equal when comparing coordinates. Use epsilon to compare T values.
144 bool AlmostEqualUlps(float a, float b);
AlmostEqualUlps(double a,double b)145 inline bool AlmostEqualUlps(double a, double b) {
146 return AlmostEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
147 }
148
149 // Use Almost Dequal when comparing should not special case denormalized values.
150 bool AlmostDequalUlps(float a, float b);
151 bool AlmostDequalUlps(double a, double b);
152
153 bool NotAlmostEqualUlps(float a, float b);
NotAlmostEqualUlps(double a,double b)154 inline bool NotAlmostEqualUlps(double a, double b) {
155 return NotAlmostEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
156 }
157
158 bool NotAlmostDequalUlps(float a, float b);
NotAlmostDequalUlps(double a,double b)159 inline bool NotAlmostDequalUlps(double a, double b) {
160 return NotAlmostDequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
161 }
162
163 // Use Almost Bequal when comparing coordinates in conjunction with between.
164 bool AlmostBequalUlps(float a, float b);
AlmostBequalUlps(double a,double b)165 inline bool AlmostBequalUlps(double a, double b) {
166 return AlmostBequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
167 }
168
169 bool AlmostPequalUlps(float a, float b);
AlmostPequalUlps(double a,double b)170 inline bool AlmostPequalUlps(double a, double b) {
171 return AlmostPequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
172 }
173
174 bool RoughlyEqualUlps(float a, float b);
RoughlyEqualUlps(double a,double b)175 inline bool RoughlyEqualUlps(double a, double b) {
176 return RoughlyEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
177 }
178
179 bool AlmostLessUlps(float a, float b);
AlmostLessUlps(double a,double b)180 inline bool AlmostLessUlps(double a, double b) {
181 return AlmostLessUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
182 }
183
184 bool AlmostLessOrEqualUlps(float a, float b);
AlmostLessOrEqualUlps(double a,double b)185 inline bool AlmostLessOrEqualUlps(double a, double b) {
186 return AlmostLessOrEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
187 }
188
189 bool AlmostBetweenUlps(float a, float b, float c);
AlmostBetweenUlps(double a,double b,double c)190 inline bool AlmostBetweenUlps(double a, double b, double c) {
191 return AlmostBetweenUlps(SkDoubleToScalar(a), SkDoubleToScalar(b), SkDoubleToScalar(c));
192 }
193
194 int UlpsDistance(float a, float b);
UlpsDistance(double a,double b)195 inline int UlpsDistance(double a, double b) {
196 return UlpsDistance(SkDoubleToScalar(a), SkDoubleToScalar(b));
197 }
198
199 // FLT_EPSILON == 1.19209290E-07 == 1 / (2 ^ 23)
200 // DBL_EPSILON == 2.22045e-16
201 const double FLT_EPSILON_CUBED = FLT_EPSILON * FLT_EPSILON * FLT_EPSILON;
202 const double FLT_EPSILON_HALF = FLT_EPSILON / 2;
203 const double FLT_EPSILON_DOUBLE = FLT_EPSILON * 2;
204 const double FLT_EPSILON_ORDERABLE_ERR = FLT_EPSILON * 16;
205 const double FLT_EPSILON_SQUARED = FLT_EPSILON * FLT_EPSILON;
206 const double FLT_EPSILON_SQRT = sqrt(FLT_EPSILON);
207 const double FLT_EPSILON_INVERSE = 1 / FLT_EPSILON;
208 const double DBL_EPSILON_ERR = DBL_EPSILON * 4; // FIXME: tune -- allow a few bits of error
209 const double DBL_EPSILON_SUBDIVIDE_ERR = DBL_EPSILON * 16;
210 const double ROUGH_EPSILON = FLT_EPSILON * 64;
211 const double MORE_ROUGH_EPSILON = FLT_EPSILON * 256;
212 const double WAY_ROUGH_EPSILON = FLT_EPSILON * 2048;
213 const double BUMP_EPSILON = FLT_EPSILON * 4096;
214
zero_or_one(double x)215 inline bool zero_or_one(double x) {
216 return x == 0 || x == 1;
217 }
218
approximately_zero(double x)219 inline bool approximately_zero(double x) {
220 return fabs(x) < FLT_EPSILON;
221 }
222
precisely_zero(double x)223 inline bool precisely_zero(double x) {
224 return fabs(x) < DBL_EPSILON_ERR;
225 }
226
precisely_subdivide_zero(double x)227 inline bool precisely_subdivide_zero(double x) {
228 return fabs(x) < DBL_EPSILON_SUBDIVIDE_ERR;
229 }
230
approximately_zero(float x)231 inline bool approximately_zero(float x) {
232 return fabs(x) < FLT_EPSILON;
233 }
234
approximately_zero_cubed(double x)235 inline bool approximately_zero_cubed(double x) {
236 return fabs(x) < FLT_EPSILON_CUBED;
237 }
238
approximately_zero_half(double x)239 inline bool approximately_zero_half(double x) {
240 return fabs(x) < FLT_EPSILON_HALF;
241 }
242
approximately_zero_double(double x)243 inline bool approximately_zero_double(double x) {
244 return fabs(x) < FLT_EPSILON_DOUBLE;
245 }
246
approximately_zero_orderable(double x)247 inline bool approximately_zero_orderable(double x) {
248 return fabs(x) < FLT_EPSILON_ORDERABLE_ERR;
249 }
250
approximately_zero_squared(double x)251 inline bool approximately_zero_squared(double x) {
252 return fabs(x) < FLT_EPSILON_SQUARED;
253 }
254
approximately_zero_sqrt(double x)255 inline bool approximately_zero_sqrt(double x) {
256 return fabs(x) < FLT_EPSILON_SQRT;
257 }
258
roughly_zero(double x)259 inline bool roughly_zero(double x) {
260 return fabs(x) < ROUGH_EPSILON;
261 }
262
approximately_zero_inverse(double x)263 inline bool approximately_zero_inverse(double x) {
264 return fabs(x) > FLT_EPSILON_INVERSE;
265 }
266
267 // OPTIMIZATION: if called multiple times with the same denom, we want to pass 1/y instead
approximately_zero_when_compared_to(double x,double y)268 inline bool approximately_zero_when_compared_to(double x, double y) {
269 return x == 0 || fabs(x) < fabs(y * FLT_EPSILON);
270 }
271
precisely_zero_when_compared_to(double x,double y)272 inline bool precisely_zero_when_compared_to(double x, double y) {
273 return x == 0 || fabs(x) < fabs(y * DBL_EPSILON);
274 }
275
276 // Use this for comparing Ts in the range of 0 to 1. For general numbers (larger and smaller) use
277 // AlmostEqualUlps instead.
approximately_equal(double x,double y)278 inline bool approximately_equal(double x, double y) {
279 return approximately_zero(x - y);
280 }
281
precisely_equal(double x,double y)282 inline bool precisely_equal(double x, double y) {
283 return precisely_zero(x - y);
284 }
285
precisely_subdivide_equal(double x,double y)286 inline bool precisely_subdivide_equal(double x, double y) {
287 return precisely_subdivide_zero(x - y);
288 }
289
approximately_equal_half(double x,double y)290 inline bool approximately_equal_half(double x, double y) {
291 return approximately_zero_half(x - y);
292 }
293
approximately_equal_double(double x,double y)294 inline bool approximately_equal_double(double x, double y) {
295 return approximately_zero_double(x - y);
296 }
297
approximately_equal_orderable(double x,double y)298 inline bool approximately_equal_orderable(double x, double y) {
299 return approximately_zero_orderable(x - y);
300 }
301
approximately_equal_squared(double x,double y)302 inline bool approximately_equal_squared(double x, double y) {
303 return approximately_equal(x, y);
304 }
305
approximately_greater(double x,double y)306 inline bool approximately_greater(double x, double y) {
307 return x - FLT_EPSILON >= y;
308 }
309
approximately_greater_double(double x,double y)310 inline bool approximately_greater_double(double x, double y) {
311 return x - FLT_EPSILON_DOUBLE >= y;
312 }
313
approximately_greater_orderable(double x,double y)314 inline bool approximately_greater_orderable(double x, double y) {
315 return x - FLT_EPSILON_ORDERABLE_ERR >= y;
316 }
317
approximately_greater_or_equal(double x,double y)318 inline bool approximately_greater_or_equal(double x, double y) {
319 return x + FLT_EPSILON > y;
320 }
321
approximately_greater_or_equal_double(double x,double y)322 inline bool approximately_greater_or_equal_double(double x, double y) {
323 return x + FLT_EPSILON_DOUBLE > y;
324 }
325
approximately_greater_or_equal_orderable(double x,double y)326 inline bool approximately_greater_or_equal_orderable(double x, double y) {
327 return x + FLT_EPSILON_ORDERABLE_ERR > y;
328 }
329
approximately_lesser(double x,double y)330 inline bool approximately_lesser(double x, double y) {
331 return x + FLT_EPSILON <= y;
332 }
333
approximately_lesser_double(double x,double y)334 inline bool approximately_lesser_double(double x, double y) {
335 return x + FLT_EPSILON_DOUBLE <= y;
336 }
337
approximately_lesser_orderable(double x,double y)338 inline bool approximately_lesser_orderable(double x, double y) {
339 return x + FLT_EPSILON_ORDERABLE_ERR <= y;
340 }
341
approximately_lesser_or_equal(double x,double y)342 inline bool approximately_lesser_or_equal(double x, double y) {
343 return x - FLT_EPSILON < y;
344 }
345
approximately_lesser_or_equal_double(double x,double y)346 inline bool approximately_lesser_or_equal_double(double x, double y) {
347 return x - FLT_EPSILON_DOUBLE < y;
348 }
349
approximately_lesser_or_equal_orderable(double x,double y)350 inline bool approximately_lesser_or_equal_orderable(double x, double y) {
351 return x - FLT_EPSILON_ORDERABLE_ERR < y;
352 }
353
approximately_greater_than_one(double x)354 inline bool approximately_greater_than_one(double x) {
355 return x > 1 - FLT_EPSILON;
356 }
357
precisely_greater_than_one(double x)358 inline bool precisely_greater_than_one(double x) {
359 return x > 1 - DBL_EPSILON_ERR;
360 }
361
approximately_less_than_zero(double x)362 inline bool approximately_less_than_zero(double x) {
363 return x < FLT_EPSILON;
364 }
365
precisely_less_than_zero(double x)366 inline bool precisely_less_than_zero(double x) {
367 return x < DBL_EPSILON_ERR;
368 }
369
approximately_negative(double x)370 inline bool approximately_negative(double x) {
371 return x < FLT_EPSILON;
372 }
373
approximately_negative_orderable(double x)374 inline bool approximately_negative_orderable(double x) {
375 return x < FLT_EPSILON_ORDERABLE_ERR;
376 }
377
precisely_negative(double x)378 inline bool precisely_negative(double x) {
379 return x < DBL_EPSILON_ERR;
380 }
381
approximately_one_or_less(double x)382 inline bool approximately_one_or_less(double x) {
383 return x < 1 + FLT_EPSILON;
384 }
385
approximately_one_or_less_double(double x)386 inline bool approximately_one_or_less_double(double x) {
387 return x < 1 + FLT_EPSILON_DOUBLE;
388 }
389
approximately_positive(double x)390 inline bool approximately_positive(double x) {
391 return x > -FLT_EPSILON;
392 }
393
approximately_positive_squared(double x)394 inline bool approximately_positive_squared(double x) {
395 return x > -(FLT_EPSILON_SQUARED);
396 }
397
approximately_zero_or_more(double x)398 inline bool approximately_zero_or_more(double x) {
399 return x > -FLT_EPSILON;
400 }
401
approximately_zero_or_more_double(double x)402 inline bool approximately_zero_or_more_double(double x) {
403 return x > -FLT_EPSILON_DOUBLE;
404 }
405
approximately_between_orderable(double a,double b,double c)406 inline bool approximately_between_orderable(double a, double b, double c) {
407 return a <= c
408 ? approximately_negative_orderable(a - b) && approximately_negative_orderable(b - c)
409 : approximately_negative_orderable(b - a) && approximately_negative_orderable(c - b);
410 }
411
approximately_between(double a,double b,double c)412 inline bool approximately_between(double a, double b, double c) {
413 return a <= c ? approximately_negative(a - b) && approximately_negative(b - c)
414 : approximately_negative(b - a) && approximately_negative(c - b);
415 }
416
precisely_between(double a,double b,double c)417 inline bool precisely_between(double a, double b, double c) {
418 return a <= c ? precisely_negative(a - b) && precisely_negative(b - c)
419 : precisely_negative(b - a) && precisely_negative(c - b);
420 }
421
422 // returns true if (a <= b <= c) || (a >= b >= c)
between(double a,double b,double c)423 inline bool between(double a, double b, double c) {
424 SkASSERT(((a <= b && b <= c) || (a >= b && b >= c)) == ((a - b) * (c - b) <= 0)
425 || (precisely_zero(a) && precisely_zero(b) && precisely_zero(c)));
426 return (a - b) * (c - b) <= 0;
427 }
428
roughly_equal(double x,double y)429 inline bool roughly_equal(double x, double y) {
430 return fabs(x - y) < ROUGH_EPSILON;
431 }
432
roughly_negative(double x)433 inline bool roughly_negative(double x) {
434 return x < ROUGH_EPSILON;
435 }
436
roughly_between(double a,double b,double c)437 inline bool roughly_between(double a, double b, double c) {
438 return a <= c ? roughly_negative(a - b) && roughly_negative(b - c)
439 : roughly_negative(b - a) && roughly_negative(c - b);
440 }
441
more_roughly_equal(double x,double y)442 inline bool more_roughly_equal(double x, double y) {
443 return fabs(x - y) < MORE_ROUGH_EPSILON;
444 }
445
way_roughly_equal(double x,double y)446 inline bool way_roughly_equal(double x, double y) {
447 return fabs(x - y) < WAY_ROUGH_EPSILON;
448 }
449
450 struct SkDPoint;
451 struct SkDVector;
452 struct SkDLine;
453 struct SkDQuad;
454 struct SkDConic;
455 struct SkDCubic;
456 struct SkDRect;
457
SkPathOpsPointsToVerb(int points)458 inline SkPath::Verb SkPathOpsPointsToVerb(int points) {
459 int verb = (1 << points) >> 1;
460 #ifdef SK_DEBUG
461 switch (points) {
462 case 0: SkASSERT(SkPath::kMove_Verb == verb); break;
463 case 1: SkASSERT(SkPath::kLine_Verb == verb); break;
464 case 2: SkASSERT(SkPath::kQuad_Verb == verb); break;
465 case 3: SkASSERT(SkPath::kCubic_Verb == verb); break;
466 default: SkDEBUGFAIL("should not be here");
467 }
468 #endif
469 return (SkPath::Verb)verb;
470 }
471
SkPathOpsVerbToPoints(SkPath::Verb verb)472 inline int SkPathOpsVerbToPoints(SkPath::Verb verb) {
473 int points = (int) verb - (((int) verb + 1) >> 2);
474 #ifdef SK_DEBUG
475 switch (verb) {
476 case SkPath::kLine_Verb: SkASSERT(1 == points); break;
477 case SkPath::kQuad_Verb: SkASSERT(2 == points); break;
478 case SkPath::kConic_Verb: SkASSERT(2 == points); break;
479 case SkPath::kCubic_Verb: SkASSERT(3 == points); break;
480 default: SkDEBUGFAIL("should not get here");
481 }
482 #endif
483 return points;
484 }
485
SkDInterp(double A,double B,double t)486 inline double SkDInterp(double A, double B, double t) {
487 return A + (B - A) * t;
488 }
489
490 double SkDCubeRoot(double x);
491
492 /* Returns -1 if negative, 0 if zero, 1 if positive
493 */
SkDSign(double x)494 inline int SkDSign(double x) {
495 return (x > 0) - (x < 0);
496 }
497
498 /* Returns 0 if negative, 1 if zero, 2 if positive
499 */
SKDSide(double x)500 inline int SKDSide(double x) {
501 return (x > 0) + (x >= 0);
502 }
503
504 /* Returns 1 if negative, 2 if zero, 4 if positive
505 */
SkDSideBit(double x)506 inline int SkDSideBit(double x) {
507 return 1 << SKDSide(x);
508 }
509
SkPinT(double t)510 inline double SkPinT(double t) {
511 return precisely_less_than_zero(t) ? 0 : precisely_greater_than_one(t) ? 1 : t;
512 }
513
514 #endif
515