blob: a3e83326503d5eb2dfa239e6443363e1d88036c0 [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
10#include "SkPathOpsCubic.h"
11#include "SkPathOpsLine.h"
12#include "SkPathOpsPoint.h"
13#include "SkPathOpsQuad.h"
14
15class SkIntersections {
16public:
17 SkIntersections()
18 : fSwap(0)
19#ifdef SK_DEBUG
20 , fDepth(0)
21#endif
22 {
23 sk_bzero(fPt, sizeof(fPt));
24 sk_bzero(fT, sizeof(fT));
25 sk_bzero(fIsCoincident, sizeof(fIsCoincident));
caryclark@google.com570863f2013-09-16 15:55:01 +000026 sk_bzero(&fIsNear, sizeof(fIsNear));
caryclark@google.com07393ca2013-04-08 11:47:37 +000027 reset();
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000028 fMax = 0; // require that the caller set the max
caryclark@google.com07393ca2013-04-08 11:47:37 +000029 }
30
31 class TArray {
32 public:
33 explicit TArray(const double ts[9]) : fTArray(ts) {}
34 double operator[](int n) const {
35 return fTArray[n];
36 }
37 const double* fTArray;
38 };
39 TArray operator[](int n) const { return TArray(fT[n]); }
40
caryclark@google.comb3f09212013-04-17 15:49:16 +000041 void set(const SkIntersections& i) {
42 memcpy(fPt, i.fPt, sizeof(fPt));
43 memcpy(fT, i.fT, sizeof(fT));
44 memcpy(fIsCoincident, i.fIsCoincident, sizeof(fIsCoincident));
caryclark@google.com570863f2013-09-16 15:55:01 +000045 memcpy(&fIsNear, &i.fIsNear, sizeof(fIsNear));
caryclark@google.comb3f09212013-04-17 15:49:16 +000046 fUsed = i.fUsed;
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000047 fMax = i.fMax;
caryclark@google.comb3f09212013-04-17 15:49:16 +000048 fSwap = i.fSwap;
49 SkDEBUGCODE(fDepth = i.fDepth);
50 }
51
caryclark@google.comfa2aeee2013-07-15 13:29:13 +000052 void allowNear(bool nearAllowed) {
53 fAllowNear = nearAllowed;
54 }
55
caryclark@google.com07393ca2013-04-08 11:47:37 +000056 int cubic(const SkPoint a[4]) {
57 SkDCubic cubic;
58 cubic.set(a);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000059 fMax = 1; // self intersect
caryclark@google.com07393ca2013-04-08 11:47:37 +000060 return intersect(cubic);
61 }
62
63 int cubicCubic(const SkPoint a[4], const SkPoint b[4]) {
64 SkDCubic aCubic;
65 aCubic.set(a);
66 SkDCubic bCubic;
67 bCubic.set(b);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000068 fMax = 9;
caryclark@google.com07393ca2013-04-08 11:47:37 +000069 return intersect(aCubic, bCubic);
70 }
71
72 int cubicHorizontal(const SkPoint a[4], SkScalar left, SkScalar right, SkScalar y,
73 bool flipped) {
74 SkDCubic cubic;
75 cubic.set(a);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000076 fMax = 3;
caryclark@google.com07393ca2013-04-08 11:47:37 +000077 return horizontal(cubic, left, right, y, flipped);
78 }
79
80 int cubicVertical(const SkPoint a[4], SkScalar top, SkScalar bottom, SkScalar x, bool flipped) {
81 SkDCubic cubic;
82 cubic.set(a);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000083 fMax = 3;
caryclark@google.com07393ca2013-04-08 11:47:37 +000084 return vertical(cubic, top, bottom, x, flipped);
85 }
86
87 int cubicLine(const SkPoint a[4], const SkPoint b[2]) {
88 SkDCubic cubic;
89 cubic.set(a);
90 SkDLine line;
91 line.set(b);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000092 fMax = 3;
caryclark@google.com07393ca2013-04-08 11:47:37 +000093 return intersect(cubic, line);
94 }
95
96 int cubicQuad(const SkPoint a[4], const SkPoint b[3]) {
97 SkDCubic cubic;
98 cubic.set(a);
99 SkDQuad quad;
100 quad.set(b);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000101 fMax = 6;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000102 return intersect(cubic, quad);
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
caryclark@google.com570863f2013-09-16 15:55:01 +0000122 bool isNear(int index) {
123 return (fIsNear & 1 << index) != 0;
124 }
125
caryclark@google.com07393ca2013-04-08 11:47:37 +0000126 int lineHorizontal(const SkPoint a[2], SkScalar left, SkScalar right, SkScalar y,
127 bool flipped) {
128 SkDLine line;
129 line.set(a);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000130 fMax = 2;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000131 return horizontal(line, left, right, y, flipped);
132 }
133
134 int lineVertical(const SkPoint a[2], SkScalar top, SkScalar bottom, SkScalar x, bool flipped) {
135 SkDLine line;
136 line.set(a);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000137 fMax = 2;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000138 return vertical(line, top, bottom, x, flipped);
139 }
140
141 int lineLine(const SkPoint a[2], const SkPoint b[2]) {
142 SkDLine aLine, bLine;
143 aLine.set(a);
144 bLine.set(b);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000145 fMax = 2;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000146 return intersect(aLine, bLine);
147 }
148
149 const SkDPoint& pt(int index) const {
150 return fPt[index];
151 }
152
153 int quadHorizontal(const SkPoint a[3], SkScalar left, SkScalar right, SkScalar y,
154 bool flipped) {
155 SkDQuad quad;
156 quad.set(a);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000157 fMax = 2;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000158 return horizontal(quad, left, right, y, flipped);
159 }
160
161 int quadVertical(const SkPoint a[3], SkScalar top, SkScalar bottom, SkScalar x, bool flipped) {
162 SkDQuad quad;
163 quad.set(a);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000164 fMax = 2;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000165 return vertical(quad, top, bottom, x, flipped);
166 }
167
168 int quadLine(const SkPoint a[3], const SkPoint b[2]) {
169 SkDQuad quad;
170 quad.set(a);
171 SkDLine line;
172 line.set(b);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000173 fMax = 2;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000174 return intersect(quad, line);
175 }
176
177 int quadQuad(const SkPoint a[3], const SkPoint b[3]) {
178 SkDQuad aQuad;
179 aQuad.set(a);
180 SkDQuad bQuad;
181 bQuad.set(b);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000182 fMax = 4;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000183 return intersect(aQuad, bQuad);
184 }
185
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000186 // leaves flip, swap, max alone
caryclark@google.com07393ca2013-04-08 11:47:37 +0000187 void reset() {
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000188 fAllowNear = true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000189 fUsed = 0;
190 }
191
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000192 void setMax(int max) {
193 fMax = max;
194 }
195
caryclark@google.com07393ca2013-04-08 11:47:37 +0000196 void swap() {
197 fSwap ^= true;
198 }
199
200 void swapPts();
201
202 bool swapped() const {
203 return fSwap;
204 }
205
206 int used() const {
207 return fUsed;
208 }
209
210 void downDepth() {
211 SkASSERT(--fDepth >= 0);
212 }
213
214 void upDepth() {
215 SkASSERT(++fDepth < 16);
216 }
217
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000218 void append(const SkIntersections& );
caryclark@google.com07393ca2013-04-08 11:47:37 +0000219 static double Axial(const SkDQuad& , const SkDPoint& , bool vertical);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000220 void cleanUpCoincidence();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000221 int coincidentUsed() const;
222 int cubicRay(const SkPoint pts[4], const SkDLine& line);
223 void flip();
224 int horizontal(const SkDLine&, double y);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000225 int horizontal(const SkDLine&, double left, double right, double y, bool flipped);
226 int horizontal(const SkDQuad&, double left, double right, double y, bool flipped);
227 int horizontal(const SkDQuad&, double left, double right, double y, double tRange[2]);
228 int horizontal(const SkDCubic&, double y, double tRange[3]);
229 int horizontal(const SkDCubic&, double left, double right, double y, bool flipped);
230 int horizontal(const SkDCubic&, double left, double right, double y, double tRange[3]);
231 // FIXME : does not respect swap
232 int insert(double one, double two, const SkDPoint& pt);
caryclark@google.com570863f2013-09-16 15:55:01 +0000233 void insertNear(double one, double two, const SkDPoint& pt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000234 // start if index == 0 : end if index == 1
235 void insertCoincident(double one, double two, const SkDPoint& pt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000236 int intersect(const SkDLine&, const SkDLine&);
237 int intersect(const SkDQuad&, const SkDLine&);
238 int intersect(const SkDQuad&, const SkDQuad&);
239 int intersect(const SkDCubic&); // return true if cubic self-intersects
240 int intersect(const SkDCubic&, const SkDLine&);
241 int intersect(const SkDCubic&, const SkDQuad&);
242 int intersect(const SkDCubic&, const SkDCubic&);
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000243 int intersectRay(const SkDLine&, const SkDLine&);
244 int intersectRay(const SkDQuad&, const SkDLine&);
245 int intersectRay(const SkDCubic&, const SkDLine&);
246 static SkDPoint Line(const SkDLine&, const SkDLine&);
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000247 int lineRay(const SkPoint pts[2], const SkDLine& line);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000248 void offset(int base, double start, double end);
249 void quickRemoveOne(int index, int replace);
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000250 int quadRay(const SkPoint pts[3], const SkDLine& line);
251 void removeOne(int index);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000252 static bool Test(const SkDLine& , const SkDLine&);
253 int vertical(const SkDLine&, double x);
254 int vertical(const SkDLine&, double top, double bottom, double x, bool flipped);
255 int vertical(const SkDQuad&, double top, double bottom, double x, bool flipped);
256 int vertical(const SkDCubic&, double top, double bottom, double x, bool flipped);
257 int verticalCubic(const SkPoint a[4], SkScalar top, SkScalar bottom, SkScalar x, bool flipped);
258 int verticalLine(const SkPoint a[2], SkScalar top, SkScalar bottom, SkScalar x, bool flipped);
259 int verticalQuad(const SkPoint a[3], SkScalar top, SkScalar bottom, SkScalar x, bool flipped);
260
261 int depth() const {
262#ifdef SK_DEBUG
263 return fDepth;
264#else
265 return 0;
266#endif
267 }
268
269private:
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000270 bool cubicCheckCoincidence(const SkDCubic& c1, const SkDCubic& c2);
271 bool cubicExactEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cubic2);
272 void cubicNearEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cubic2, const SkDRect& );
273 void cleanUpParallelLines(bool parallel);
274 void computePoints(const SkDLine& line, int used);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000275 // used by addCoincident to remove ordinary intersections in range
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000276 // void remove(double one, double two, const SkDPoint& startPt, const SkDPoint& endPt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000277
caryclark@google.com570863f2013-09-16 15:55:01 +0000278 SkDPoint fPt[9]; // FIXME: since scans store points as SkPoint, this should also
caryclark@google.com07393ca2013-04-08 11:47:37 +0000279 double fT[2][9];
caryclark@google.com570863f2013-09-16 15:55:01 +0000280 uint16_t fIsCoincident[2]; // bit set for each curve's coincident T
281 uint16_t fIsNear; // bit set for each T if 2nd curve's point is near but not equal to 1st
caryclark@google.com07393ca2013-04-08 11:47:37 +0000282 unsigned char fUsed;
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000283 unsigned char fMax;
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000284 bool fAllowNear;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000285 bool fSwap;
286#ifdef SK_DEBUG
287 int fDepth;
288#endif
289};
290
291extern int (SkIntersections::*CurveRay[])(const SkPoint[], const SkDLine& );
292extern int (SkIntersections::*CurveVertical[])(const SkPoint[], SkScalar top, SkScalar bottom,
293 SkScalar x, bool flipped);
294
295#endif