blob: 4e9fbe9ac5f347eeb1427e414efcbbfb55932446 [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
caryclark@google.com07393ca2013-04-08 11:47:37 +000011
12#include "SkFloatingPoint.h"
reed@google.com277c3f82013-05-31 15:17:50 +000013#include "SkPath.h"
caryclark@google.com07393ca2013-04-08 11:47:37 +000014#include "SkPathOps.h"
15#include "SkPathOpsDebug.h"
Mike Kleine9f78b42016-11-22 08:57:45 -050016#include "SkSafe_math.h" // for fabs, sqrt
caryclark@google.com07393ca2013-04-08 11:47:37 +000017#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;
caryclark13260682016-10-24 05:10:14 -070078#endif
79
caryclark13260682016-10-24 05:10:14 -070080#ifdef SK_DEBUG
caryclark54359292015-03-26 07:52:43 -070081 const class SkOpSegment* debugSegment(int id) const;
caryclarkdae6b972016-06-08 04:28:19 -070082 bool debugSkipAssert() const { return fDebugSkipAssert; }
caryclark54359292015-03-26 07:52:43 -070083 const class SkOpSpanBase* debugSpan(int id) const;
caryclarkd4349722015-07-23 12:40:22 -070084 const char* debugTestName() const { return fDebugTestName; }
caryclark4e1a4c92015-05-18 12:56:57 -070085#endif
caryclark54359292015-03-26 07:52:43 -070086
caryclark26ad22a2015-10-16 09:03:38 -070087#if DEBUG_T_SECT_LOOP_COUNT
88 void debugAddLoopCount(SkIntersections* , const SkIntersectionHelper& ,
89 const SkIntersectionHelper& );
90 void debugDoYourWorst(SkOpGlobalState* );
91 void debugLoopReport();
92 void debugResetLoopCounts();
93#endif
94
caryclark55888e42016-07-18 10:01:36 -070095#if DEBUG_COINCIDENCE
96 void debugSetCheckHealth(bool check) { fDebugCheckHealth = check; }
97 bool debugCheckHealth() const { return fDebugCheckHealth; }
98#endif
99
Cary Clarkab87d7a2016-10-04 10:01:04 -0400100#if DEBUG_VALIDATE || DEBUG_COIN
101 void debugSetPhase(const char* funcName DEBUG_COIN_DECLARE_PARAMS()) const;
102#endif
103
104#if DEBUG_COIN
105 void debugAddToCoinChangedDict();
106 void debugAddToGlobalCoinDicts();
107 SkPathOpsDebug::CoinDict* debugCoinChangedDict() { return &fCoinChangedDict; }
108 const SkPathOpsDebug::CoinDictEntry& debugCoinDictEntry() const { return fCoinDictEntry; }
109
110 static void DumpCoinDict();
111#endif
112
113
caryclark4e1a4c92015-05-18 12:56:57 -0700114 int nested() const {
115 return fNested;
116 }
117
118#ifdef SK_DEBUG
caryclark54359292015-03-26 07:52:43 -0700119 int nextAngleID() {
120 return ++fAngleID;
121 }
122
caryclark26ad22a2015-10-16 09:03:38 -0700123 int nextCoinID() {
124 return ++fCoinID;
125 }
126
caryclark54359292015-03-26 07:52:43 -0700127 int nextContourID() {
128 return ++fContourID;
129 }
caryclark26ad22a2015-10-16 09:03:38 -0700130
caryclark54359292015-03-26 07:52:43 -0700131 int nextPtTID() {
132 return ++fPtTID;
133 }
134
135 int nextSegmentID() {
136 return ++fSegmentID;
137 }
138
139 int nextSpanID() {
140 return ++fSpanID;
141 }
142#endif
143
Cary Clarkab87d7a2016-10-04 10:01:04 -0400144 SkOpPhase phase() const {
caryclark54359292015-03-26 07:52:43 -0700145 return fPhase;
146 }
Mike Kleine9f78b42016-11-22 08:57:45 -0500147
caryclark29b25632016-08-25 11:27:17 -0700148 void resetAllocatedOpSpan() {
149 fAllocatedOpSpan = false;
150 }
151
152 void setAllocatedOpSpan() {
153 fAllocatedOpSpan = true;
154 }
caryclark54359292015-03-26 07:52:43 -0700155
caryclark55888e42016-07-18 10:01:36 -0700156 void setCoincidence(SkOpCoincidence* coincidence) {
157 fCoincidence = coincidence;
158 }
Mike Kleine9f78b42016-11-22 08:57:45 -0500159
caryclark624637c2015-05-11 07:21:27 -0700160 void setContourHead(SkOpContourHead* contourHead) {
161 fContourHead = contourHead;
162 }
163
Cary Clarkab87d7a2016-10-04 10:01:04 -0400164 void setPhase(SkOpPhase phase) {
165 if (SkOpPhase::kNoChange == phase) {
166 return;
167 }
caryclark54359292015-03-26 07:52:43 -0700168 SkASSERT(fPhase != phase);
169 fPhase = phase;
170 }
caryclark54359292015-03-26 07:52:43 -0700171
172 // called in very rare cases where angles are sorted incorrectly -- signfies op will fail
173 void setWindingFailed() {
174 fWindingFailed = true;
175 }
176
177 bool windingFailed() const {
178 return fWindingFailed;
179 }
180
181private:
caryclark55888e42016-07-18 10:01:36 -0700182 SkChunkAlloc* fAllocator;
caryclark54359292015-03-26 07:52:43 -0700183 SkOpCoincidence* fCoincidence;
caryclark624637c2015-05-11 07:21:27 -0700184 SkOpContourHead* fContourHead;
caryclark4e1a4c92015-05-18 12:56:57 -0700185 int fNested;
caryclark29b25632016-08-25 11:27:17 -0700186 bool fAllocatedOpSpan;
caryclark54359292015-03-26 07:52:43 -0700187 bool fWindingFailed;
Cary Clarkab87d7a2016-10-04 10:01:04 -0400188 SkOpPhase fPhase;
caryclark54359292015-03-26 07:52:43 -0700189#ifdef SK_DEBUG
caryclarkd4349722015-07-23 12:40:22 -0700190 const char* fDebugTestName;
Cary Clarkab87d7a2016-10-04 10:01:04 -0400191 void* fDebugReporter;
caryclark54359292015-03-26 07:52:43 -0700192 int fAngleID;
caryclark26ad22a2015-10-16 09:03:38 -0700193 int fCoinID;
caryclark54359292015-03-26 07:52:43 -0700194 int fContourID;
195 int fPtTID;
196 int fSegmentID;
197 int fSpanID;
caryclarkdae6b972016-06-08 04:28:19 -0700198 bool fDebugSkipAssert;
caryclark54359292015-03-26 07:52:43 -0700199#endif
caryclark26ad22a2015-10-16 09:03:38 -0700200#if DEBUG_T_SECT_LOOP_COUNT
201 int fDebugLoopCount[3];
202 SkPath::Verb fDebugWorstVerb[6];
203 SkPoint fDebugWorstPts[24];
204 float fDebugWorstWeight[6];
205#endif
Cary Clarkab87d7a2016-10-04 10:01:04 -0400206#if DEBUG_COIN
207 SkPathOpsDebug::CoinDict fCoinChangedDict;
208 SkPathOpsDebug::CoinDict fCoinVisitedDict;
209 SkPathOpsDebug::CoinDictEntry fCoinDictEntry;
210 const char* fPreviousFuncName;
211#endif
caryclark55888e42016-07-18 10:01:36 -0700212#if DEBUG_COINCIDENCE
213 bool fDebugCheckHealth;
214#endif
caryclark54359292015-03-26 07:52:43 -0700215};
216
caryclarkcdeff812016-07-22 03:34:19 -0700217#ifdef SK_DEBUG
caryclark30b9fdd2016-08-31 14:36:29 -0700218#if DEBUG_COINCIDENCE
caryclarke25a4f62016-07-26 09:26:29 -0700219#define SkOPASSERT(cond) SkASSERT((this->globalState() && \
caryclark30b9fdd2016-08-31 14:36:29 -0700220 (this->globalState()->debugCheckHealth() || \
221 this->globalState()->debugSkipAssert())) || (cond))
222#else
223#define SkOPASSERT(cond) SkASSERT((this->globalState() && \
224 this->globalState()->debugSkipAssert()) || (cond))
225#endif
caryclarka35ab3e2016-10-20 08:32:18 -0700226#define SkOPOBJASSERT(obj, cond) SkASSERT((obj->globalState() && \
227 obj->globalState()->debugSkipAssert()) || (cond))
caryclarkcdeff812016-07-22 03:34:19 -0700228#else
229#define SkOPASSERT(cond)
230#define SkOPOBJASSERT(obj, cond)
231#endif
caryclark15976282016-07-21 05:48:43 -0700232
caryclark@google.comc3f63572013-04-23 12:04:05 +0000233// Use Almost Equal when comparing coordinates. Use epsilon to compare T values.
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000234bool AlmostEqualUlps(float a, float b);
235inline bool AlmostEqualUlps(double a, double b) {
236 return AlmostEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000237}
238
caryclark55888e42016-07-18 10:01:36 -0700239bool AlmostEqualUlpsNoNormalCheck(float a, float b);
240inline bool AlmostEqualUlpsNoNormalCheck(double a, double b) {
241 return AlmostEqualUlpsNoNormalCheck(SkDoubleToScalar(a), SkDoubleToScalar(b));
242}
243
caryclarkb6693002015-12-16 12:28:35 -0800244bool AlmostEqualUlps_Pin(float a, float b);
245inline bool AlmostEqualUlps_Pin(double a, double b) {
246 return AlmostEqualUlps_Pin(SkDoubleToScalar(a), SkDoubleToScalar(b));
247}
248
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000249// Use Almost Dequal when comparing should not special case denormalized values.
250bool AlmostDequalUlps(float a, float b);
commit-bot@chromium.org2db7fe72014-05-07 15:31:40 +0000251bool AlmostDequalUlps(double a, double b);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000252
caryclark@google.com570863f2013-09-16 15:55:01 +0000253bool NotAlmostEqualUlps(float a, float b);
254inline bool NotAlmostEqualUlps(double a, double b) {
255 return NotAlmostEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
256}
257
caryclarkb6693002015-12-16 12:28:35 -0800258bool NotAlmostEqualUlps_Pin(float a, float b);
259inline bool NotAlmostEqualUlps_Pin(double a, double b) {
260 return NotAlmostEqualUlps_Pin(SkDoubleToScalar(a), SkDoubleToScalar(b));
261}
262
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000263bool NotAlmostDequalUlps(float a, float b);
264inline bool NotAlmostDequalUlps(double a, double b) {
265 return NotAlmostDequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
266}
267
caryclark@google.com570863f2013-09-16 15:55:01 +0000268// Use Almost Bequal when comparing coordinates in conjunction with between.
269bool AlmostBequalUlps(float a, float b);
270inline bool AlmostBequalUlps(double a, double b) {
271 return AlmostBequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
272}
273
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000274bool AlmostPequalUlps(float a, float b);
275inline bool AlmostPequalUlps(double a, double b) {
276 return AlmostPequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
277}
278
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000279bool RoughlyEqualUlps(float a, float b);
280inline bool RoughlyEqualUlps(double a, double b) {
281 return RoughlyEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000282}
283
caryclark@google.com570863f2013-09-16 15:55:01 +0000284bool AlmostLessUlps(float a, float b);
285inline bool AlmostLessUlps(double a, double b) {
286 return AlmostLessUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
287}
288
289bool AlmostLessOrEqualUlps(float a, float b);
290inline bool AlmostLessOrEqualUlps(double a, double b) {
291 return AlmostLessOrEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
292}
293
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000294bool AlmostBetweenUlps(float a, float b, float c);
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000295inline bool AlmostBetweenUlps(double a, double b, double c) {
296 return AlmostBetweenUlps(SkDoubleToScalar(a), SkDoubleToScalar(b), SkDoubleToScalar(c));
297}
298
299int UlpsDistance(float a, float b);
300inline int UlpsDistance(double a, double b) {
301 return UlpsDistance(SkDoubleToScalar(a), SkDoubleToScalar(b));
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000302}
303
caryclark@google.com07393ca2013-04-08 11:47:37 +0000304// FLT_EPSILON == 1.19209290E-07 == 1 / (2 ^ 23)
305// DBL_EPSILON == 2.22045e-16
306const double FLT_EPSILON_CUBED = FLT_EPSILON * FLT_EPSILON * FLT_EPSILON;
307const double FLT_EPSILON_HALF = FLT_EPSILON / 2;
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000308const double FLT_EPSILON_DOUBLE = FLT_EPSILON * 2;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000309const double FLT_EPSILON_ORDERABLE_ERR = FLT_EPSILON * 16;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000310const double FLT_EPSILON_SQUARED = FLT_EPSILON * FLT_EPSILON;
Bruce Dawson759ae562016-11-18 15:08:45 -0500311// Use a compile-time constant for FLT_EPSILON_SQRT to avoid initializers.
312// A 17 digit constant guarantees exact results.
313const double FLT_EPSILON_SQRT = 0.00034526697709225118; // sqrt(FLT_EPSILON);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000314const double FLT_EPSILON_INVERSE = 1 / FLT_EPSILON;
315const double DBL_EPSILON_ERR = DBL_EPSILON * 4; // FIXME: tune -- allow a few bits of error
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000316const double DBL_EPSILON_SUBDIVIDE_ERR = DBL_EPSILON * 16;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000317const double ROUGH_EPSILON = FLT_EPSILON * 64;
318const double MORE_ROUGH_EPSILON = FLT_EPSILON * 256;
caryclarkdac1d172014-06-17 05:15:38 -0700319const double WAY_ROUGH_EPSILON = FLT_EPSILON * 2048;
caryclark54359292015-03-26 07:52:43 -0700320const double BUMP_EPSILON = FLT_EPSILON * 4096;
caryclarkdac1d172014-06-17 05:15:38 -0700321
caryclark55888e42016-07-18 10:01:36 -0700322const SkScalar INVERSE_NUMBER_RANGE = FLT_EPSILON_ORDERABLE_ERR;
323
caryclarkdac1d172014-06-17 05:15:38 -0700324inline bool zero_or_one(double x) {
325 return x == 0 || x == 1;
326}
caryclark@google.com07393ca2013-04-08 11:47:37 +0000327
328inline bool approximately_zero(double x) {
329 return fabs(x) < FLT_EPSILON;
330}
331
332inline bool precisely_zero(double x) {
333 return fabs(x) < DBL_EPSILON_ERR;
334}
335
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000336inline bool precisely_subdivide_zero(double x) {
337 return fabs(x) < DBL_EPSILON_SUBDIVIDE_ERR;
338}
339
caryclark@google.com07393ca2013-04-08 11:47:37 +0000340inline bool approximately_zero(float x) {
341 return fabs(x) < FLT_EPSILON;
342}
343
344inline bool approximately_zero_cubed(double x) {
345 return fabs(x) < FLT_EPSILON_CUBED;
346}
347
348inline bool approximately_zero_half(double x) {
349 return fabs(x) < FLT_EPSILON_HALF;
350}
351
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000352inline bool approximately_zero_double(double x) {
353 return fabs(x) < FLT_EPSILON_DOUBLE;
354}
355
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000356inline bool approximately_zero_orderable(double x) {
357 return fabs(x) < FLT_EPSILON_ORDERABLE_ERR;
358}
359
caryclark@google.com07393ca2013-04-08 11:47:37 +0000360inline bool approximately_zero_squared(double x) {
361 return fabs(x) < FLT_EPSILON_SQUARED;
362}
363
364inline bool approximately_zero_sqrt(double x) {
365 return fabs(x) < FLT_EPSILON_SQRT;
366}
367
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000368inline bool roughly_zero(double x) {
369 return fabs(x) < ROUGH_EPSILON;
370}
371
caryclark@google.com07393ca2013-04-08 11:47:37 +0000372inline bool approximately_zero_inverse(double x) {
373 return fabs(x) > FLT_EPSILON_INVERSE;
374}
375
caryclark@google.com07393ca2013-04-08 11:47:37 +0000376inline bool approximately_zero_when_compared_to(double x, double y) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000377 return x == 0 || fabs(x) < fabs(y * FLT_EPSILON);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000378}
379
caryclark54359292015-03-26 07:52:43 -0700380inline bool precisely_zero_when_compared_to(double x, double y) {
381 return x == 0 || fabs(x) < fabs(y * DBL_EPSILON);
382}
383
caryclark55888e42016-07-18 10:01:36 -0700384inline bool roughly_zero_when_compared_to(double x, double y) {
385 return x == 0 || fabs(x) < fabs(y * ROUGH_EPSILON);
386}
387
caryclark@google.com07393ca2013-04-08 11:47:37 +0000388// Use this for comparing Ts in the range of 0 to 1. For general numbers (larger and smaller) use
389// AlmostEqualUlps instead.
390inline bool approximately_equal(double x, double y) {
391 return approximately_zero(x - y);
392}
393
394inline bool precisely_equal(double x, double y) {
395 return precisely_zero(x - y);
396}
397
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000398inline bool precisely_subdivide_equal(double x, double y) {
399 return precisely_subdivide_zero(x - y);
400}
401
caryclark@google.com07393ca2013-04-08 11:47:37 +0000402inline bool approximately_equal_half(double x, double y) {
403 return approximately_zero_half(x - y);
404}
405
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000406inline bool approximately_equal_double(double x, double y) {
407 return approximately_zero_double(x - y);
408}
409
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000410inline bool approximately_equal_orderable(double x, double y) {
411 return approximately_zero_orderable(x - y);
412}
413
caryclark@google.com07393ca2013-04-08 11:47:37 +0000414inline bool approximately_equal_squared(double x, double y) {
415 return approximately_equal(x, y);
416}
417
418inline bool approximately_greater(double x, double y) {
419 return x - FLT_EPSILON >= y;
420}
421
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000422inline bool approximately_greater_double(double x, double y) {
423 return x - FLT_EPSILON_DOUBLE >= y;
424}
425
426inline bool approximately_greater_orderable(double x, double y) {
427 return x - FLT_EPSILON_ORDERABLE_ERR >= y;
428}
429
caryclark@google.com07393ca2013-04-08 11:47:37 +0000430inline bool approximately_greater_or_equal(double x, double y) {
431 return x + FLT_EPSILON > y;
432}
433
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000434inline bool approximately_greater_or_equal_double(double x, double y) {
435 return x + FLT_EPSILON_DOUBLE > y;
436}
437
438inline bool approximately_greater_or_equal_orderable(double x, double y) {
439 return x + FLT_EPSILON_ORDERABLE_ERR > y;
440}
441
caryclark@google.com07393ca2013-04-08 11:47:37 +0000442inline bool approximately_lesser(double x, double y) {
443 return x + FLT_EPSILON <= y;
444}
445
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000446inline bool approximately_lesser_double(double x, double y) {
447 return x + FLT_EPSILON_DOUBLE <= y;
448}
449
450inline bool approximately_lesser_orderable(double x, double y) {
451 return x + FLT_EPSILON_ORDERABLE_ERR <= y;
452}
453
caryclark@google.com07393ca2013-04-08 11:47:37 +0000454inline bool approximately_lesser_or_equal(double x, double y) {
455 return x - FLT_EPSILON < y;
456}
457
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000458inline bool approximately_lesser_or_equal_double(double x, double y) {
459 return x - FLT_EPSILON_DOUBLE < y;
460}
461
462inline bool approximately_lesser_or_equal_orderable(double x, double y) {
463 return x - FLT_EPSILON_ORDERABLE_ERR < y;
464}
465
caryclark@google.com07393ca2013-04-08 11:47:37 +0000466inline bool approximately_greater_than_one(double x) {
467 return x > 1 - FLT_EPSILON;
468}
469
470inline bool precisely_greater_than_one(double x) {
471 return x > 1 - DBL_EPSILON_ERR;
472}
473
474inline bool approximately_less_than_zero(double x) {
475 return x < FLT_EPSILON;
476}
477
478inline bool precisely_less_than_zero(double x) {
479 return x < DBL_EPSILON_ERR;
480}
481
482inline bool approximately_negative(double x) {
483 return x < FLT_EPSILON;
484}
485
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000486inline bool approximately_negative_orderable(double x) {
487 return x < FLT_EPSILON_ORDERABLE_ERR;
488}
489
caryclark@google.com07393ca2013-04-08 11:47:37 +0000490inline bool precisely_negative(double x) {
491 return x < DBL_EPSILON_ERR;
492}
493
494inline bool approximately_one_or_less(double x) {
495 return x < 1 + FLT_EPSILON;
496}
497
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000498inline bool approximately_one_or_less_double(double x) {
499 return x < 1 + FLT_EPSILON_DOUBLE;
500}
501
caryclark@google.com07393ca2013-04-08 11:47:37 +0000502inline bool approximately_positive(double x) {
503 return x > -FLT_EPSILON;
504}
505
506inline bool approximately_positive_squared(double x) {
507 return x > -(FLT_EPSILON_SQUARED);
508}
509
510inline bool approximately_zero_or_more(double x) {
511 return x > -FLT_EPSILON;
512}
513
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000514inline bool approximately_zero_or_more_double(double x) {
515 return x > -FLT_EPSILON_DOUBLE;
516}
517
518inline bool approximately_between_orderable(double a, double b, double c) {
519 return a <= c
520 ? approximately_negative_orderable(a - b) && approximately_negative_orderable(b - c)
521 : approximately_negative_orderable(b - a) && approximately_negative_orderable(c - b);
522}
523
caryclark@google.com07393ca2013-04-08 11:47:37 +0000524inline bool approximately_between(double a, double b, double c) {
525 return a <= c ? approximately_negative(a - b) && approximately_negative(b - c)
526 : approximately_negative(b - a) && approximately_negative(c - b);
527}
528
caryclark@google.com03610322013-04-18 15:58:21 +0000529inline bool precisely_between(double a, double b, double c) {
530 return a <= c ? precisely_negative(a - b) && precisely_negative(b - c)
531 : precisely_negative(b - a) && precisely_negative(c - b);
532}
533
caryclark@google.com07393ca2013-04-08 11:47:37 +0000534// returns true if (a <= b <= c) || (a >= b >= c)
535inline bool between(double a, double b, double c) {
caryclark54359292015-03-26 07:52:43 -0700536 SkASSERT(((a <= b && b <= c) || (a >= b && b >= c)) == ((a - b) * (c - b) <= 0)
537 || (precisely_zero(a) && precisely_zero(b) && precisely_zero(c)));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000538 return (a - b) * (c - b) <= 0;
539}
540
caryclarkdac1d172014-06-17 05:15:38 -0700541inline bool roughly_equal(double x, double y) {
542 return fabs(x - y) < ROUGH_EPSILON;
543}
544
caryclark54359292015-03-26 07:52:43 -0700545inline bool roughly_negative(double x) {
546 return x < ROUGH_EPSILON;
547}
548
549inline bool roughly_between(double a, double b, double c) {
550 return a <= c ? roughly_negative(a - b) && roughly_negative(b - c)
551 : roughly_negative(b - a) && roughly_negative(c - b);
552}
553
caryclark@google.com07393ca2013-04-08 11:47:37 +0000554inline bool more_roughly_equal(double x, double y) {
555 return fabs(x - y) < MORE_ROUGH_EPSILON;
556}
557
caryclark@google.com07393ca2013-04-08 11:47:37 +0000558struct SkDPoint;
559struct SkDVector;
560struct SkDLine;
561struct SkDQuad;
caryclark1049f122015-04-20 08:31:59 -0700562struct SkDConic;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000563struct SkDCubic;
564struct SkDRect;
565
reed@google.com277c3f82013-05-31 15:17:50 +0000566inline SkPath::Verb SkPathOpsPointsToVerb(int points) {
567 int verb = (1 << points) >> 1;
568#ifdef SK_DEBUG
569 switch (points) {
570 case 0: SkASSERT(SkPath::kMove_Verb == verb); break;
571 case 1: SkASSERT(SkPath::kLine_Verb == verb); break;
572 case 2: SkASSERT(SkPath::kQuad_Verb == verb); break;
573 case 3: SkASSERT(SkPath::kCubic_Verb == verb); break;
mtklein@google.com330313a2013-08-22 15:37:26 +0000574 default: SkDEBUGFAIL("should not be here");
reed@google.com277c3f82013-05-31 15:17:50 +0000575 }
576#endif
577 return (SkPath::Verb)verb;
578}
579
580inline int SkPathOpsVerbToPoints(SkPath::Verb verb) {
caryclark1049f122015-04-20 08:31:59 -0700581 int points = (int) verb - (((int) verb + 1) >> 2);
reed@google.com277c3f82013-05-31 15:17:50 +0000582#ifdef SK_DEBUG
583 switch (verb) {
584 case SkPath::kLine_Verb: SkASSERT(1 == points); break;
585 case SkPath::kQuad_Verb: SkASSERT(2 == points); break;
caryclark1049f122015-04-20 08:31:59 -0700586 case SkPath::kConic_Verb: SkASSERT(2 == points); break;
reed@google.com277c3f82013-05-31 15:17:50 +0000587 case SkPath::kCubic_Verb: SkASSERT(3 == points); break;
mtklein@google.com330313a2013-08-22 15:37:26 +0000588 default: SkDEBUGFAIL("should not get here");
reed@google.com277c3f82013-05-31 15:17:50 +0000589 }
590#endif
591 return points;
592}
593
caryclark@google.com07393ca2013-04-08 11:47:37 +0000594inline double SkDInterp(double A, double B, double t) {
595 return A + (B - A) * t;
596}
597
598double SkDCubeRoot(double x);
599
600/* Returns -1 if negative, 0 if zero, 1 if positive
601*/
602inline int SkDSign(double x) {
603 return (x > 0) - (x < 0);
604}
605
606/* Returns 0 if negative, 1 if zero, 2 if positive
607*/
608inline int SKDSide(double x) {
609 return (x > 0) + (x >= 0);
610}
611
612/* Returns 1 if negative, 2 if zero, 4 if positive
613*/
614inline int SkDSideBit(double x) {
615 return 1 << SKDSide(x);
616}
617
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000618inline double SkPinT(double t) {
619 return precisely_less_than_zero(t) ? 0 : precisely_greater_than_one(t) ? 1 : t;
620}
621
caryclark@google.com07393ca2013-04-08 11:47:37 +0000622#endif