blob: b733ed0ea7f654847fbe6b3629c02af886d36858 [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 SkIntersections_DEFINE
8#define SkIntersections_DEFINE
9
caryclark1049f122015-04-20 08:31:59 -070010#include "SkPathOpsConic.h"
caryclark@google.com07393ca2013-04-08 11:47:37 +000011#include "SkPathOpsCubic.h"
12#include "SkPathOpsLine.h"
13#include "SkPathOpsPoint.h"
14#include "SkPathOpsQuad.h"
15
16class SkIntersections {
17public:
18 SkIntersections()
19 : fSwap(0)
20#ifdef SK_DEBUG
21 , fDepth(0)
22#endif
23 {
24 sk_bzero(fPt, sizeof(fPt));
caryclarkdac1d172014-06-17 05:15:38 -070025 sk_bzero(fPt2, sizeof(fPt2));
caryclark@google.com07393ca2013-04-08 11:47:37 +000026 sk_bzero(fT, sizeof(fT));
caryclarkdac1d172014-06-17 05:15:38 -070027 sk_bzero(fNearlySame, sizeof(fNearlySame));
Tom Hudson2880df22015-10-29 09:55:42 -040028#if DEBUG_T_SECT_LOOP_COUNT
29 sk_bzero(fDebugLoopCount, sizeof(fDebugLoopCount));
30#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +000031 reset();
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000032 fMax = 0; // require that the caller set the max
caryclark@google.com07393ca2013-04-08 11:47:37 +000033 }
34
35 class TArray {
36 public:
caryclark54359292015-03-26 07:52:43 -070037 explicit TArray(const double ts[10]) : fTArray(ts) {}
caryclark@google.com07393ca2013-04-08 11:47:37 +000038 double operator[](int n) const {
39 return fTArray[n];
40 }
41 const double* fTArray;
42 };
43 TArray operator[](int n) const { return TArray(fT[n]); }
44
caryclark@google.comfa2aeee2013-07-15 13:29:13 +000045 void allowNear(bool nearAllowed) {
46 fAllowNear = nearAllowed;
47 }
48
caryclark54359292015-03-26 07:52:43 -070049 void clearCoincidence(int index) {
50 SkASSERT(index >= 0);
51 int bit = 1 << index;
52 fIsCoincident[0] &= ~bit;
53 fIsCoincident[1] &= ~bit;
caryclark@google.com07393ca2013-04-08 11:47:37 +000054 }
55
caryclark1049f122015-04-20 08:31:59 -070056 int conicHorizontal(const SkPoint a[3], SkScalar weight, SkScalar left, SkScalar right,
57 SkScalar y, bool flipped) {
58 SkDConic conic;
59 conic.set(a, weight);
60 fMax = 2;
61 return horizontal(conic, left, right, y, flipped);
62 }
63
64 int conicVertical(const SkPoint a[3], SkScalar weight, SkScalar top, SkScalar bottom,
65 SkScalar x, bool flipped) {
66 SkDConic conic;
67 conic.set(a, weight);
68 fMax = 2;
69 return vertical(conic, top, bottom, x, flipped);
70 }
71
72 int conicLine(const SkPoint a[3], SkScalar weight, const SkPoint b[2]) {
73 SkDConic conic;
74 conic.set(a, weight);
75 SkDLine line;
76 line.set(b);
77 fMax = 3; // 2; permit small coincident segment + non-coincident intersection
78 return intersect(conic, line);
79 }
80
caryclark@google.com07393ca2013-04-08 11:47:37 +000081 int cubicHorizontal(const SkPoint a[4], SkScalar left, SkScalar right, SkScalar y,
82 bool flipped) {
83 SkDCubic cubic;
84 cubic.set(a);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000085 fMax = 3;
caryclark@google.com07393ca2013-04-08 11:47:37 +000086 return horizontal(cubic, left, right, y, flipped);
87 }
88
89 int cubicVertical(const SkPoint a[4], SkScalar top, SkScalar bottom, SkScalar x, bool flipped) {
90 SkDCubic cubic;
91 cubic.set(a);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000092 fMax = 3;
caryclark@google.com07393ca2013-04-08 11:47:37 +000093 return vertical(cubic, top, bottom, x, flipped);
94 }
95
96 int cubicLine(const SkPoint a[4], const SkPoint b[2]) {
97 SkDCubic cubic;
98 cubic.set(a);
99 SkDLine line;
100 line.set(b);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000101 fMax = 3;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000102 return intersect(cubic, line);
103 }
104
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000105 bool hasT(double t) const {
106 SkASSERT(t == 0 || t == 1);
107 return fUsed > 0 && (t == 0 ? fT[0][0] == 0 : fT[0][fUsed - 1] == 1);
108 }
109
caryclark@google.com07393ca2013-04-08 11:47:37 +0000110 int insertSwap(double one, double two, const SkDPoint& pt) {
111 if (fSwap) {
112 return insert(two, one, pt);
113 } else {
114 return insert(one, two, pt);
115 }
116 }
117
118 bool isCoincident(int index) {
119 return (fIsCoincident[0] & 1 << index) != 0;
120 }
121
122 int lineHorizontal(const SkPoint a[2], SkScalar left, SkScalar right, SkScalar y,
123 bool flipped) {
124 SkDLine line;
125 line.set(a);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000126 fMax = 2;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000127 return horizontal(line, left, right, y, flipped);
128 }
129
130 int lineVertical(const SkPoint a[2], SkScalar top, SkScalar bottom, SkScalar x, bool flipped) {
131 SkDLine line;
132 line.set(a);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000133 fMax = 2;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000134 return vertical(line, top, bottom, x, flipped);
135 }
136
137 int lineLine(const SkPoint a[2], const SkPoint b[2]) {
138 SkDLine aLine, bLine;
139 aLine.set(a);
140 bLine.set(b);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000141 fMax = 2;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000142 return intersect(aLine, bLine);
143 }
144
caryclarkdac1d172014-06-17 05:15:38 -0700145 bool nearlySame(int index) const {
146 SkASSERT(index == 0 || index == 1);
147 return fNearlySame[index];
148 }
149
caryclark@google.com07393ca2013-04-08 11:47:37 +0000150 const SkDPoint& pt(int index) const {
151 return fPt[index];
152 }
153
caryclarkdac1d172014-06-17 05:15:38 -0700154 const SkDPoint& pt2(int index) const {
155 return fPt2[index];
156 }
157
caryclark@google.com07393ca2013-04-08 11:47:37 +0000158 int quadHorizontal(const SkPoint a[3], SkScalar left, SkScalar right, SkScalar y,
159 bool flipped) {
160 SkDQuad quad;
161 quad.set(a);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000162 fMax = 2;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000163 return horizontal(quad, left, right, y, flipped);
164 }
165
166 int quadVertical(const SkPoint a[3], SkScalar top, SkScalar bottom, SkScalar x, bool flipped) {
167 SkDQuad quad;
168 quad.set(a);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000169 fMax = 2;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000170 return vertical(quad, top, bottom, x, flipped);
171 }
172
173 int quadLine(const SkPoint a[3], const SkPoint b[2]) {
174 SkDQuad quad;
175 quad.set(a);
176 SkDLine line;
177 line.set(b);
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000178 fMax = 3; // 2; permit small coincident segment + non-coincident intersection
caryclark@google.com07393ca2013-04-08 11:47:37 +0000179 return intersect(quad, line);
180 }
181
caryclarkdac1d172014-06-17 05:15:38 -0700182 // leaves swap, max alone
caryclark@google.com07393ca2013-04-08 11:47:37 +0000183 void reset() {
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000184 fAllowNear = true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000185 fUsed = 0;
caryclark54359292015-03-26 07:52:43 -0700186 sk_bzero(fIsCoincident, sizeof(fIsCoincident));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000187 }
188
caryclarkdac1d172014-06-17 05:15:38 -0700189 void set(bool swap, int tIndex, double t) {
190 fT[(int) swap][tIndex] = t;
191 }
192
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000193 void setMax(int max) {
Tom Hudson2880df22015-10-29 09:55:42 -0400194 SkASSERT(max <= (int) SK_ARRAY_COUNT(fPt));
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000195 fMax = max;
196 }
197
caryclark@google.com07393ca2013-04-08 11:47:37 +0000198 void swap() {
199 fSwap ^= true;
200 }
201
caryclark@google.com07393ca2013-04-08 11:47:37 +0000202 bool swapped() const {
203 return fSwap;
204 }
caryclark65f55312014-11-13 06:58:52 -0800205
caryclark@google.com07393ca2013-04-08 11:47:37 +0000206 int used() const {
207 return fUsed;
208 }
209
210 void downDepth() {
211 SkASSERT(--fDepth >= 0);
212 }
213
caryclark54359292015-03-26 07:52:43 -0700214 bool unBumpT(int index) {
215 SkASSERT(fUsed == 1);
216 fT[0][index] = fT[0][index] * (1 + BUMP_EPSILON * 2) - BUMP_EPSILON;
217 if (!between(0, fT[0][index], 1)) {
218 fUsed = 0;
219 return false;
220 }
221 return true;
222 }
223
caryclark@google.com07393ca2013-04-08 11:47:37 +0000224 void upDepth() {
225 SkASSERT(++fDepth < 16);
226 }
227
caryclark65f55312014-11-13 06:58:52 -0800228 void alignQuadPts(const SkPoint a[3], const SkPoint b[3]);
caryclark65f55312014-11-13 06:58:52 -0800229 int cleanUpCoincidence();
caryclark54359292015-03-26 07:52:43 -0700230 int closestTo(double rangeStart, double rangeEnd, const SkDPoint& testPt, double* dist) const;
caryclarkdac1d172014-06-17 05:15:38 -0700231 void cubicInsert(double one, double two, const SkDPoint& pt, const SkDCubic& c1,
232 const SkDCubic& c2);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000233 void flip();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000234 int horizontal(const SkDLine&, double left, double right, double y, bool flipped);
235 int horizontal(const SkDQuad&, double left, double right, double y, bool flipped);
236 int horizontal(const SkDQuad&, double left, double right, double y, double tRange[2]);
237 int horizontal(const SkDCubic&, double y, double tRange[3]);
caryclark1049f122015-04-20 08:31:59 -0700238 int horizontal(const SkDConic&, double left, double right, double y, bool flipped);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000239 int horizontal(const SkDCubic&, double left, double right, double y, bool flipped);
240 int horizontal(const SkDCubic&, double left, double right, double y, double tRange[3]);
caryclark624637c2015-05-11 07:21:27 -0700241 static double HorizontalIntercept(const SkDLine& line, double y);
242 static int HorizontalIntercept(const SkDQuad& quad, SkScalar y, double* roots);
243 static int HorizontalIntercept(const SkDConic& conic, SkScalar y, double* roots);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000244 // FIXME : does not respect swap
245 int insert(double one, double two, const SkDPoint& pt);
caryclarkdac1d172014-06-17 05:15:38 -0700246 void insertNear(double one, double two, const SkDPoint& pt1, const SkDPoint& pt2);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000247 // start if index == 0 : end if index == 1
caryclark54359292015-03-26 07:52:43 -0700248 int insertCoincident(double one, double two, const SkDPoint& pt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000249 int intersect(const SkDLine&, const SkDLine&);
250 int intersect(const SkDQuad&, const SkDLine&);
251 int intersect(const SkDQuad&, const SkDQuad&);
caryclark1049f122015-04-20 08:31:59 -0700252 int intersect(const SkDConic&, const SkDLine&);
253 int intersect(const SkDConic&, const SkDQuad&);
254 int intersect(const SkDConic&, const SkDConic&);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000255 int intersect(const SkDCubic&, const SkDLine&);
caryclark1049f122015-04-20 08:31:59 -0700256 int intersect(const SkDCubic&, const SkDQuad&);
257 int intersect(const SkDCubic&, const SkDConic&);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000258 int intersect(const SkDCubic&, const SkDCubic&);
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000259 int intersectRay(const SkDLine&, const SkDLine&);
260 int intersectRay(const SkDQuad&, const SkDLine&);
caryclark1049f122015-04-20 08:31:59 -0700261 int intersectRay(const SkDConic&, const SkDLine&);
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000262 int intersectRay(const SkDCubic&, const SkDLine&);
caryclark54359292015-03-26 07:52:43 -0700263 void merge(const SkIntersections& , int , const SkIntersections& , int );
264 int mostOutside(double rangeStart, double rangeEnd, const SkDPoint& origin) const;
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000265 void removeOne(int index);
caryclark54359292015-03-26 07:52:43 -0700266 void setCoincident(int index);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000267 int vertical(const SkDLine&, double top, double bottom, double x, bool flipped);
268 int vertical(const SkDQuad&, double top, double bottom, double x, bool flipped);
caryclark1049f122015-04-20 08:31:59 -0700269 int vertical(const SkDConic&, double top, double bottom, double x, bool flipped);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000270 int vertical(const SkDCubic&, double top, double bottom, double x, bool flipped);
caryclark624637c2015-05-11 07:21:27 -0700271 static double VerticalIntercept(const SkDLine& line, double x);
272 static int VerticalIntercept(const SkDQuad& quad, SkScalar x, double* roots);
273 static int VerticalIntercept(const SkDConic& conic, SkScalar x, double* roots);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000274
275 int depth() const {
276#ifdef SK_DEBUG
277 return fDepth;
278#else
279 return 0;
280#endif
281 }
282
Tom Hudson2880df22015-10-29 09:55:42 -0400283 enum DebugLoop {
284 kIterations_DebugLoop,
285 kCoinCheck_DebugLoop,
286 kComputePerp_DebugLoop,
287 };
288
289 void debugBumpLoopCount(DebugLoop );
caryclark624637c2015-05-11 07:21:27 -0700290 int debugCoincidentUsed() const;
Tom Hudson2880df22015-10-29 09:55:42 -0400291 int debugLoopCount(DebugLoop ) const;
292 void debugResetLoopCount();
caryclark54359292015-03-26 07:52:43 -0700293 void dump() const; // implemented for testing only
294
caryclark@google.com07393ca2013-04-08 11:47:37 +0000295private:
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000296 bool cubicCheckCoincidence(const SkDCubic& c1, const SkDCubic& c2);
297 bool cubicExactEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cubic2);
298 void cubicNearEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cubic2, const SkDRect& );
299 void cleanUpParallelLines(bool parallel);
300 void computePoints(const SkDLine& line, int used);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000301
Tom Hudson2880df22015-10-29 09:55:42 -0400302 SkDPoint fPt[12]; // FIXME: since scans store points as SkPoint, this should also
caryclark54359292015-03-26 07:52:43 -0700303 SkDPoint fPt2[2]; // used by nearly same to store alternate intersection point
Tom Hudson2880df22015-10-29 09:55:42 -0400304 double fT[2][12];
caryclark@google.com570863f2013-09-16 15:55:01 +0000305 uint16_t fIsCoincident[2]; // bit set for each curve's coincident T
caryclarkdac1d172014-06-17 05:15:38 -0700306 bool fNearlySame[2]; // true if end points nearly match
caryclark@google.com07393ca2013-04-08 11:47:37 +0000307 unsigned char fUsed;
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000308 unsigned char fMax;
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000309 bool fAllowNear;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000310 bool fSwap;
311#ifdef SK_DEBUG
312 int fDepth;
313#endif
Tom Hudson2880df22015-10-29 09:55:42 -0400314#if DEBUG_T_SECT_LOOP_COUNT
315 int fDebugLoopCount[3];
316#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000317};
318
caryclark@google.com07393ca2013-04-08 11:47:37 +0000319#endif