blob: 2fef8266c277073208dc8606b13901d2ab2e0a73 [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
Herb Derbyc3cc5fa2017-03-07 11:11:47 -050025class SkArenaAlloc;
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,
Herb Derbyc3cc5fa2017-03-07 11:11:47 -050042 SkArenaAlloc* 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
Herb Derbyc3cc5fa2017-03-07 11:11:47 -050053 SkArenaAlloc* allocator() {
caryclark55888e42016-07-18 10:01:36 -070054 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
Cary Clark59d5a0e2017-01-23 14:38:52 +000080 static bool DebugRunFail();
81
caryclark13260682016-10-24 05:10:14 -070082#ifdef SK_DEBUG
caryclark54359292015-03-26 07:52:43 -070083 const class SkOpSegment* debugSegment(int id) const;
caryclarkdae6b972016-06-08 04:28:19 -070084 bool debugSkipAssert() const { return fDebugSkipAssert; }
caryclark54359292015-03-26 07:52:43 -070085 const class SkOpSpanBase* debugSpan(int id) const;
caryclarkd4349722015-07-23 12:40:22 -070086 const char* debugTestName() const { return fDebugTestName; }
caryclark4e1a4c92015-05-18 12:56:57 -070087#endif
caryclark54359292015-03-26 07:52:43 -070088
caryclark26ad22a2015-10-16 09:03:38 -070089#if DEBUG_T_SECT_LOOP_COUNT
90 void debugAddLoopCount(SkIntersections* , const SkIntersectionHelper& ,
91 const SkIntersectionHelper& );
92 void debugDoYourWorst(SkOpGlobalState* );
93 void debugLoopReport();
94 void debugResetLoopCounts();
95#endif
96
caryclark55888e42016-07-18 10:01:36 -070097#if DEBUG_COINCIDENCE
98 void debugSetCheckHealth(bool check) { fDebugCheckHealth = check; }
99 bool debugCheckHealth() const { return fDebugCheckHealth; }
100#endif
101
Cary Clarkab87d7a2016-10-04 10:01:04 -0400102#if DEBUG_VALIDATE || DEBUG_COIN
103 void debugSetPhase(const char* funcName DEBUG_COIN_DECLARE_PARAMS()) const;
104#endif
105
106#if DEBUG_COIN
107 void debugAddToCoinChangedDict();
108 void debugAddToGlobalCoinDicts();
109 SkPathOpsDebug::CoinDict* debugCoinChangedDict() { return &fCoinChangedDict; }
110 const SkPathOpsDebug::CoinDictEntry& debugCoinDictEntry() const { return fCoinDictEntry; }
111
112 static void DumpCoinDict();
113#endif
114
115
caryclark4e1a4c92015-05-18 12:56:57 -0700116 int nested() const {
117 return fNested;
118 }
119
120#ifdef SK_DEBUG
caryclark54359292015-03-26 07:52:43 -0700121 int nextAngleID() {
122 return ++fAngleID;
123 }
124
caryclark26ad22a2015-10-16 09:03:38 -0700125 int nextCoinID() {
126 return ++fCoinID;
127 }
128
caryclark54359292015-03-26 07:52:43 -0700129 int nextContourID() {
130 return ++fContourID;
131 }
caryclark26ad22a2015-10-16 09:03:38 -0700132
caryclark54359292015-03-26 07:52:43 -0700133 int nextPtTID() {
134 return ++fPtTID;
135 }
136
137 int nextSegmentID() {
138 return ++fSegmentID;
139 }
140
141 int nextSpanID() {
142 return ++fSpanID;
143 }
144#endif
145
Cary Clarkab87d7a2016-10-04 10:01:04 -0400146 SkOpPhase phase() const {
caryclark54359292015-03-26 07:52:43 -0700147 return fPhase;
148 }
Mike Kleine9f78b42016-11-22 08:57:45 -0500149
caryclark29b25632016-08-25 11:27:17 -0700150 void resetAllocatedOpSpan() {
151 fAllocatedOpSpan = false;
152 }
153
154 void setAllocatedOpSpan() {
155 fAllocatedOpSpan = true;
156 }
caryclark54359292015-03-26 07:52:43 -0700157
caryclark55888e42016-07-18 10:01:36 -0700158 void setCoincidence(SkOpCoincidence* coincidence) {
159 fCoincidence = coincidence;
160 }
Mike Kleine9f78b42016-11-22 08:57:45 -0500161
caryclark624637c2015-05-11 07:21:27 -0700162 void setContourHead(SkOpContourHead* contourHead) {
163 fContourHead = contourHead;
164 }
165
Cary Clarkab87d7a2016-10-04 10:01:04 -0400166 void setPhase(SkOpPhase phase) {
167 if (SkOpPhase::kNoChange == phase) {
168 return;
169 }
caryclark54359292015-03-26 07:52:43 -0700170 SkASSERT(fPhase != phase);
171 fPhase = phase;
172 }
caryclark54359292015-03-26 07:52:43 -0700173
174 // called in very rare cases where angles are sorted incorrectly -- signfies op will fail
175 void setWindingFailed() {
176 fWindingFailed = true;
177 }
178
179 bool windingFailed() const {
180 return fWindingFailed;
181 }
182
183private:
Herb Derbyc3cc5fa2017-03-07 11:11:47 -0500184 SkArenaAlloc* fAllocator;
caryclark54359292015-03-26 07:52:43 -0700185 SkOpCoincidence* fCoincidence;
caryclark624637c2015-05-11 07:21:27 -0700186 SkOpContourHead* fContourHead;
caryclark4e1a4c92015-05-18 12:56:57 -0700187 int fNested;
caryclark29b25632016-08-25 11:27:17 -0700188 bool fAllocatedOpSpan;
caryclark54359292015-03-26 07:52:43 -0700189 bool fWindingFailed;
Cary Clarkab87d7a2016-10-04 10:01:04 -0400190 SkOpPhase fPhase;
caryclark54359292015-03-26 07:52:43 -0700191#ifdef SK_DEBUG
caryclarkd4349722015-07-23 12:40:22 -0700192 const char* fDebugTestName;
Cary Clarkab87d7a2016-10-04 10:01:04 -0400193 void* fDebugReporter;
caryclark54359292015-03-26 07:52:43 -0700194 int fAngleID;
caryclark26ad22a2015-10-16 09:03:38 -0700195 int fCoinID;
caryclark54359292015-03-26 07:52:43 -0700196 int fContourID;
197 int fPtTID;
198 int fSegmentID;
199 int fSpanID;
caryclarkdae6b972016-06-08 04:28:19 -0700200 bool fDebugSkipAssert;
caryclark54359292015-03-26 07:52:43 -0700201#endif
caryclark26ad22a2015-10-16 09:03:38 -0700202#if DEBUG_T_SECT_LOOP_COUNT
203 int fDebugLoopCount[3];
204 SkPath::Verb fDebugWorstVerb[6];
205 SkPoint fDebugWorstPts[24];
206 float fDebugWorstWeight[6];
207#endif
Cary Clarkab87d7a2016-10-04 10:01:04 -0400208#if DEBUG_COIN
209 SkPathOpsDebug::CoinDict fCoinChangedDict;
210 SkPathOpsDebug::CoinDict fCoinVisitedDict;
211 SkPathOpsDebug::CoinDictEntry fCoinDictEntry;
212 const char* fPreviousFuncName;
213#endif
caryclark55888e42016-07-18 10:01:36 -0700214#if DEBUG_COINCIDENCE
215 bool fDebugCheckHealth;
216#endif
caryclark54359292015-03-26 07:52:43 -0700217};
218
caryclarkcdeff812016-07-22 03:34:19 -0700219#ifdef SK_DEBUG
caryclark30b9fdd2016-08-31 14:36:29 -0700220#if DEBUG_COINCIDENCE
caryclarke25a4f62016-07-26 09:26:29 -0700221#define SkOPASSERT(cond) SkASSERT((this->globalState() && \
caryclark30b9fdd2016-08-31 14:36:29 -0700222 (this->globalState()->debugCheckHealth() || \
223 this->globalState()->debugSkipAssert())) || (cond))
224#else
225#define SkOPASSERT(cond) SkASSERT((this->globalState() && \
226 this->globalState()->debugSkipAssert()) || (cond))
227#endif
caryclarka35ab3e2016-10-20 08:32:18 -0700228#define SkOPOBJASSERT(obj, cond) SkASSERT((obj->globalState() && \
229 obj->globalState()->debugSkipAssert()) || (cond))
caryclarkcdeff812016-07-22 03:34:19 -0700230#else
231#define SkOPASSERT(cond)
232#define SkOPOBJASSERT(obj, cond)
233#endif
caryclark15976282016-07-21 05:48:43 -0700234
caryclark@google.comc3f63572013-04-23 12:04:05 +0000235// Use Almost Equal when comparing coordinates. Use epsilon to compare T values.
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000236bool AlmostEqualUlps(float a, float b);
237inline bool AlmostEqualUlps(double a, double b) {
238 return AlmostEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000239}
240
caryclark55888e42016-07-18 10:01:36 -0700241bool AlmostEqualUlpsNoNormalCheck(float a, float b);
242inline bool AlmostEqualUlpsNoNormalCheck(double a, double b) {
243 return AlmostEqualUlpsNoNormalCheck(SkDoubleToScalar(a), SkDoubleToScalar(b));
244}
245
caryclarkb6693002015-12-16 12:28:35 -0800246bool AlmostEqualUlps_Pin(float a, float b);
247inline bool AlmostEqualUlps_Pin(double a, double b) {
248 return AlmostEqualUlps_Pin(SkDoubleToScalar(a), SkDoubleToScalar(b));
249}
250
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000251// Use Almost Dequal when comparing should not special case denormalized values.
252bool AlmostDequalUlps(float a, float b);
commit-bot@chromium.org2db7fe72014-05-07 15:31:40 +0000253bool AlmostDequalUlps(double a, double b);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000254
caryclark@google.com570863f2013-09-16 15:55:01 +0000255bool NotAlmostEqualUlps(float a, float b);
256inline bool NotAlmostEqualUlps(double a, double b) {
257 return NotAlmostEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
258}
259
caryclarkb6693002015-12-16 12:28:35 -0800260bool NotAlmostEqualUlps_Pin(float a, float b);
261inline bool NotAlmostEqualUlps_Pin(double a, double b) {
262 return NotAlmostEqualUlps_Pin(SkDoubleToScalar(a), SkDoubleToScalar(b));
263}
264
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000265bool NotAlmostDequalUlps(float a, float b);
266inline bool NotAlmostDequalUlps(double a, double b) {
267 return NotAlmostDequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
268}
269
caryclark@google.com570863f2013-09-16 15:55:01 +0000270// Use Almost Bequal when comparing coordinates in conjunction with between.
271bool AlmostBequalUlps(float a, float b);
272inline bool AlmostBequalUlps(double a, double b) {
273 return AlmostBequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
274}
275
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000276bool AlmostPequalUlps(float a, float b);
277inline bool AlmostPequalUlps(double a, double b) {
278 return AlmostPequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
279}
280
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000281bool RoughlyEqualUlps(float a, float b);
282inline bool RoughlyEqualUlps(double a, double b) {
283 return RoughlyEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000284}
285
caryclark@google.com570863f2013-09-16 15:55:01 +0000286bool AlmostLessUlps(float a, float b);
287inline bool AlmostLessUlps(double a, double b) {
288 return AlmostLessUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
289}
290
291bool AlmostLessOrEqualUlps(float a, float b);
292inline bool AlmostLessOrEqualUlps(double a, double b) {
293 return AlmostLessOrEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
294}
295
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000296bool AlmostBetweenUlps(float a, float b, float c);
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000297inline bool AlmostBetweenUlps(double a, double b, double c) {
298 return AlmostBetweenUlps(SkDoubleToScalar(a), SkDoubleToScalar(b), SkDoubleToScalar(c));
299}
300
301int UlpsDistance(float a, float b);
302inline int UlpsDistance(double a, double b) {
303 return UlpsDistance(SkDoubleToScalar(a), SkDoubleToScalar(b));
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000304}
305
caryclark@google.com07393ca2013-04-08 11:47:37 +0000306// FLT_EPSILON == 1.19209290E-07 == 1 / (2 ^ 23)
307// DBL_EPSILON == 2.22045e-16
308const double FLT_EPSILON_CUBED = FLT_EPSILON * FLT_EPSILON * FLT_EPSILON;
309const double FLT_EPSILON_HALF = FLT_EPSILON / 2;
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000310const double FLT_EPSILON_DOUBLE = FLT_EPSILON * 2;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000311const double FLT_EPSILON_ORDERABLE_ERR = FLT_EPSILON * 16;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000312const double FLT_EPSILON_SQUARED = FLT_EPSILON * FLT_EPSILON;
Bruce Dawson759ae562016-11-18 15:08:45 -0500313// Use a compile-time constant for FLT_EPSILON_SQRT to avoid initializers.
314// A 17 digit constant guarantees exact results.
315const double FLT_EPSILON_SQRT = 0.00034526697709225118; // sqrt(FLT_EPSILON);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000316const double FLT_EPSILON_INVERSE = 1 / FLT_EPSILON;
317const double DBL_EPSILON_ERR = DBL_EPSILON * 4; // FIXME: tune -- allow a few bits of error
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000318const double DBL_EPSILON_SUBDIVIDE_ERR = DBL_EPSILON * 16;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000319const double ROUGH_EPSILON = FLT_EPSILON * 64;
320const double MORE_ROUGH_EPSILON = FLT_EPSILON * 256;
caryclarkdac1d172014-06-17 05:15:38 -0700321const double WAY_ROUGH_EPSILON = FLT_EPSILON * 2048;
caryclark54359292015-03-26 07:52:43 -0700322const double BUMP_EPSILON = FLT_EPSILON * 4096;
caryclarkdac1d172014-06-17 05:15:38 -0700323
caryclark55888e42016-07-18 10:01:36 -0700324const SkScalar INVERSE_NUMBER_RANGE = FLT_EPSILON_ORDERABLE_ERR;
325
caryclarkdac1d172014-06-17 05:15:38 -0700326inline bool zero_or_one(double x) {
327 return x == 0 || x == 1;
328}
caryclark@google.com07393ca2013-04-08 11:47:37 +0000329
330inline bool approximately_zero(double x) {
331 return fabs(x) < FLT_EPSILON;
332}
333
334inline bool precisely_zero(double x) {
335 return fabs(x) < DBL_EPSILON_ERR;
336}
337
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000338inline bool precisely_subdivide_zero(double x) {
339 return fabs(x) < DBL_EPSILON_SUBDIVIDE_ERR;
340}
341
caryclark@google.com07393ca2013-04-08 11:47:37 +0000342inline bool approximately_zero(float x) {
343 return fabs(x) < FLT_EPSILON;
344}
345
346inline bool approximately_zero_cubed(double x) {
347 return fabs(x) < FLT_EPSILON_CUBED;
348}
349
350inline bool approximately_zero_half(double x) {
351 return fabs(x) < FLT_EPSILON_HALF;
352}
353
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000354inline bool approximately_zero_double(double x) {
355 return fabs(x) < FLT_EPSILON_DOUBLE;
356}
357
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000358inline bool approximately_zero_orderable(double x) {
359 return fabs(x) < FLT_EPSILON_ORDERABLE_ERR;
360}
361
caryclark@google.com07393ca2013-04-08 11:47:37 +0000362inline bool approximately_zero_squared(double x) {
363 return fabs(x) < FLT_EPSILON_SQUARED;
364}
365
366inline bool approximately_zero_sqrt(double x) {
367 return fabs(x) < FLT_EPSILON_SQRT;
368}
369
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000370inline bool roughly_zero(double x) {
371 return fabs(x) < ROUGH_EPSILON;
372}
373
caryclark@google.com07393ca2013-04-08 11:47:37 +0000374inline bool approximately_zero_inverse(double x) {
375 return fabs(x) > FLT_EPSILON_INVERSE;
376}
377
caryclark@google.com07393ca2013-04-08 11:47:37 +0000378inline bool approximately_zero_when_compared_to(double x, double y) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000379 return x == 0 || fabs(x) < fabs(y * FLT_EPSILON);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000380}
381
caryclark54359292015-03-26 07:52:43 -0700382inline bool precisely_zero_when_compared_to(double x, double y) {
383 return x == 0 || fabs(x) < fabs(y * DBL_EPSILON);
384}
385
caryclark55888e42016-07-18 10:01:36 -0700386inline bool roughly_zero_when_compared_to(double x, double y) {
387 return x == 0 || fabs(x) < fabs(y * ROUGH_EPSILON);
388}
389
caryclark@google.com07393ca2013-04-08 11:47:37 +0000390// Use this for comparing Ts in the range of 0 to 1. For general numbers (larger and smaller) use
391// AlmostEqualUlps instead.
392inline bool approximately_equal(double x, double y) {
393 return approximately_zero(x - y);
394}
395
396inline bool precisely_equal(double x, double y) {
397 return precisely_zero(x - y);
398}
399
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000400inline bool precisely_subdivide_equal(double x, double y) {
401 return precisely_subdivide_zero(x - y);
402}
403
caryclark@google.com07393ca2013-04-08 11:47:37 +0000404inline bool approximately_equal_half(double x, double y) {
405 return approximately_zero_half(x - y);
406}
407
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000408inline bool approximately_equal_double(double x, double y) {
409 return approximately_zero_double(x - y);
410}
411
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000412inline bool approximately_equal_orderable(double x, double y) {
413 return approximately_zero_orderable(x - y);
414}
415
caryclark@google.com07393ca2013-04-08 11:47:37 +0000416inline bool approximately_equal_squared(double x, double y) {
417 return approximately_equal(x, y);
418}
419
420inline bool approximately_greater(double x, double y) {
421 return x - FLT_EPSILON >= y;
422}
423
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000424inline bool approximately_greater_double(double x, double y) {
425 return x - FLT_EPSILON_DOUBLE >= y;
426}
427
428inline bool approximately_greater_orderable(double x, double y) {
429 return x - FLT_EPSILON_ORDERABLE_ERR >= y;
430}
431
caryclark@google.com07393ca2013-04-08 11:47:37 +0000432inline bool approximately_greater_or_equal(double x, double y) {
433 return x + FLT_EPSILON > y;
434}
435
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000436inline bool approximately_greater_or_equal_double(double x, double y) {
437 return x + FLT_EPSILON_DOUBLE > y;
438}
439
440inline bool approximately_greater_or_equal_orderable(double x, double y) {
441 return x + FLT_EPSILON_ORDERABLE_ERR > y;
442}
443
caryclark@google.com07393ca2013-04-08 11:47:37 +0000444inline bool approximately_lesser(double x, double y) {
445 return x + FLT_EPSILON <= y;
446}
447
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000448inline bool approximately_lesser_double(double x, double y) {
449 return x + FLT_EPSILON_DOUBLE <= y;
450}
451
452inline bool approximately_lesser_orderable(double x, double y) {
453 return x + FLT_EPSILON_ORDERABLE_ERR <= y;
454}
455
caryclark@google.com07393ca2013-04-08 11:47:37 +0000456inline bool approximately_lesser_or_equal(double x, double y) {
457 return x - FLT_EPSILON < y;
458}
459
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000460inline bool approximately_lesser_or_equal_double(double x, double y) {
461 return x - FLT_EPSILON_DOUBLE < y;
462}
463
464inline bool approximately_lesser_or_equal_orderable(double x, double y) {
465 return x - FLT_EPSILON_ORDERABLE_ERR < y;
466}
467
caryclark@google.com07393ca2013-04-08 11:47:37 +0000468inline bool approximately_greater_than_one(double x) {
469 return x > 1 - FLT_EPSILON;
470}
471
472inline bool precisely_greater_than_one(double x) {
473 return x > 1 - DBL_EPSILON_ERR;
474}
475
476inline bool approximately_less_than_zero(double x) {
477 return x < FLT_EPSILON;
478}
479
480inline bool precisely_less_than_zero(double x) {
481 return x < DBL_EPSILON_ERR;
482}
483
484inline bool approximately_negative(double x) {
485 return x < FLT_EPSILON;
486}
487
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000488inline bool approximately_negative_orderable(double x) {
489 return x < FLT_EPSILON_ORDERABLE_ERR;
490}
491
caryclark@google.com07393ca2013-04-08 11:47:37 +0000492inline bool precisely_negative(double x) {
493 return x < DBL_EPSILON_ERR;
494}
495
496inline bool approximately_one_or_less(double x) {
497 return x < 1 + FLT_EPSILON;
498}
499
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000500inline bool approximately_one_or_less_double(double x) {
501 return x < 1 + FLT_EPSILON_DOUBLE;
502}
503
caryclark@google.com07393ca2013-04-08 11:47:37 +0000504inline bool approximately_positive(double x) {
505 return x > -FLT_EPSILON;
506}
507
508inline bool approximately_positive_squared(double x) {
509 return x > -(FLT_EPSILON_SQUARED);
510}
511
512inline bool approximately_zero_or_more(double x) {
513 return x > -FLT_EPSILON;
514}
515
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000516inline bool approximately_zero_or_more_double(double x) {
517 return x > -FLT_EPSILON_DOUBLE;
518}
519
520inline bool approximately_between_orderable(double a, double b, double c) {
521 return a <= c
522 ? approximately_negative_orderable(a - b) && approximately_negative_orderable(b - c)
523 : approximately_negative_orderable(b - a) && approximately_negative_orderable(c - b);
524}
525
caryclark@google.com07393ca2013-04-08 11:47:37 +0000526inline bool approximately_between(double a, double b, double c) {
527 return a <= c ? approximately_negative(a - b) && approximately_negative(b - c)
528 : approximately_negative(b - a) && approximately_negative(c - b);
529}
530
caryclark@google.com03610322013-04-18 15:58:21 +0000531inline bool precisely_between(double a, double b, double c) {
532 return a <= c ? precisely_negative(a - b) && precisely_negative(b - c)
533 : precisely_negative(b - a) && precisely_negative(c - b);
534}
535
caryclark@google.com07393ca2013-04-08 11:47:37 +0000536// returns true if (a <= b <= c) || (a >= b >= c)
537inline bool between(double a, double b, double c) {
caryclark54359292015-03-26 07:52:43 -0700538 SkASSERT(((a <= b && b <= c) || (a >= b && b >= c)) == ((a - b) * (c - b) <= 0)
539 || (precisely_zero(a) && precisely_zero(b) && precisely_zero(c)));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000540 return (a - b) * (c - b) <= 0;
541}
542
caryclarkdac1d172014-06-17 05:15:38 -0700543inline bool roughly_equal(double x, double y) {
544 return fabs(x - y) < ROUGH_EPSILON;
545}
546
caryclark54359292015-03-26 07:52:43 -0700547inline bool roughly_negative(double x) {
548 return x < ROUGH_EPSILON;
549}
550
551inline bool roughly_between(double a, double b, double c) {
552 return a <= c ? roughly_negative(a - b) && roughly_negative(b - c)
553 : roughly_negative(b - a) && roughly_negative(c - b);
554}
555
caryclark@google.com07393ca2013-04-08 11:47:37 +0000556inline bool more_roughly_equal(double x, double y) {
557 return fabs(x - y) < MORE_ROUGH_EPSILON;
558}
559
caryclark@google.com07393ca2013-04-08 11:47:37 +0000560struct SkDPoint;
561struct SkDVector;
562struct SkDLine;
563struct SkDQuad;
caryclark1049f122015-04-20 08:31:59 -0700564struct SkDConic;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000565struct SkDCubic;
566struct SkDRect;
567
reed@google.com277c3f82013-05-31 15:17:50 +0000568inline SkPath::Verb SkPathOpsPointsToVerb(int points) {
569 int verb = (1 << points) >> 1;
570#ifdef SK_DEBUG
571 switch (points) {
572 case 0: SkASSERT(SkPath::kMove_Verb == verb); break;
573 case 1: SkASSERT(SkPath::kLine_Verb == verb); break;
574 case 2: SkASSERT(SkPath::kQuad_Verb == verb); break;
575 case 3: SkASSERT(SkPath::kCubic_Verb == verb); break;
mtklein@google.com330313a2013-08-22 15:37:26 +0000576 default: SkDEBUGFAIL("should not be here");
reed@google.com277c3f82013-05-31 15:17:50 +0000577 }
578#endif
579 return (SkPath::Verb)verb;
580}
581
582inline int SkPathOpsVerbToPoints(SkPath::Verb verb) {
caryclark1049f122015-04-20 08:31:59 -0700583 int points = (int) verb - (((int) verb + 1) >> 2);
reed@google.com277c3f82013-05-31 15:17:50 +0000584#ifdef SK_DEBUG
585 switch (verb) {
586 case SkPath::kLine_Verb: SkASSERT(1 == points); break;
587 case SkPath::kQuad_Verb: SkASSERT(2 == points); break;
caryclark1049f122015-04-20 08:31:59 -0700588 case SkPath::kConic_Verb: SkASSERT(2 == points); break;
reed@google.com277c3f82013-05-31 15:17:50 +0000589 case SkPath::kCubic_Verb: SkASSERT(3 == points); break;
mtklein@google.com330313a2013-08-22 15:37:26 +0000590 default: SkDEBUGFAIL("should not get here");
reed@google.com277c3f82013-05-31 15:17:50 +0000591 }
592#endif
593 return points;
594}
595
caryclark@google.com07393ca2013-04-08 11:47:37 +0000596inline double SkDInterp(double A, double B, double t) {
597 return A + (B - A) * t;
598}
599
600double SkDCubeRoot(double x);
601
602/* Returns -1 if negative, 0 if zero, 1 if positive
603*/
604inline int SkDSign(double x) {
605 return (x > 0) - (x < 0);
606}
607
608/* Returns 0 if negative, 1 if zero, 2 if positive
609*/
610inline int SKDSide(double x) {
611 return (x > 0) + (x >= 0);
612}
613
614/* Returns 1 if negative, 2 if zero, 4 if positive
615*/
616inline int SkDSideBit(double x) {
617 return 1 << SKDSide(x);
618}
619
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000620inline double SkPinT(double t) {
621 return precisely_less_than_zero(t) ? 0 : precisely_greater_than_one(t) ? 1 : t;
622}
623
caryclark@google.com07393ca2013-04-08 11:47:37 +0000624#endif