blob: 786eb2288e52266caf96ef13f8d1fb8d2575e98f [file] [log] [blame]
caryclark@google.com07393ca2013-04-08 11:47:37 +00001/*
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"
reed@google.com277c3f82013-05-31 15:17:50 +000014#include "SkPath.h"
caryclark@google.com07393ca2013-04-08 11:47:37 +000015#include "SkPathOps.h"
16#include "SkPathOpsDebug.h"
17#include "SkScalar.h"
18
caryclark@google.com07393ca2013-04-08 11:47:37 +000019enum SkPathOpsMask {
20 kWinding_PathOpsMask = -1,
21 kNo_PathOpsMask = 0,
22 kEvenOdd_PathOpsMask = 1
23};
24
caryclark55888e42016-07-18 10:01:36 -070025class SkChunkAlloc;
caryclark54359292015-03-26 07:52:43 -070026class SkOpCoincidence;
27class SkOpContour;
caryclark624637c2015-05-11 07:21:27 -070028class SkOpContourHead;
caryclark26ad22a2015-10-16 09:03:38 -070029class SkIntersections;
30class SkIntersectionHelper;
caryclark54359292015-03-26 07:52:43 -070031
Cary Clarkab87d7a2016-10-04 10:01:04 -040032enum class SkOpPhase : char {
33 kNoChange,
34 kIntersecting,
35 kWalking,
36 kFixWinding,
37};
38
caryclark54359292015-03-26 07:52:43 -070039class SkOpGlobalState {
40public:
caryclark55888e42016-07-18 10:01:36 -070041 SkOpGlobalState(SkOpContourHead* head,
42 SkChunkAlloc* allocator SkDEBUGPARAMS(bool debugSkipAssert)
caryclarkd4349722015-07-23 12:40:22 -070043 SkDEBUGPARAMS(const char* testName));
caryclark54359292015-03-26 07:52:43 -070044
caryclark624637c2015-05-11 07:21:27 -070045 enum {
46 kMaxWindingTries = 10
47 };
48
caryclark29b25632016-08-25 11:27:17 -070049 bool allocatedOpSpan() const {
50 return fAllocatedOpSpan;
51 }
52
caryclark55888e42016-07-18 10:01:36 -070053 SkChunkAlloc* allocator() {
54 return fAllocator;
55 }
56
caryclark4e1a4c92015-05-18 12:56:57 -070057 void bumpNested() {
58 ++fNested;
59 }
60
61 void clearNested() {
62 fNested = 0;
63 }
64
caryclark54359292015-03-26 07:52:43 -070065 SkOpCoincidence* coincidence() {
66 return fCoincidence;
67 }
68
caryclark624637c2015-05-11 07:21:27 -070069 SkOpContourHead* contourHead() {
70 return fContourHead;
71 }
72
caryclark54359292015-03-26 07:52:43 -070073#ifdef SK_DEBUG
caryclark55888e42016-07-18 10:01:36 -070074 const class SkOpAngle* debugAngle(int id) const;
75 const SkOpCoincidence* debugCoincidence() const;
caryclark30b9fdd2016-08-31 14:36:29 -070076 SkOpContour* debugContour(int id) const;
caryclark54359292015-03-26 07:52:43 -070077 const class SkOpPtT* debugPtT(int id) const;
caryclark27c8eb82015-07-06 11:38:33 -070078 bool debugRunFail() const;
caryclark54359292015-03-26 07:52:43 -070079 const class SkOpSegment* debugSegment(int id) const;
caryclarkdae6b972016-06-08 04:28:19 -070080 bool debugSkipAssert() const { return fDebugSkipAssert; }
caryclark54359292015-03-26 07:52:43 -070081 const class SkOpSpanBase* debugSpan(int id) const;
caryclarkd4349722015-07-23 12:40:22 -070082 const char* debugTestName() const { return fDebugTestName; }
caryclark4e1a4c92015-05-18 12:56:57 -070083#endif
caryclark54359292015-03-26 07:52:43 -070084
caryclark26ad22a2015-10-16 09:03:38 -070085#if DEBUG_T_SECT_LOOP_COUNT
86 void debugAddLoopCount(SkIntersections* , const SkIntersectionHelper& ,
87 const SkIntersectionHelper& );
88 void debugDoYourWorst(SkOpGlobalState* );
89 void debugLoopReport();
90 void debugResetLoopCounts();
91#endif
92
caryclark55888e42016-07-18 10:01:36 -070093#if DEBUG_COINCIDENCE
94 void debugSetCheckHealth(bool check) { fDebugCheckHealth = check; }
95 bool debugCheckHealth() const { return fDebugCheckHealth; }
96#endif
97
Cary Clarkab87d7a2016-10-04 10:01:04 -040098#if DEBUG_VALIDATE || DEBUG_COIN
99 void debugSetPhase(const char* funcName DEBUG_COIN_DECLARE_PARAMS()) const;
100#endif
101
102#if DEBUG_COIN
103 void debugAddToCoinChangedDict();
104 void debugAddToGlobalCoinDicts();
105 SkPathOpsDebug::CoinDict* debugCoinChangedDict() { return &fCoinChangedDict; }
106 const SkPathOpsDebug::CoinDictEntry& debugCoinDictEntry() const { return fCoinDictEntry; }
107
108 static void DumpCoinDict();
109#endif
110
111
caryclark4e1a4c92015-05-18 12:56:57 -0700112 int nested() const {
113 return fNested;
114 }
115
116#ifdef SK_DEBUG
caryclark54359292015-03-26 07:52:43 -0700117 int nextAngleID() {
118 return ++fAngleID;
119 }
120
caryclark26ad22a2015-10-16 09:03:38 -0700121 int nextCoinID() {
122 return ++fCoinID;
123 }
124
caryclark54359292015-03-26 07:52:43 -0700125 int nextContourID() {
126 return ++fContourID;
127 }
caryclark26ad22a2015-10-16 09:03:38 -0700128
caryclark54359292015-03-26 07:52:43 -0700129 int nextPtTID() {
130 return ++fPtTID;
131 }
132
133 int nextSegmentID() {
134 return ++fSegmentID;
135 }
136
137 int nextSpanID() {
138 return ++fSpanID;
139 }
140#endif
141
Cary Clarkab87d7a2016-10-04 10:01:04 -0400142 SkOpPhase phase() const {
caryclark54359292015-03-26 07:52:43 -0700143 return fPhase;
144 }
caryclark29b25632016-08-25 11:27:17 -0700145
146 void resetAllocatedOpSpan() {
147 fAllocatedOpSpan = false;
148 }
149
150 void setAllocatedOpSpan() {
151 fAllocatedOpSpan = true;
152 }
caryclark54359292015-03-26 07:52:43 -0700153
caryclark55888e42016-07-18 10:01:36 -0700154 void setCoincidence(SkOpCoincidence* coincidence) {
155 fCoincidence = coincidence;
156 }
caryclark54359292015-03-26 07:52:43 -0700157
caryclark624637c2015-05-11 07:21:27 -0700158 void setContourHead(SkOpContourHead* contourHead) {
159 fContourHead = contourHead;
160 }
161
Cary Clarkab87d7a2016-10-04 10:01:04 -0400162 void setPhase(SkOpPhase phase) {
163 if (SkOpPhase::kNoChange == phase) {
164 return;
165 }
caryclark54359292015-03-26 07:52:43 -0700166 SkASSERT(fPhase != phase);
167 fPhase = phase;
168 }
caryclark54359292015-03-26 07:52:43 -0700169
170 // called in very rare cases where angles are sorted incorrectly -- signfies op will fail
171 void setWindingFailed() {
172 fWindingFailed = true;
173 }
174
175 bool windingFailed() const {
176 return fWindingFailed;
177 }
178
179private:
caryclark55888e42016-07-18 10:01:36 -0700180 SkChunkAlloc* fAllocator;
caryclark54359292015-03-26 07:52:43 -0700181 SkOpCoincidence* fCoincidence;
caryclark624637c2015-05-11 07:21:27 -0700182 SkOpContourHead* fContourHead;
caryclark4e1a4c92015-05-18 12:56:57 -0700183 int fNested;
caryclark29b25632016-08-25 11:27:17 -0700184 bool fAllocatedOpSpan;
caryclark54359292015-03-26 07:52:43 -0700185 bool fWindingFailed;
Cary Clarkab87d7a2016-10-04 10:01:04 -0400186 SkOpPhase fPhase;
caryclark54359292015-03-26 07:52:43 -0700187#ifdef SK_DEBUG
caryclarkd4349722015-07-23 12:40:22 -0700188 const char* fDebugTestName;
Cary Clarkab87d7a2016-10-04 10:01:04 -0400189 void* fDebugReporter;
caryclark54359292015-03-26 07:52:43 -0700190 int fAngleID;
caryclark26ad22a2015-10-16 09:03:38 -0700191 int fCoinID;
caryclark54359292015-03-26 07:52:43 -0700192 int fContourID;
193 int fPtTID;
194 int fSegmentID;
195 int fSpanID;
caryclarkdae6b972016-06-08 04:28:19 -0700196 bool fDebugSkipAssert;
caryclark54359292015-03-26 07:52:43 -0700197#endif
caryclark26ad22a2015-10-16 09:03:38 -0700198#if DEBUG_T_SECT_LOOP_COUNT
199 int fDebugLoopCount[3];
200 SkPath::Verb fDebugWorstVerb[6];
201 SkPoint fDebugWorstPts[24];
202 float fDebugWorstWeight[6];
203#endif
Cary Clarkab87d7a2016-10-04 10:01:04 -0400204#if DEBUG_COIN
205 SkPathOpsDebug::CoinDict fCoinChangedDict;
206 SkPathOpsDebug::CoinDict fCoinVisitedDict;
207 SkPathOpsDebug::CoinDictEntry fCoinDictEntry;
208 const char* fPreviousFuncName;
209#endif
caryclark55888e42016-07-18 10:01:36 -0700210#if DEBUG_COINCIDENCE
211 bool fDebugCheckHealth;
212#endif
caryclark54359292015-03-26 07:52:43 -0700213};
214
caryclarkcdeff812016-07-22 03:34:19 -0700215#ifdef SK_DEBUG
caryclark30b9fdd2016-08-31 14:36:29 -0700216#if DEBUG_COINCIDENCE
caryclarke25a4f62016-07-26 09:26:29 -0700217#define SkOPASSERT(cond) SkASSERT((this->globalState() && \
caryclark30b9fdd2016-08-31 14:36:29 -0700218 (this->globalState()->debugCheckHealth() || \
219 this->globalState()->debugSkipAssert())) || (cond))
220#else
221#define SkOPASSERT(cond) SkASSERT((this->globalState() && \
222 this->globalState()->debugSkipAssert()) || (cond))
223#endif
caryclark15976282016-07-21 05:48:43 -0700224#define SkOPOBJASSERT(obj, cond) SkASSERT((obj->debugGlobalState() && \
caryclark30b9fdd2016-08-31 14:36:29 -0700225 obj->debugGlobalState()->debugSkipAssert()) || (cond))
caryclarkcdeff812016-07-22 03:34:19 -0700226#else
227#define SkOPASSERT(cond)
228#define SkOPOBJASSERT(obj, cond)
229#endif
caryclark15976282016-07-21 05:48:43 -0700230
caryclark@google.comc3f63572013-04-23 12:04:05 +0000231// Use Almost Equal when comparing coordinates. Use epsilon to compare T values.
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000232bool AlmostEqualUlps(float a, float b);
233inline bool AlmostEqualUlps(double a, double b) {
234 return AlmostEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000235}
236
caryclark55888e42016-07-18 10:01:36 -0700237bool AlmostEqualUlpsNoNormalCheck(float a, float b);
238inline bool AlmostEqualUlpsNoNormalCheck(double a, double b) {
239 return AlmostEqualUlpsNoNormalCheck(SkDoubleToScalar(a), SkDoubleToScalar(b));
240}
241
caryclarkb6693002015-12-16 12:28:35 -0800242bool AlmostEqualUlps_Pin(float a, float b);
243inline bool AlmostEqualUlps_Pin(double a, double b) {
244 return AlmostEqualUlps_Pin(SkDoubleToScalar(a), SkDoubleToScalar(b));
245}
246
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000247// Use Almost Dequal when comparing should not special case denormalized values.
248bool AlmostDequalUlps(float a, float b);
commit-bot@chromium.org2db7fe72014-05-07 15:31:40 +0000249bool AlmostDequalUlps(double a, double b);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000250
caryclark@google.com570863f2013-09-16 15:55:01 +0000251bool NotAlmostEqualUlps(float a, float b);
252inline bool NotAlmostEqualUlps(double a, double b) {
253 return NotAlmostEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
254}
255
caryclarkb6693002015-12-16 12:28:35 -0800256bool NotAlmostEqualUlps_Pin(float a, float b);
257inline bool NotAlmostEqualUlps_Pin(double a, double b) {
258 return NotAlmostEqualUlps_Pin(SkDoubleToScalar(a), SkDoubleToScalar(b));
259}
260
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000261bool NotAlmostDequalUlps(float a, float b);
262inline bool NotAlmostDequalUlps(double a, double b) {
263 return NotAlmostDequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
264}
265
caryclark@google.com570863f2013-09-16 15:55:01 +0000266// Use Almost Bequal when comparing coordinates in conjunction with between.
267bool AlmostBequalUlps(float a, float b);
268inline bool AlmostBequalUlps(double a, double b) {
269 return AlmostBequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
270}
271
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000272bool AlmostPequalUlps(float a, float b);
273inline bool AlmostPequalUlps(double a, double b) {
274 return AlmostPequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
275}
276
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000277bool RoughlyEqualUlps(float a, float b);
278inline bool RoughlyEqualUlps(double a, double b) {
279 return RoughlyEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000280}
281
caryclark@google.com570863f2013-09-16 15:55:01 +0000282bool AlmostLessUlps(float a, float b);
283inline bool AlmostLessUlps(double a, double b) {
284 return AlmostLessUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
285}
286
287bool AlmostLessOrEqualUlps(float a, float b);
288inline bool AlmostLessOrEqualUlps(double a, double b) {
289 return AlmostLessOrEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
290}
291
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000292bool AlmostBetweenUlps(float a, float b, float c);
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000293inline bool AlmostBetweenUlps(double a, double b, double c) {
294 return AlmostBetweenUlps(SkDoubleToScalar(a), SkDoubleToScalar(b), SkDoubleToScalar(c));
295}
296
297int UlpsDistance(float a, float b);
298inline int UlpsDistance(double a, double b) {
299 return UlpsDistance(SkDoubleToScalar(a), SkDoubleToScalar(b));
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000300}
301
caryclark@google.com07393ca2013-04-08 11:47:37 +0000302// FLT_EPSILON == 1.19209290E-07 == 1 / (2 ^ 23)
303// DBL_EPSILON == 2.22045e-16
304const double FLT_EPSILON_CUBED = FLT_EPSILON * FLT_EPSILON * FLT_EPSILON;
305const double FLT_EPSILON_HALF = FLT_EPSILON / 2;
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000306const double FLT_EPSILON_DOUBLE = FLT_EPSILON * 2;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000307const double FLT_EPSILON_ORDERABLE_ERR = FLT_EPSILON * 16;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000308const double FLT_EPSILON_SQUARED = FLT_EPSILON * FLT_EPSILON;
309const double FLT_EPSILON_SQRT = sqrt(FLT_EPSILON);
310const double FLT_EPSILON_INVERSE = 1 / FLT_EPSILON;
311const double DBL_EPSILON_ERR = DBL_EPSILON * 4; // FIXME: tune -- allow a few bits of error
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000312const double DBL_EPSILON_SUBDIVIDE_ERR = DBL_EPSILON * 16;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000313const double ROUGH_EPSILON = FLT_EPSILON * 64;
314const double MORE_ROUGH_EPSILON = FLT_EPSILON * 256;
caryclarkdac1d172014-06-17 05:15:38 -0700315const double WAY_ROUGH_EPSILON = FLT_EPSILON * 2048;
caryclark54359292015-03-26 07:52:43 -0700316const double BUMP_EPSILON = FLT_EPSILON * 4096;
caryclarkdac1d172014-06-17 05:15:38 -0700317
caryclark55888e42016-07-18 10:01:36 -0700318const SkScalar INVERSE_NUMBER_RANGE = FLT_EPSILON_ORDERABLE_ERR;
319
caryclarkdac1d172014-06-17 05:15:38 -0700320inline bool zero_or_one(double x) {
321 return x == 0 || x == 1;
322}
caryclark@google.com07393ca2013-04-08 11:47:37 +0000323
324inline bool approximately_zero(double x) {
325 return fabs(x) < FLT_EPSILON;
326}
327
328inline bool precisely_zero(double x) {
329 return fabs(x) < DBL_EPSILON_ERR;
330}
331
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000332inline bool precisely_subdivide_zero(double x) {
333 return fabs(x) < DBL_EPSILON_SUBDIVIDE_ERR;
334}
335
caryclark@google.com07393ca2013-04-08 11:47:37 +0000336inline bool approximately_zero(float x) {
337 return fabs(x) < FLT_EPSILON;
338}
339
340inline bool approximately_zero_cubed(double x) {
341 return fabs(x) < FLT_EPSILON_CUBED;
342}
343
344inline bool approximately_zero_half(double x) {
345 return fabs(x) < FLT_EPSILON_HALF;
346}
347
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000348inline bool approximately_zero_double(double x) {
349 return fabs(x) < FLT_EPSILON_DOUBLE;
350}
351
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000352inline bool approximately_zero_orderable(double x) {
353 return fabs(x) < FLT_EPSILON_ORDERABLE_ERR;
354}
355
caryclark@google.com07393ca2013-04-08 11:47:37 +0000356inline bool approximately_zero_squared(double x) {
357 return fabs(x) < FLT_EPSILON_SQUARED;
358}
359
360inline bool approximately_zero_sqrt(double x) {
361 return fabs(x) < FLT_EPSILON_SQRT;
362}
363
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000364inline bool roughly_zero(double x) {
365 return fabs(x) < ROUGH_EPSILON;
366}
367
caryclark@google.com07393ca2013-04-08 11:47:37 +0000368inline bool approximately_zero_inverse(double x) {
369 return fabs(x) > FLT_EPSILON_INVERSE;
370}
371
caryclark@google.com07393ca2013-04-08 11:47:37 +0000372inline bool approximately_zero_when_compared_to(double x, double y) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000373 return x == 0 || fabs(x) < fabs(y * FLT_EPSILON);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000374}
375
caryclark54359292015-03-26 07:52:43 -0700376inline bool precisely_zero_when_compared_to(double x, double y) {
377 return x == 0 || fabs(x) < fabs(y * DBL_EPSILON);
378}
379
caryclark55888e42016-07-18 10:01:36 -0700380inline bool roughly_zero_when_compared_to(double x, double y) {
381 return x == 0 || fabs(x) < fabs(y * ROUGH_EPSILON);
382}
383
caryclark@google.com07393ca2013-04-08 11:47:37 +0000384// Use this for comparing Ts in the range of 0 to 1. For general numbers (larger and smaller) use
385// AlmostEqualUlps instead.
386inline bool approximately_equal(double x, double y) {
387 return approximately_zero(x - y);
388}
389
390inline bool precisely_equal(double x, double y) {
391 return precisely_zero(x - y);
392}
393
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000394inline bool precisely_subdivide_equal(double x, double y) {
395 return precisely_subdivide_zero(x - y);
396}
397
caryclark@google.com07393ca2013-04-08 11:47:37 +0000398inline bool approximately_equal_half(double x, double y) {
399 return approximately_zero_half(x - y);
400}
401
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000402inline bool approximately_equal_double(double x, double y) {
403 return approximately_zero_double(x - y);
404}
405
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000406inline bool approximately_equal_orderable(double x, double y) {
407 return approximately_zero_orderable(x - y);
408}
409
caryclark@google.com07393ca2013-04-08 11:47:37 +0000410inline bool approximately_equal_squared(double x, double y) {
411 return approximately_equal(x, y);
412}
413
414inline bool approximately_greater(double x, double y) {
415 return x - FLT_EPSILON >= y;
416}
417
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000418inline bool approximately_greater_double(double x, double y) {
419 return x - FLT_EPSILON_DOUBLE >= y;
420}
421
422inline bool approximately_greater_orderable(double x, double y) {
423 return x - FLT_EPSILON_ORDERABLE_ERR >= y;
424}
425
caryclark@google.com07393ca2013-04-08 11:47:37 +0000426inline bool approximately_greater_or_equal(double x, double y) {
427 return x + FLT_EPSILON > y;
428}
429
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000430inline bool approximately_greater_or_equal_double(double x, double y) {
431 return x + FLT_EPSILON_DOUBLE > y;
432}
433
434inline bool approximately_greater_or_equal_orderable(double x, double y) {
435 return x + FLT_EPSILON_ORDERABLE_ERR > y;
436}
437
caryclark@google.com07393ca2013-04-08 11:47:37 +0000438inline bool approximately_lesser(double x, double y) {
439 return x + FLT_EPSILON <= y;
440}
441
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000442inline bool approximately_lesser_double(double x, double y) {
443 return x + FLT_EPSILON_DOUBLE <= y;
444}
445
446inline bool approximately_lesser_orderable(double x, double y) {
447 return x + FLT_EPSILON_ORDERABLE_ERR <= y;
448}
449
caryclark@google.com07393ca2013-04-08 11:47:37 +0000450inline bool approximately_lesser_or_equal(double x, double y) {
451 return x - FLT_EPSILON < y;
452}
453
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000454inline bool approximately_lesser_or_equal_double(double x, double y) {
455 return x - FLT_EPSILON_DOUBLE < y;
456}
457
458inline bool approximately_lesser_or_equal_orderable(double x, double y) {
459 return x - FLT_EPSILON_ORDERABLE_ERR < y;
460}
461
caryclark@google.com07393ca2013-04-08 11:47:37 +0000462inline bool approximately_greater_than_one(double x) {
463 return x > 1 - FLT_EPSILON;
464}
465
466inline bool precisely_greater_than_one(double x) {
467 return x > 1 - DBL_EPSILON_ERR;
468}
469
470inline bool approximately_less_than_zero(double x) {
471 return x < FLT_EPSILON;
472}
473
474inline bool precisely_less_than_zero(double x) {
475 return x < DBL_EPSILON_ERR;
476}
477
478inline bool approximately_negative(double x) {
479 return x < FLT_EPSILON;
480}
481
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000482inline bool approximately_negative_orderable(double x) {
483 return x < FLT_EPSILON_ORDERABLE_ERR;
484}
485
caryclark@google.com07393ca2013-04-08 11:47:37 +0000486inline bool precisely_negative(double x) {
487 return x < DBL_EPSILON_ERR;
488}
489
490inline bool approximately_one_or_less(double x) {
491 return x < 1 + FLT_EPSILON;
492}
493
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000494inline bool approximately_one_or_less_double(double x) {
495 return x < 1 + FLT_EPSILON_DOUBLE;
496}
497
caryclark@google.com07393ca2013-04-08 11:47:37 +0000498inline bool approximately_positive(double x) {
499 return x > -FLT_EPSILON;
500}
501
502inline bool approximately_positive_squared(double x) {
503 return x > -(FLT_EPSILON_SQUARED);
504}
505
506inline bool approximately_zero_or_more(double x) {
507 return x > -FLT_EPSILON;
508}
509
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000510inline bool approximately_zero_or_more_double(double x) {
511 return x > -FLT_EPSILON_DOUBLE;
512}
513
514inline bool approximately_between_orderable(double a, double b, double c) {
515 return a <= c
516 ? approximately_negative_orderable(a - b) && approximately_negative_orderable(b - c)
517 : approximately_negative_orderable(b - a) && approximately_negative_orderable(c - b);
518}
519
caryclark@google.com07393ca2013-04-08 11:47:37 +0000520inline bool approximately_between(double a, double b, double c) {
521 return a <= c ? approximately_negative(a - b) && approximately_negative(b - c)
522 : approximately_negative(b - a) && approximately_negative(c - b);
523}
524
caryclark@google.com03610322013-04-18 15:58:21 +0000525inline bool precisely_between(double a, double b, double c) {
526 return a <= c ? precisely_negative(a - b) && precisely_negative(b - c)
527 : precisely_negative(b - a) && precisely_negative(c - b);
528}
529
caryclark@google.com07393ca2013-04-08 11:47:37 +0000530// returns true if (a <= b <= c) || (a >= b >= c)
531inline bool between(double a, double b, double c) {
caryclark54359292015-03-26 07:52:43 -0700532 SkASSERT(((a <= b && b <= c) || (a >= b && b >= c)) == ((a - b) * (c - b) <= 0)
533 || (precisely_zero(a) && precisely_zero(b) && precisely_zero(c)));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000534 return (a - b) * (c - b) <= 0;
535}
536
caryclarkdac1d172014-06-17 05:15:38 -0700537inline bool roughly_equal(double x, double y) {
538 return fabs(x - y) < ROUGH_EPSILON;
539}
540
caryclark54359292015-03-26 07:52:43 -0700541inline bool roughly_negative(double x) {
542 return x < ROUGH_EPSILON;
543}
544
545inline bool roughly_between(double a, double b, double c) {
546 return a <= c ? roughly_negative(a - b) && roughly_negative(b - c)
547 : roughly_negative(b - a) && roughly_negative(c - b);
548}
549
caryclark@google.com07393ca2013-04-08 11:47:37 +0000550inline bool more_roughly_equal(double x, double y) {
551 return fabs(x - y) < MORE_ROUGH_EPSILON;
552}
553
caryclark@google.com07393ca2013-04-08 11:47:37 +0000554struct SkDPoint;
555struct SkDVector;
556struct SkDLine;
557struct SkDQuad;
caryclark1049f122015-04-20 08:31:59 -0700558struct SkDConic;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000559struct SkDCubic;
560struct SkDRect;
561
reed@google.com277c3f82013-05-31 15:17:50 +0000562inline SkPath::Verb SkPathOpsPointsToVerb(int points) {
563 int verb = (1 << points) >> 1;
564#ifdef SK_DEBUG
565 switch (points) {
566 case 0: SkASSERT(SkPath::kMove_Verb == verb); break;
567 case 1: SkASSERT(SkPath::kLine_Verb == verb); break;
568 case 2: SkASSERT(SkPath::kQuad_Verb == verb); break;
569 case 3: SkASSERT(SkPath::kCubic_Verb == verb); break;
mtklein@google.com330313a2013-08-22 15:37:26 +0000570 default: SkDEBUGFAIL("should not be here");
reed@google.com277c3f82013-05-31 15:17:50 +0000571 }
572#endif
573 return (SkPath::Verb)verb;
574}
575
576inline int SkPathOpsVerbToPoints(SkPath::Verb verb) {
caryclark1049f122015-04-20 08:31:59 -0700577 int points = (int) verb - (((int) verb + 1) >> 2);
reed@google.com277c3f82013-05-31 15:17:50 +0000578#ifdef SK_DEBUG
579 switch (verb) {
580 case SkPath::kLine_Verb: SkASSERT(1 == points); break;
581 case SkPath::kQuad_Verb: SkASSERT(2 == points); break;
caryclark1049f122015-04-20 08:31:59 -0700582 case SkPath::kConic_Verb: SkASSERT(2 == points); break;
reed@google.com277c3f82013-05-31 15:17:50 +0000583 case SkPath::kCubic_Verb: SkASSERT(3 == points); break;
mtklein@google.com330313a2013-08-22 15:37:26 +0000584 default: SkDEBUGFAIL("should not get here");
reed@google.com277c3f82013-05-31 15:17:50 +0000585 }
586#endif
587 return points;
588}
589
caryclark@google.com07393ca2013-04-08 11:47:37 +0000590inline double SkDInterp(double A, double B, double t) {
591 return A + (B - A) * t;
592}
593
594double SkDCubeRoot(double x);
595
596/* Returns -1 if negative, 0 if zero, 1 if positive
597*/
598inline int SkDSign(double x) {
599 return (x > 0) - (x < 0);
600}
601
602/* Returns 0 if negative, 1 if zero, 2 if positive
603*/
604inline int SKDSide(double x) {
605 return (x > 0) + (x >= 0);
606}
607
608/* Returns 1 if negative, 2 if zero, 4 if positive
609*/
610inline int SkDSideBit(double x) {
611 return 1 << SKDSide(x);
612}
613
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000614inline double SkPinT(double t) {
615 return precisely_less_than_zero(t) ? 0 : precisely_greater_than_one(t) ? 1 : t;
616}
617
caryclark@google.com07393ca2013-04-08 11:47:37 +0000618#endif