blob: d5d217cc80173ccb03a89fa627926da5825f7fb4 [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:
caryclarkdae6b972016-06-08 04:28:19 -070018 SkIntersections(SkDEBUGCODE(SkOpGlobalState* globalState = nullptr))
caryclark@google.com07393ca2013-04-08 11:47:37 +000019 : fSwap(0)
20#ifdef SK_DEBUG
caryclarkdae6b972016-06-08 04:28:19 -070021 SkDEBUGPARAMS(fDebugGlobalState(globalState))
caryclark@google.com07393ca2013-04-08 11:47:37 +000022 , fDepth(0)
23#endif
24 {
25 sk_bzero(fPt, sizeof(fPt));
caryclarkdac1d172014-06-17 05:15:38 -070026 sk_bzero(fPt2, sizeof(fPt2));
caryclark@google.com07393ca2013-04-08 11:47:37 +000027 sk_bzero(fT, sizeof(fT));
caryclarkdac1d172014-06-17 05:15:38 -070028 sk_bzero(fNearlySame, sizeof(fNearlySame));
caryclark26ad22a2015-10-16 09:03:38 -070029#if DEBUG_T_SECT_LOOP_COUNT
30 sk_bzero(fDebugLoopCount, sizeof(fDebugLoopCount));
31#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +000032 reset();
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000033 fMax = 0; // require that the caller set the max
caryclark@google.com07393ca2013-04-08 11:47:37 +000034 }
35
36 class TArray {
37 public:
caryclark54359292015-03-26 07:52:43 -070038 explicit TArray(const double ts[10]) : fTArray(ts) {}
caryclark@google.com07393ca2013-04-08 11:47:37 +000039 double operator[](int n) const {
40 return fTArray[n];
41 }
42 const double* fTArray;
43 };
44 TArray operator[](int n) const { return TArray(fT[n]); }
45
caryclark@google.comfa2aeee2013-07-15 13:29:13 +000046 void allowNear(bool nearAllowed) {
47 fAllowNear = nearAllowed;
48 }
49
caryclark54359292015-03-26 07:52:43 -070050 void clearCoincidence(int index) {
51 SkASSERT(index >= 0);
52 int bit = 1 << index;
53 fIsCoincident[0] &= ~bit;
54 fIsCoincident[1] &= ~bit;
caryclark@google.com07393ca2013-04-08 11:47:37 +000055 }
56
caryclark1049f122015-04-20 08:31:59 -070057 int conicHorizontal(const SkPoint a[3], SkScalar weight, SkScalar left, SkScalar right,
58 SkScalar y, bool flipped) {
59 SkDConic conic;
60 conic.set(a, weight);
61 fMax = 2;
62 return horizontal(conic, left, right, y, flipped);
63 }
64
65 int conicVertical(const SkPoint a[3], SkScalar weight, SkScalar top, SkScalar bottom,
66 SkScalar x, bool flipped) {
67 SkDConic conic;
68 conic.set(a, weight);
69 fMax = 2;
70 return vertical(conic, top, bottom, x, flipped);
71 }
72
73 int conicLine(const SkPoint a[3], SkScalar weight, const SkPoint b[2]) {
74 SkDConic conic;
75 conic.set(a, weight);
76 SkDLine line;
77 line.set(b);
78 fMax = 3; // 2; permit small coincident segment + non-coincident intersection
79 return intersect(conic, line);
80 }
81
caryclark@google.com07393ca2013-04-08 11:47:37 +000082 int cubicHorizontal(const SkPoint a[4], SkScalar left, SkScalar right, SkScalar y,
83 bool flipped) {
84 SkDCubic cubic;
85 cubic.set(a);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000086 fMax = 3;
caryclark@google.com07393ca2013-04-08 11:47:37 +000087 return horizontal(cubic, left, right, y, flipped);
88 }
89
90 int cubicVertical(const SkPoint a[4], SkScalar top, SkScalar bottom, SkScalar x, bool flipped) {
91 SkDCubic cubic;
92 cubic.set(a);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000093 fMax = 3;
caryclark@google.com07393ca2013-04-08 11:47:37 +000094 return vertical(cubic, top, bottom, x, flipped);
95 }
96
97 int cubicLine(const SkPoint a[4], const SkPoint b[2]) {
98 SkDCubic cubic;
99 cubic.set(a);
100 SkDLine line;
101 line.set(b);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000102 fMax = 3;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000103 return intersect(cubic, line);
104 }
105
caryclarkdae6b972016-06-08 04:28:19 -0700106#ifdef SK_DEBUG
caryclarka35ab3e2016-10-20 08:32:18 -0700107 SkOpGlobalState* globalState() const { return fDebugGlobalState; }
caryclarkdae6b972016-06-08 04:28:19 -0700108#endif
109
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000110 bool hasT(double t) const {
111 SkASSERT(t == 0 || t == 1);
112 return fUsed > 0 && (t == 0 ? fT[0][0] == 0 : fT[0][fUsed - 1] == 1);
113 }
114
caryclark55888e42016-07-18 10:01:36 -0700115 bool hasOppT(double t) const {
116 SkASSERT(t == 0 || t == 1);
117 return fUsed > 0 && (fT[1][0] == t || fT[1][fUsed - 1] == t);
118 }
119
caryclark@google.com07393ca2013-04-08 11:47:37 +0000120 int insertSwap(double one, double two, const SkDPoint& pt) {
121 if (fSwap) {
122 return insert(two, one, pt);
123 } else {
124 return insert(one, two, pt);
125 }
126 }
127
128 bool isCoincident(int index) {
129 return (fIsCoincident[0] & 1 << index) != 0;
130 }
131
132 int lineHorizontal(const SkPoint a[2], SkScalar left, SkScalar right, SkScalar y,
133 bool flipped) {
134 SkDLine line;
135 line.set(a);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000136 fMax = 2;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000137 return horizontal(line, left, right, y, flipped);
138 }
139
140 int lineVertical(const SkPoint a[2], SkScalar top, SkScalar bottom, SkScalar x, bool flipped) {
141 SkDLine line;
142 line.set(a);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000143 fMax = 2;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000144 return vertical(line, top, bottom, x, flipped);
145 }
146
147 int lineLine(const SkPoint a[2], const SkPoint b[2]) {
148 SkDLine aLine, bLine;
149 aLine.set(a);
150 bLine.set(b);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000151 fMax = 2;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000152 return intersect(aLine, bLine);
153 }
154
caryclarkdac1d172014-06-17 05:15:38 -0700155 bool nearlySame(int index) const {
156 SkASSERT(index == 0 || index == 1);
157 return fNearlySame[index];
158 }
159
caryclark@google.com07393ca2013-04-08 11:47:37 +0000160 const SkDPoint& pt(int index) const {
161 return fPt[index];
162 }
163
caryclarkdac1d172014-06-17 05:15:38 -0700164 const SkDPoint& pt2(int index) const {
165 return fPt2[index];
166 }
167
caryclark@google.com07393ca2013-04-08 11:47:37 +0000168 int quadHorizontal(const SkPoint a[3], SkScalar left, SkScalar right, SkScalar y,
169 bool flipped) {
170 SkDQuad quad;
171 quad.set(a);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000172 fMax = 2;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000173 return horizontal(quad, left, right, y, flipped);
174 }
175
176 int quadVertical(const SkPoint a[3], SkScalar top, SkScalar bottom, SkScalar x, bool flipped) {
177 SkDQuad quad;
178 quad.set(a);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000179 fMax = 2;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000180 return vertical(quad, top, bottom, x, flipped);
181 }
182
183 int quadLine(const SkPoint a[3], const SkPoint b[2]) {
184 SkDQuad quad;
185 quad.set(a);
186 SkDLine line;
187 line.set(b);
188 return intersect(quad, line);
189 }
190
caryclarkdac1d172014-06-17 05:15:38 -0700191 // leaves swap, max alone
caryclark@google.com07393ca2013-04-08 11:47:37 +0000192 void reset() {
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000193 fAllowNear = true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000194 fUsed = 0;
caryclark54359292015-03-26 07:52:43 -0700195 sk_bzero(fIsCoincident, sizeof(fIsCoincident));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000196 }
197
caryclarkdac1d172014-06-17 05:15:38 -0700198 void set(bool swap, int tIndex, double t) {
199 fT[(int) swap][tIndex] = t;
200 }
201
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000202 void setMax(int max) {
caryclark94c902e2015-08-18 07:12:43 -0700203 SkASSERT(max <= (int) SK_ARRAY_COUNT(fPt));
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000204 fMax = max;
205 }
206
caryclark@google.com07393ca2013-04-08 11:47:37 +0000207 void swap() {
208 fSwap ^= true;
209 }
210
caryclark@google.com07393ca2013-04-08 11:47:37 +0000211 bool swapped() const {
212 return fSwap;
213 }
caryclark55888e42016-07-18 10:01:36 -0700214
caryclark@google.com07393ca2013-04-08 11:47:37 +0000215 int used() const {
216 return fUsed;
217 }
218
219 void downDepth() {
220 SkASSERT(--fDepth >= 0);
221 }
222
caryclark54359292015-03-26 07:52:43 -0700223 bool unBumpT(int index) {
224 SkASSERT(fUsed == 1);
225 fT[0][index] = fT[0][index] * (1 + BUMP_EPSILON * 2) - BUMP_EPSILON;
226 if (!between(0, fT[0][index], 1)) {
227 fUsed = 0;
228 return false;
229 }
230 return true;
231 }
232
caryclark@google.com07393ca2013-04-08 11:47:37 +0000233 void upDepth() {
234 SkASSERT(++fDepth < 16);
235 }
236
caryclark65f55312014-11-13 06:58:52 -0800237 void alignQuadPts(const SkPoint a[3], const SkPoint b[3]);
caryclark65f55312014-11-13 06:58:52 -0800238 int cleanUpCoincidence();
caryclark54359292015-03-26 07:52:43 -0700239 int closestTo(double rangeStart, double rangeEnd, const SkDPoint& testPt, double* dist) const;
caryclarkdac1d172014-06-17 05:15:38 -0700240 void cubicInsert(double one, double two, const SkDPoint& pt, const SkDCubic& c1,
241 const SkDCubic& c2);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000242 void flip();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000243 int horizontal(const SkDLine&, double left, double right, double y, bool flipped);
244 int horizontal(const SkDQuad&, double left, double right, double y, bool flipped);
245 int horizontal(const SkDQuad&, double left, double right, double y, double tRange[2]);
246 int horizontal(const SkDCubic&, double y, double tRange[3]);
caryclark1049f122015-04-20 08:31:59 -0700247 int horizontal(const SkDConic&, double left, double right, double y, bool flipped);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000248 int horizontal(const SkDCubic&, double left, double right, double y, bool flipped);
249 int horizontal(const SkDCubic&, double left, double right, double y, double tRange[3]);
caryclark624637c2015-05-11 07:21:27 -0700250 static double HorizontalIntercept(const SkDLine& line, double y);
251 static int HorizontalIntercept(const SkDQuad& quad, SkScalar y, double* roots);
252 static int HorizontalIntercept(const SkDConic& conic, SkScalar y, double* roots);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000253 // FIXME : does not respect swap
254 int insert(double one, double two, const SkDPoint& pt);
caryclarkdac1d172014-06-17 05:15:38 -0700255 void insertNear(double one, double two, const SkDPoint& pt1, const SkDPoint& pt2);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000256 // start if index == 0 : end if index == 1
caryclark54359292015-03-26 07:52:43 -0700257 int insertCoincident(double one, double two, const SkDPoint& pt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000258 int intersect(const SkDLine&, const SkDLine&);
259 int intersect(const SkDQuad&, const SkDLine&);
260 int intersect(const SkDQuad&, const SkDQuad&);
caryclark1049f122015-04-20 08:31:59 -0700261 int intersect(const SkDConic&, const SkDLine&);
262 int intersect(const SkDConic&, const SkDQuad&);
263 int intersect(const SkDConic&, const SkDConic&);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000264 int intersect(const SkDCubic&, const SkDLine&);
caryclark1049f122015-04-20 08:31:59 -0700265 int intersect(const SkDCubic&, const SkDQuad&);
266 int intersect(const SkDCubic&, const SkDConic&);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000267 int intersect(const SkDCubic&, const SkDCubic&);
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000268 int intersectRay(const SkDLine&, const SkDLine&);
269 int intersectRay(const SkDQuad&, const SkDLine&);
caryclark1049f122015-04-20 08:31:59 -0700270 int intersectRay(const SkDConic&, const SkDLine&);
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000271 int intersectRay(const SkDCubic&, const SkDLine&);
caryclark54359292015-03-26 07:52:43 -0700272 void merge(const SkIntersections& , int , const SkIntersections& , int );
273 int mostOutside(double rangeStart, double rangeEnd, const SkDPoint& origin) const;
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000274 void removeOne(int index);
caryclark54359292015-03-26 07:52:43 -0700275 void setCoincident(int index);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000276 int vertical(const SkDLine&, double top, double bottom, double x, bool flipped);
277 int vertical(const SkDQuad&, double top, double bottom, double x, bool flipped);
caryclark1049f122015-04-20 08:31:59 -0700278 int vertical(const SkDConic&, double top, double bottom, double x, bool flipped);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000279 int vertical(const SkDCubic&, double top, double bottom, double x, bool flipped);
caryclark624637c2015-05-11 07:21:27 -0700280 static double VerticalIntercept(const SkDLine& line, double x);
281 static int VerticalIntercept(const SkDQuad& quad, SkScalar x, double* roots);
282 static int VerticalIntercept(const SkDConic& conic, SkScalar x, double* roots);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000283
284 int depth() const {
285#ifdef SK_DEBUG
286 return fDepth;
287#else
288 return 0;
289#endif
290 }
291
caryclark26ad22a2015-10-16 09:03:38 -0700292 enum DebugLoop {
293 kIterations_DebugLoop,
294 kCoinCheck_DebugLoop,
295 kComputePerp_DebugLoop,
296 };
297
298 void debugBumpLoopCount(DebugLoop );
caryclark624637c2015-05-11 07:21:27 -0700299 int debugCoincidentUsed() const;
caryclark26ad22a2015-10-16 09:03:38 -0700300 int debugLoopCount(DebugLoop ) const;
301 void debugResetLoopCount();
caryclark54359292015-03-26 07:52:43 -0700302 void dump() const; // implemented for testing only
303
caryclark@google.com07393ca2013-04-08 11:47:37 +0000304private:
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000305 bool cubicCheckCoincidence(const SkDCubic& c1, const SkDCubic& c2);
306 bool cubicExactEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cubic2);
307 void cubicNearEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cubic2, const SkDRect& );
308 void cleanUpParallelLines(bool parallel);
309 void computePoints(const SkDLine& line, int used);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000310
caryclarka35ab3e2016-10-20 08:32:18 -0700311 SkDPoint fPt[13]; // FIXME: since scans store points as SkPoint, this should also
caryclark54359292015-03-26 07:52:43 -0700312 SkDPoint fPt2[2]; // used by nearly same to store alternate intersection point
caryclarka35ab3e2016-10-20 08:32:18 -0700313 double fT[2][13];
caryclark@google.com570863f2013-09-16 15:55:01 +0000314 uint16_t fIsCoincident[2]; // bit set for each curve's coincident T
caryclarkdac1d172014-06-17 05:15:38 -0700315 bool fNearlySame[2]; // true if end points nearly match
caryclark@google.com07393ca2013-04-08 11:47:37 +0000316 unsigned char fUsed;
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000317 unsigned char fMax;
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000318 bool fAllowNear;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000319 bool fSwap;
320#ifdef SK_DEBUG
caryclarkdae6b972016-06-08 04:28:19 -0700321 SkOpGlobalState* fDebugGlobalState;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000322 int fDepth;
323#endif
caryclark26ad22a2015-10-16 09:03:38 -0700324#if DEBUG_T_SECT_LOOP_COUNT
325 int fDebugLoopCount[3];
326#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000327};
328
caryclark@google.com07393ca2013-04-08 11:47:37 +0000329#endif