Line data Source code
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 :
12 : #include "SkFloatingPoint.h"
13 : #include "SkPath.h"
14 : #include "SkPathOps.h"
15 : #include "SkPathOpsDebug.h"
16 : #include "SkSafe_math.h" // for fabs, sqrt
17 : #include "SkScalar.h"
18 :
19 : enum SkPathOpsMask {
20 : kWinding_PathOpsMask = -1,
21 : kNo_PathOpsMask = 0,
22 : kEvenOdd_PathOpsMask = 1
23 : };
24 :
25 : class SkArenaAlloc;
26 : class SkOpCoincidence;
27 : class SkOpContour;
28 : class SkOpContourHead;
29 : class SkIntersections;
30 : class SkIntersectionHelper;
31 :
32 : enum class SkOpPhase : char {
33 : kNoChange,
34 : kIntersecting,
35 : kWalking,
36 : kFixWinding,
37 : };
38 :
39 : class SkOpGlobalState {
40 : public:
41 : SkOpGlobalState(SkOpContourHead* head,
42 : SkArenaAlloc* allocator SkDEBUGPARAMS(bool debugSkipAssert)
43 : SkDEBUGPARAMS(const char* testName));
44 :
45 : enum {
46 : kMaxWindingTries = 10
47 : };
48 :
49 0 : bool allocatedOpSpan() const {
50 0 : return fAllocatedOpSpan;
51 : }
52 :
53 0 : SkArenaAlloc* allocator() {
54 0 : return fAllocator;
55 : }
56 :
57 0 : void bumpNested() {
58 0 : ++fNested;
59 0 : }
60 :
61 0 : void clearNested() {
62 0 : fNested = 0;
63 0 : }
64 :
65 0 : SkOpCoincidence* coincidence() {
66 0 : return fCoincidence;
67 : }
68 :
69 0 : SkOpContourHead* contourHead() {
70 0 : return fContourHead;
71 : }
72 :
73 : #ifdef SK_DEBUG
74 : const class SkOpAngle* debugAngle(int id) const;
75 : const SkOpCoincidence* debugCoincidence() const;
76 : SkOpContour* debugContour(int id) const;
77 : const class SkOpPtT* debugPtT(int id) const;
78 : #endif
79 :
80 : static bool DebugRunFail();
81 :
82 : #ifdef SK_DEBUG
83 : const class SkOpSegment* debugSegment(int id) const;
84 0 : bool debugSkipAssert() const { return fDebugSkipAssert; }
85 : const class SkOpSpanBase* debugSpan(int id) const;
86 : const char* debugTestName() const { return fDebugTestName; }
87 : #endif
88 :
89 : #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 :
97 : #if DEBUG_COINCIDENCE
98 : void debugSetCheckHealth(bool check) { fDebugCheckHealth = check; }
99 : bool debugCheckHealth() const { return fDebugCheckHealth; }
100 : #endif
101 :
102 : #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 :
116 0 : int nested() const {
117 0 : return fNested;
118 : }
119 :
120 : #ifdef SK_DEBUG
121 0 : int nextAngleID() {
122 0 : return ++fAngleID;
123 : }
124 :
125 : int nextCoinID() {
126 : return ++fCoinID;
127 : }
128 :
129 0 : int nextContourID() {
130 0 : return ++fContourID;
131 : }
132 :
133 0 : int nextPtTID() {
134 0 : return ++fPtTID;
135 : }
136 :
137 0 : int nextSegmentID() {
138 0 : return ++fSegmentID;
139 : }
140 :
141 0 : int nextSpanID() {
142 0 : return ++fSpanID;
143 : }
144 : #endif
145 :
146 0 : SkOpPhase phase() const {
147 0 : return fPhase;
148 : }
149 :
150 0 : void resetAllocatedOpSpan() {
151 0 : fAllocatedOpSpan = false;
152 0 : }
153 :
154 0 : void setAllocatedOpSpan() {
155 0 : fAllocatedOpSpan = true;
156 0 : }
157 :
158 0 : void setCoincidence(SkOpCoincidence* coincidence) {
159 0 : fCoincidence = coincidence;
160 0 : }
161 :
162 0 : void setContourHead(SkOpContourHead* contourHead) {
163 0 : fContourHead = contourHead;
164 0 : }
165 :
166 0 : void setPhase(SkOpPhase phase) {
167 0 : if (SkOpPhase::kNoChange == phase) {
168 0 : return;
169 : }
170 0 : SkASSERT(fPhase != phase);
171 0 : fPhase = phase;
172 : }
173 :
174 : // called in very rare cases where angles are sorted incorrectly -- signfies op will fail
175 0 : void setWindingFailed() {
176 0 : fWindingFailed = true;
177 0 : }
178 :
179 : bool windingFailed() const {
180 : return fWindingFailed;
181 : }
182 :
183 : private:
184 : SkArenaAlloc* fAllocator;
185 : SkOpCoincidence* fCoincidence;
186 : SkOpContourHead* fContourHead;
187 : int fNested;
188 : bool fAllocatedOpSpan;
189 : bool fWindingFailed;
190 : SkOpPhase fPhase;
191 : #ifdef SK_DEBUG
192 : const char* fDebugTestName;
193 : void* fDebugReporter;
194 : int fAngleID;
195 : int fCoinID;
196 : int fContourID;
197 : int fPtTID;
198 : int fSegmentID;
199 : int fSpanID;
200 : bool fDebugSkipAssert;
201 : #endif
202 : #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
208 : #if DEBUG_COIN
209 : SkPathOpsDebug::CoinDict fCoinChangedDict;
210 : SkPathOpsDebug::CoinDict fCoinVisitedDict;
211 : SkPathOpsDebug::CoinDictEntry fCoinDictEntry;
212 : const char* fPreviousFuncName;
213 : #endif
214 : #if DEBUG_COINCIDENCE
215 : bool fDebugCheckHealth;
216 : #endif
217 : };
218 :
219 : #ifdef SK_DEBUG
220 : #if DEBUG_COINCIDENCE
221 : #define SkOPASSERT(cond) SkASSERT((this->globalState() && \
222 : (this->globalState()->debugCheckHealth() || \
223 : this->globalState()->debugSkipAssert())) || (cond))
224 : #else
225 : #define SkOPASSERT(cond) SkASSERT((this->globalState() && \
226 : this->globalState()->debugSkipAssert()) || (cond))
227 : #endif
228 : #define SkOPOBJASSERT(obj, cond) SkASSERT((obj->globalState() && \
229 : obj->globalState()->debugSkipAssert()) || (cond))
230 : #else
231 : #define SkOPASSERT(cond)
232 : #define SkOPOBJASSERT(obj, cond)
233 : #endif
234 :
235 : // Use Almost Equal when comparing coordinates. Use epsilon to compare T values.
236 : bool AlmostEqualUlps(float a, float b);
237 0 : inline bool AlmostEqualUlps(double a, double b) {
238 0 : return AlmostEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
239 : }
240 :
241 : bool AlmostEqualUlpsNoNormalCheck(float a, float b);
242 0 : inline bool AlmostEqualUlpsNoNormalCheck(double a, double b) {
243 0 : return AlmostEqualUlpsNoNormalCheck(SkDoubleToScalar(a), SkDoubleToScalar(b));
244 : }
245 :
246 : bool AlmostEqualUlps_Pin(float a, float b);
247 0 : inline bool AlmostEqualUlps_Pin(double a, double b) {
248 0 : return AlmostEqualUlps_Pin(SkDoubleToScalar(a), SkDoubleToScalar(b));
249 : }
250 :
251 : // Use Almost Dequal when comparing should not special case denormalized values.
252 : bool AlmostDequalUlps(float a, float b);
253 : bool AlmostDequalUlps(double a, double b);
254 :
255 : bool NotAlmostEqualUlps(float a, float b);
256 0 : inline bool NotAlmostEqualUlps(double a, double b) {
257 0 : return NotAlmostEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
258 : }
259 :
260 : bool NotAlmostEqualUlps_Pin(float a, float b);
261 0 : inline bool NotAlmostEqualUlps_Pin(double a, double b) {
262 0 : return NotAlmostEqualUlps_Pin(SkDoubleToScalar(a), SkDoubleToScalar(b));
263 : }
264 :
265 : bool NotAlmostDequalUlps(float a, float b);
266 0 : inline bool NotAlmostDequalUlps(double a, double b) {
267 0 : return NotAlmostDequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
268 : }
269 :
270 : // Use Almost Bequal when comparing coordinates in conjunction with between.
271 : bool AlmostBequalUlps(float a, float b);
272 0 : inline bool AlmostBequalUlps(double a, double b) {
273 0 : return AlmostBequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
274 : }
275 :
276 : bool AlmostPequalUlps(float a, float b);
277 0 : inline bool AlmostPequalUlps(double a, double b) {
278 0 : return AlmostPequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
279 : }
280 :
281 : bool RoughlyEqualUlps(float a, float b);
282 0 : inline bool RoughlyEqualUlps(double a, double b) {
283 0 : return RoughlyEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
284 : }
285 :
286 : bool AlmostLessUlps(float a, float b);
287 : inline bool AlmostLessUlps(double a, double b) {
288 : return AlmostLessUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
289 : }
290 :
291 : bool AlmostLessOrEqualUlps(float a, float b);
292 : inline bool AlmostLessOrEqualUlps(double a, double b) {
293 : return AlmostLessOrEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
294 : }
295 :
296 : bool AlmostBetweenUlps(float a, float b, float c);
297 0 : inline bool AlmostBetweenUlps(double a, double b, double c) {
298 0 : return AlmostBetweenUlps(SkDoubleToScalar(a), SkDoubleToScalar(b), SkDoubleToScalar(c));
299 : }
300 :
301 : int UlpsDistance(float a, float b);
302 : inline int UlpsDistance(double a, double b) {
303 : return UlpsDistance(SkDoubleToScalar(a), SkDoubleToScalar(b));
304 : }
305 :
306 : // FLT_EPSILON == 1.19209290E-07 == 1 / (2 ^ 23)
307 : // DBL_EPSILON == 2.22045e-16
308 : const double FLT_EPSILON_CUBED = FLT_EPSILON * FLT_EPSILON * FLT_EPSILON;
309 : const double FLT_EPSILON_HALF = FLT_EPSILON / 2;
310 : const double FLT_EPSILON_DOUBLE = FLT_EPSILON * 2;
311 : const double FLT_EPSILON_ORDERABLE_ERR = FLT_EPSILON * 16;
312 : const double FLT_EPSILON_SQUARED = FLT_EPSILON * FLT_EPSILON;
313 : // Use a compile-time constant for FLT_EPSILON_SQRT to avoid initializers.
314 : // A 17 digit constant guarantees exact results.
315 : const double FLT_EPSILON_SQRT = 0.00034526697709225118; // sqrt(FLT_EPSILON);
316 : const double FLT_EPSILON_INVERSE = 1 / FLT_EPSILON;
317 : const double DBL_EPSILON_ERR = DBL_EPSILON * 4; // FIXME: tune -- allow a few bits of error
318 : const double DBL_EPSILON_SUBDIVIDE_ERR = DBL_EPSILON * 16;
319 : const double ROUGH_EPSILON = FLT_EPSILON * 64;
320 : const double MORE_ROUGH_EPSILON = FLT_EPSILON * 256;
321 : const double WAY_ROUGH_EPSILON = FLT_EPSILON * 2048;
322 : const double BUMP_EPSILON = FLT_EPSILON * 4096;
323 :
324 : const SkScalar INVERSE_NUMBER_RANGE = FLT_EPSILON_ORDERABLE_ERR;
325 :
326 0 : inline bool zero_or_one(double x) {
327 0 : return x == 0 || x == 1;
328 : }
329 :
330 101 : inline bool approximately_zero(double x) {
331 101 : return fabs(x) < FLT_EPSILON;
332 : }
333 :
334 0 : inline bool precisely_zero(double x) {
335 0 : return fabs(x) < DBL_EPSILON_ERR;
336 : }
337 :
338 : inline bool precisely_subdivide_zero(double x) {
339 : return fabs(x) < DBL_EPSILON_SUBDIVIDE_ERR;
340 : }
341 :
342 : inline bool approximately_zero(float x) {
343 : return fabs(x) < FLT_EPSILON;
344 : }
345 :
346 2 : inline bool approximately_zero_cubed(double x) {
347 2 : return fabs(x) < FLT_EPSILON_CUBED;
348 : }
349 :
350 0 : inline bool approximately_zero_half(double x) {
351 0 : return fabs(x) < FLT_EPSILON_HALF;
352 : }
353 :
354 : inline bool approximately_zero_double(double x) {
355 : return fabs(x) < FLT_EPSILON_DOUBLE;
356 : }
357 :
358 0 : inline bool approximately_zero_orderable(double x) {
359 0 : return fabs(x) < FLT_EPSILON_ORDERABLE_ERR;
360 : }
361 :
362 : inline bool approximately_zero_squared(double x) {
363 : return fabs(x) < FLT_EPSILON_SQUARED;
364 : }
365 :
366 : inline bool approximately_zero_sqrt(double x) {
367 : return fabs(x) < FLT_EPSILON_SQRT;
368 : }
369 :
370 : inline bool roughly_zero(double x) {
371 : return fabs(x) < ROUGH_EPSILON;
372 : }
373 :
374 0 : inline bool approximately_zero_inverse(double x) {
375 0 : return fabs(x) > FLT_EPSILON_INVERSE;
376 : }
377 :
378 39 : inline bool approximately_zero_when_compared_to(double x, double y) {
379 39 : return x == 0 || fabs(x) < fabs(y * FLT_EPSILON);
380 : }
381 :
382 0 : inline bool precisely_zero_when_compared_to(double x, double y) {
383 0 : return x == 0 || fabs(x) < fabs(y * DBL_EPSILON);
384 : }
385 :
386 0 : inline bool roughly_zero_when_compared_to(double x, double y) {
387 0 : return x == 0 || fabs(x) < fabs(y * ROUGH_EPSILON);
388 : }
389 :
390 : // Use this for comparing Ts in the range of 0 to 1. For general numbers (larger and smaller) use
391 : // AlmostEqualUlps instead.
392 33 : inline bool approximately_equal(double x, double y) {
393 33 : return approximately_zero(x - y);
394 : }
395 :
396 0 : inline bool precisely_equal(double x, double y) {
397 0 : return precisely_zero(x - y);
398 : }
399 :
400 : inline bool precisely_subdivide_equal(double x, double y) {
401 : return precisely_subdivide_zero(x - y);
402 : }
403 :
404 0 : inline bool approximately_equal_half(double x, double y) {
405 0 : return approximately_zero_half(x - y);
406 : }
407 :
408 : inline bool approximately_equal_double(double x, double y) {
409 : return approximately_zero_double(x - y);
410 : }
411 :
412 0 : inline bool approximately_equal_orderable(double x, double y) {
413 0 : return approximately_zero_orderable(x - y);
414 : }
415 :
416 : inline bool approximately_equal_squared(double x, double y) {
417 : return approximately_equal(x, y);
418 : }
419 :
420 : inline bool approximately_greater(double x, double y) {
421 : return x - FLT_EPSILON >= y;
422 : }
423 :
424 : inline bool approximately_greater_double(double x, double y) {
425 : return x - FLT_EPSILON_DOUBLE >= y;
426 : }
427 :
428 : inline bool approximately_greater_orderable(double x, double y) {
429 : return x - FLT_EPSILON_ORDERABLE_ERR >= y;
430 : }
431 :
432 : inline bool approximately_greater_or_equal(double x, double y) {
433 : return x + FLT_EPSILON > y;
434 : }
435 :
436 : inline bool approximately_greater_or_equal_double(double x, double y) {
437 : return x + FLT_EPSILON_DOUBLE > y;
438 : }
439 :
440 : inline bool approximately_greater_or_equal_orderable(double x, double y) {
441 : return x + FLT_EPSILON_ORDERABLE_ERR > y;
442 : }
443 :
444 : inline bool approximately_lesser(double x, double y) {
445 : return x + FLT_EPSILON <= y;
446 : }
447 :
448 : inline bool approximately_lesser_double(double x, double y) {
449 : return x + FLT_EPSILON_DOUBLE <= y;
450 : }
451 :
452 : inline bool approximately_lesser_orderable(double x, double y) {
453 : return x + FLT_EPSILON_ORDERABLE_ERR <= y;
454 : }
455 :
456 : inline bool approximately_lesser_or_equal(double x, double y) {
457 : return x - FLT_EPSILON < y;
458 : }
459 :
460 : inline bool approximately_lesser_or_equal_double(double x, double y) {
461 : return x - FLT_EPSILON_DOUBLE < y;
462 : }
463 :
464 : inline bool approximately_lesser_or_equal_orderable(double x, double y) {
465 : return x - FLT_EPSILON_ORDERABLE_ERR < y;
466 : }
467 :
468 30 : inline bool approximately_greater_than_one(double x) {
469 30 : return x > 1 - FLT_EPSILON;
470 : }
471 :
472 0 : inline bool precisely_greater_than_one(double x) {
473 0 : return x > 1 - DBL_EPSILON_ERR;
474 : }
475 :
476 33 : inline bool approximately_less_than_zero(double x) {
477 33 : return x < FLT_EPSILON;
478 : }
479 :
480 0 : inline bool precisely_less_than_zero(double x) {
481 0 : return x < DBL_EPSILON_ERR;
482 : }
483 :
484 0 : inline bool approximately_negative(double x) {
485 0 : return x < FLT_EPSILON;
486 : }
487 :
488 0 : inline bool approximately_negative_orderable(double x) {
489 0 : return x < FLT_EPSILON_ORDERABLE_ERR;
490 : }
491 :
492 0 : inline bool precisely_negative(double x) {
493 0 : return x < DBL_EPSILON_ERR;
494 : }
495 :
496 162 : inline bool approximately_one_or_less(double x) {
497 162 : return x < 1 + FLT_EPSILON;
498 : }
499 :
500 0 : inline bool approximately_one_or_less_double(double x) {
501 0 : return x < 1 + FLT_EPSILON_DOUBLE;
502 : }
503 :
504 : inline bool approximately_positive(double x) {
505 : return x > -FLT_EPSILON;
506 : }
507 :
508 : inline bool approximately_positive_squared(double x) {
509 : return x > -(FLT_EPSILON_SQUARED);
510 : }
511 :
512 194 : inline bool approximately_zero_or_more(double x) {
513 194 : return x > -FLT_EPSILON;
514 : }
515 :
516 0 : inline bool approximately_zero_or_more_double(double x) {
517 0 : return x > -FLT_EPSILON_DOUBLE;
518 : }
519 :
520 0 : inline bool approximately_between_orderable(double a, double b, double c) {
521 : return a <= c
522 0 : ? approximately_negative_orderable(a - b) && approximately_negative_orderable(b - c)
523 0 : : approximately_negative_orderable(b - a) && approximately_negative_orderable(c - b);
524 : }
525 :
526 0 : inline bool approximately_between(double a, double b, double c) {
527 0 : return a <= c ? approximately_negative(a - b) && approximately_negative(b - c)
528 0 : : approximately_negative(b - a) && approximately_negative(c - b);
529 : }
530 :
531 0 : inline bool precisely_between(double a, double b, double c) {
532 0 : return a <= c ? precisely_negative(a - b) && precisely_negative(b - c)
533 0 : : precisely_negative(b - a) && precisely_negative(c - b);
534 : }
535 :
536 : // returns true if (a <= b <= c) || (a >= b >= c)
537 64 : inline bool between(double a, double b, double c) {
538 64 : SkASSERT(((a <= b && b <= c) || (a >= b && b >= c)) == ((a - b) * (c - b) <= 0)
539 : || (precisely_zero(a) && precisely_zero(b) && precisely_zero(c)));
540 64 : return (a - b) * (c - b) <= 0;
541 : }
542 :
543 0 : inline bool roughly_equal(double x, double y) {
544 0 : return fabs(x - y) < ROUGH_EPSILON;
545 : }
546 :
547 0 : inline bool roughly_negative(double x) {
548 0 : return x < ROUGH_EPSILON;
549 : }
550 :
551 0 : inline bool roughly_between(double a, double b, double c) {
552 0 : return a <= c ? roughly_negative(a - b) && roughly_negative(b - c)
553 0 : : roughly_negative(b - a) && roughly_negative(c - b);
554 : }
555 :
556 0 : inline bool more_roughly_equal(double x, double y) {
557 0 : return fabs(x - y) < MORE_ROUGH_EPSILON;
558 : }
559 :
560 : struct SkDPoint;
561 : struct SkDVector;
562 : struct SkDLine;
563 : struct SkDQuad;
564 : struct SkDConic;
565 : struct SkDCubic;
566 : struct SkDRect;
567 :
568 0 : inline SkPath::Verb SkPathOpsPointsToVerb(int points) {
569 0 : int verb = (1 << points) >> 1;
570 : #ifdef SK_DEBUG
571 0 : switch (points) {
572 0 : case 0: SkASSERT(SkPath::kMove_Verb == verb); break;
573 0 : case 1: SkASSERT(SkPath::kLine_Verb == verb); break;
574 0 : case 2: SkASSERT(SkPath::kQuad_Verb == verb); break;
575 0 : case 3: SkASSERT(SkPath::kCubic_Verb == verb); break;
576 0 : default: SkDEBUGFAIL("should not be here");
577 : }
578 : #endif
579 0 : return (SkPath::Verb)verb;
580 : }
581 :
582 0 : inline int SkPathOpsVerbToPoints(SkPath::Verb verb) {
583 0 : int points = (int) verb - (((int) verb + 1) >> 2);
584 : #ifdef SK_DEBUG
585 0 : switch (verb) {
586 0 : case SkPath::kLine_Verb: SkASSERT(1 == points); break;
587 0 : case SkPath::kQuad_Verb: SkASSERT(2 == points); break;
588 0 : case SkPath::kConic_Verb: SkASSERT(2 == points); break;
589 0 : case SkPath::kCubic_Verb: SkASSERT(3 == points); break;
590 0 : default: SkDEBUGFAIL("should not get here");
591 : }
592 : #endif
593 0 : return points;
594 : }
595 :
596 396 : inline double SkDInterp(double A, double B, double t) {
597 396 : return A + (B - A) * t;
598 : }
599 :
600 : double SkDCubeRoot(double x);
601 :
602 : /* Returns -1 if negative, 0 if zero, 1 if positive
603 : */
604 : inline int SkDSign(double x) {
605 : return (x > 0) - (x < 0);
606 : }
607 :
608 : /* Returns 0 if negative, 1 if zero, 2 if positive
609 : */
610 : inline int SKDSide(double x) {
611 : return (x > 0) + (x >= 0);
612 : }
613 :
614 : /* Returns 1 if negative, 2 if zero, 4 if positive
615 : */
616 : inline int SkDSideBit(double x) {
617 : return 1 << SKDSide(x);
618 : }
619 :
620 0 : inline double SkPinT(double t) {
621 0 : return precisely_less_than_zero(t) ? 0 : precisely_greater_than_one(t) ? 1 : t;
622 : }
623 :
624 : #endif
|