SkPathOpsTypes.h revision 65f553182ab7069378ef863d30094d0327f178d0
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
19enum SkPathOpsMask {
20    kWinding_PathOpsMask = -1,
21    kNo_PathOpsMask = 0,
22    kEvenOdd_PathOpsMask = 1
23};
24
25// Use Almost Equal when comparing coordinates. Use epsilon to compare T values.
26bool AlmostEqualUlps(float a, float b);
27inline bool AlmostEqualUlps(double a, double b) {
28    return AlmostEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
29}
30
31// Use Almost Dequal when comparing should not special case denormalized values.
32bool AlmostDequalUlps(float a, float b);
33bool AlmostDequalUlps(double a, double b);
34
35bool NotAlmostEqualUlps(float a, float b);
36inline bool NotAlmostEqualUlps(double a, double b) {
37    return NotAlmostEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
38}
39
40bool NotAlmostDequalUlps(float a, float b);
41inline bool NotAlmostDequalUlps(double a, double b) {
42    return NotAlmostDequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
43}
44
45// Use Almost Bequal when comparing coordinates in conjunction with between.
46bool AlmostBequalUlps(float a, float b);
47inline bool AlmostBequalUlps(double a, double b) {
48    return AlmostBequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
49}
50
51bool AlmostPequalUlps(float a, float b);
52inline bool AlmostPequalUlps(double a, double b) {
53    return AlmostPequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
54}
55
56bool RoughlyEqualUlps(float a, float b);
57inline bool RoughlyEqualUlps(double a, double b) {
58    return RoughlyEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
59}
60
61bool AlmostLessUlps(float a, float b);
62inline bool AlmostLessUlps(double a, double b) {
63    return AlmostLessUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
64}
65
66bool AlmostLessOrEqualUlps(float a, float b);
67inline bool AlmostLessOrEqualUlps(double a, double b) {
68    return AlmostLessOrEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
69}
70
71bool AlmostBetweenUlps(float a, float b, float c);
72inline bool AlmostBetweenUlps(double a, double b, double c) {
73    return AlmostBetweenUlps(SkDoubleToScalar(a), SkDoubleToScalar(b), SkDoubleToScalar(c));
74}
75
76int UlpsDistance(float a, float b);
77inline int UlpsDistance(double a, double b) {
78    return UlpsDistance(SkDoubleToScalar(a), SkDoubleToScalar(b));
79}
80
81// FLT_EPSILON == 1.19209290E-07 == 1 / (2 ^ 23)
82// DBL_EPSILON == 2.22045e-16
83const double FLT_EPSILON_CUBED = FLT_EPSILON * FLT_EPSILON * FLT_EPSILON;
84const double FLT_EPSILON_HALF = FLT_EPSILON / 2;
85const double FLT_EPSILON_DOUBLE = FLT_EPSILON * 2;
86const double FLT_EPSILON_ORDERABLE_ERR = FLT_EPSILON * 16;
87const double FLT_EPSILON_SQUARED = FLT_EPSILON * FLT_EPSILON;
88const double FLT_EPSILON_SQRT = sqrt(FLT_EPSILON);
89const double FLT_EPSILON_INVERSE = 1 / FLT_EPSILON;
90const double DBL_EPSILON_ERR = DBL_EPSILON * 4;  // FIXME: tune -- allow a few bits of error
91const double DBL_EPSILON_SUBDIVIDE_ERR = DBL_EPSILON * 16;
92const double ROUGH_EPSILON = FLT_EPSILON * 64;
93const double MORE_ROUGH_EPSILON = FLT_EPSILON * 256;
94const double WAY_ROUGH_EPSILON = FLT_EPSILON * 2048;
95
96inline bool zero_or_one(double x) {
97    return x == 0 || x == 1;
98}
99
100inline bool approximately_zero(double x) {
101    return fabs(x) < FLT_EPSILON;
102}
103
104inline bool precisely_zero(double x) {
105    return fabs(x) < DBL_EPSILON_ERR;
106}
107
108inline bool precisely_subdivide_zero(double x) {
109    return fabs(x) < DBL_EPSILON_SUBDIVIDE_ERR;
110}
111
112inline bool approximately_zero(float x) {
113    return fabs(x) < FLT_EPSILON;
114}
115
116inline bool approximately_zero_cubed(double x) {
117    return fabs(x) < FLT_EPSILON_CUBED;
118}
119
120inline bool approximately_zero_half(double x) {
121    return fabs(x) < FLT_EPSILON_HALF;
122}
123
124inline bool approximately_zero_double(double x) {
125    return fabs(x) < FLT_EPSILON_DOUBLE;
126}
127
128inline bool approximately_zero_orderable(double x) {
129    return fabs(x) < FLT_EPSILON_ORDERABLE_ERR;
130}
131
132inline bool approximately_zero_squared(double x) {
133    return fabs(x) < FLT_EPSILON_SQUARED;
134}
135
136inline bool approximately_zero_sqrt(double x) {
137    return fabs(x) < FLT_EPSILON_SQRT;
138}
139
140inline bool roughly_zero(double x) {
141    return fabs(x) < ROUGH_EPSILON;
142}
143
144#if 0  // unused for now
145inline bool way_roughly_zero(double x) {
146    return fabs(x) < WAY_ROUGH_EPSILON;
147}
148#endif
149
150inline bool approximately_zero_inverse(double x) {
151    return fabs(x) > FLT_EPSILON_INVERSE;
152}
153
154// OPTIMIZATION: if called multiple times with the same denom, we want to pass 1/y instead
155inline bool approximately_zero_when_compared_to(double x, double y) {
156    return x == 0 || fabs(x) < fabs(y * FLT_EPSILON);
157}
158
159// Use this for comparing Ts in the range of 0 to 1. For general numbers (larger and smaller) use
160// AlmostEqualUlps instead.
161inline bool approximately_equal(double x, double y) {
162    return approximately_zero(x - y);
163}
164
165inline bool precisely_equal(double x, double y) {
166    return precisely_zero(x - y);
167}
168
169inline bool precisely_subdivide_equal(double x, double y) {
170    return precisely_subdivide_zero(x - y);
171}
172
173inline bool approximately_equal_half(double x, double y) {
174    return approximately_zero_half(x - y);
175}
176
177inline bool approximately_equal_double(double x, double y) {
178    return approximately_zero_double(x - y);
179}
180
181inline bool approximately_equal_orderable(double x, double y) {
182    return approximately_zero_orderable(x - y);
183}
184
185inline bool approximately_equal_squared(double x, double y) {
186    return approximately_equal(x, y);
187}
188
189inline bool approximately_greater(double x, double y) {
190    return x - FLT_EPSILON >= y;
191}
192
193inline bool approximately_greater_double(double x, double y) {
194    return x - FLT_EPSILON_DOUBLE >= y;
195}
196
197inline bool approximately_greater_orderable(double x, double y) {
198    return x - FLT_EPSILON_ORDERABLE_ERR >= y;
199}
200
201inline bool approximately_greater_or_equal(double x, double y) {
202    return x + FLT_EPSILON > y;
203}
204
205inline bool approximately_greater_or_equal_double(double x, double y) {
206    return x + FLT_EPSILON_DOUBLE > y;
207}
208
209inline bool approximately_greater_or_equal_orderable(double x, double y) {
210    return x + FLT_EPSILON_ORDERABLE_ERR > y;
211}
212
213inline bool approximately_lesser(double x, double y) {
214    return x + FLT_EPSILON <= y;
215}
216
217inline bool approximately_lesser_double(double x, double y) {
218    return x + FLT_EPSILON_DOUBLE <= y;
219}
220
221inline bool approximately_lesser_orderable(double x, double y) {
222    return x + FLT_EPSILON_ORDERABLE_ERR <= y;
223}
224
225inline bool approximately_lesser_or_equal(double x, double y) {
226    return x - FLT_EPSILON < y;
227}
228
229inline bool approximately_lesser_or_equal_double(double x, double y) {
230    return x - FLT_EPSILON_DOUBLE < y;
231}
232
233inline bool approximately_lesser_or_equal_orderable(double x, double y) {
234    return x - FLT_EPSILON_ORDERABLE_ERR < y;
235}
236
237inline bool approximately_greater_than_one(double x) {
238    return x > 1 - FLT_EPSILON;
239}
240
241inline bool precisely_greater_than_one(double x) {
242    return x > 1 - DBL_EPSILON_ERR;
243}
244
245inline bool approximately_less_than_zero(double x) {
246    return x < FLT_EPSILON;
247}
248
249inline bool precisely_less_than_zero(double x) {
250    return x < DBL_EPSILON_ERR;
251}
252
253inline bool approximately_negative(double x) {
254    return x < FLT_EPSILON;
255}
256
257inline bool approximately_negative_orderable(double x) {
258    return x < FLT_EPSILON_ORDERABLE_ERR;
259}
260
261inline bool precisely_negative(double x) {
262    return x < DBL_EPSILON_ERR;
263}
264
265inline bool approximately_one_or_less(double x) {
266    return x < 1 + FLT_EPSILON;
267}
268
269inline bool approximately_one_or_less_double(double x) {
270    return x < 1 + FLT_EPSILON_DOUBLE;
271}
272
273inline bool approximately_positive(double x) {
274    return x > -FLT_EPSILON;
275}
276
277inline bool approximately_positive_squared(double x) {
278    return x > -(FLT_EPSILON_SQUARED);
279}
280
281inline bool approximately_zero_or_more(double x) {
282    return x > -FLT_EPSILON;
283}
284
285inline bool approximately_zero_or_more_double(double x) {
286    return x > -FLT_EPSILON_DOUBLE;
287}
288
289inline bool approximately_between_orderable(double a, double b, double c) {
290    return a <= c
291            ? approximately_negative_orderable(a - b) && approximately_negative_orderable(b - c)
292            : approximately_negative_orderable(b - a) && approximately_negative_orderable(c - b);
293}
294
295inline bool approximately_between(double a, double b, double c) {
296    return a <= c ? approximately_negative(a - b) && approximately_negative(b - c)
297            : approximately_negative(b - a) && approximately_negative(c - b);
298}
299
300inline bool precisely_between(double a, double b, double c) {
301    return a <= c ? precisely_negative(a - b) && precisely_negative(b - c)
302            : precisely_negative(b - a) && precisely_negative(c - b);
303}
304
305// returns true if (a <= b <= c) || (a >= b >= c)
306inline bool between(double a, double b, double c) {
307    SkASSERT(((a <= b && b <= c) || (a >= b && b >= c)) == ((a - b) * (c - b) <= 0));
308    return (a - b) * (c - b) <= 0;
309}
310
311inline bool roughly_equal(double x, double y) {
312    return fabs(x - y) < ROUGH_EPSILON;
313}
314
315inline bool more_roughly_equal(double x, double y) {
316    return fabs(x - y) < MORE_ROUGH_EPSILON;
317}
318
319inline bool way_roughly_equal(double x, double y) {
320    return fabs(x - y) < WAY_ROUGH_EPSILON;
321}
322
323struct SkDPoint;
324struct SkDVector;
325struct SkDLine;
326struct SkDQuad;
327struct SkDTriangle;
328struct SkDCubic;
329struct SkDRect;
330
331inline SkPath::Verb SkPathOpsPointsToVerb(int points) {
332    int verb = (1 << points) >> 1;
333#ifdef SK_DEBUG
334    switch (points) {
335        case 0: SkASSERT(SkPath::kMove_Verb == verb); break;
336        case 1: SkASSERT(SkPath::kLine_Verb == verb); break;
337        case 2: SkASSERT(SkPath::kQuad_Verb == verb); break;
338        case 3: SkASSERT(SkPath::kCubic_Verb == verb); break;
339        default: SkDEBUGFAIL("should not be here");
340    }
341#endif
342    return (SkPath::Verb)verb;
343}
344
345inline int SkPathOpsVerbToPoints(SkPath::Verb verb) {
346    int points = (int) verb - ((int) verb >> 2);
347#ifdef SK_DEBUG
348    switch (verb) {
349        case SkPath::kLine_Verb: SkASSERT(1 == points); break;
350        case SkPath::kQuad_Verb: SkASSERT(2 == points); break;
351        case SkPath::kCubic_Verb: SkASSERT(3 == points); break;
352        default: SkDEBUGFAIL("should not get here");
353    }
354#endif
355    return points;
356}
357
358inline double SkDInterp(double A, double B, double t) {
359    return A + (B - A) * t;
360}
361
362double SkDCubeRoot(double x);
363
364/* Returns -1 if negative, 0 if zero, 1 if positive
365*/
366inline int SkDSign(double x) {
367    return (x > 0) - (x < 0);
368}
369
370/* Returns 0 if negative, 1 if zero, 2 if positive
371*/
372inline int SKDSide(double x) {
373    return (x > 0) + (x >= 0);
374}
375
376/* Returns 1 if negative, 2 if zero, 4 if positive
377*/
378inline int SkDSideBit(double x) {
379    return 1 << SKDSide(x);
380}
381
382inline double SkPinT(double t) {
383    return precisely_less_than_zero(t) ? 0 : precisely_greater_than_one(t) ? 1 : t;
384}
385
386#endif
387