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