blob: f63a023ef0a5ef26c21c42ecfc8bd5b0c2a88fc3 [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
186 int quadRay(const SkPoint pts[3], const SkDLine& line);
187 void removeOne(int index);
188
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000189 // leaves flip, swap, max alone
caryclark@google.com07393ca2013-04-08 11:47:37 +0000190 void reset() {
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000191 fAllowNear = true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000192 fUsed = 0;
193 }
194
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000195 void setMax(int max) {
196 fMax = max;
197 }
198
caryclark@google.com07393ca2013-04-08 11:47:37 +0000199 void swap() {
200 fSwap ^= true;
201 }
202
203 void swapPts();
204
205 bool swapped() const {
206 return fSwap;
207 }
208
209 int used() const {
210 return fUsed;
211 }
212
213 void downDepth() {
214 SkASSERT(--fDepth >= 0);
215 }
216
217 void upDepth() {
218 SkASSERT(++fDepth < 16);
219 }
220
221 static double Axial(const SkDQuad& , const SkDPoint& , bool vertical);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000222 void cleanUpCoincidence();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000223 int coincidentUsed() const;
224 int cubicRay(const SkPoint pts[4], const SkDLine& line);
225 void flip();
226 int horizontal(const SkDLine&, double y);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000227 int horizontal(const SkDLine&, double left, double right, double y, bool flipped);
228 int horizontal(const SkDQuad&, double left, double right, double y, bool flipped);
229 int horizontal(const SkDQuad&, double left, double right, double y, double tRange[2]);
230 int horizontal(const SkDCubic&, double y, double tRange[3]);
231 int horizontal(const SkDCubic&, double left, double right, double y, bool flipped);
232 int horizontal(const SkDCubic&, double left, double right, double y, double tRange[3]);
233 // FIXME : does not respect swap
234 int insert(double one, double two, const SkDPoint& pt);
caryclark@google.com570863f2013-09-16 15:55:01 +0000235 void insertNear(double one, double two, const SkDPoint& pt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000236 // start if index == 0 : end if index == 1
237 void insertCoincident(double one, double two, const SkDPoint& pt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000238 int intersect(const SkDLine&, const SkDLine&);
239 int intersect(const SkDQuad&, const SkDLine&);
240 int intersect(const SkDQuad&, const SkDQuad&);
241 int intersect(const SkDCubic&); // return true if cubic self-intersects
242 int intersect(const SkDCubic&, const SkDLine&);
243 int intersect(const SkDCubic&, const SkDQuad&);
244 int intersect(const SkDCubic&, const SkDCubic&);
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000245 int intersectRay(const SkDLine&, const SkDLine&);
246 int intersectRay(const SkDQuad&, const SkDLine&);
247 int intersectRay(const SkDCubic&, const SkDLine&);
248 static SkDPoint Line(const SkDLine&, const SkDLine&);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000249 void offset(int base, double start, double end);
250 void quickRemoveOne(int index, int replace);
251 static bool Test(const SkDLine& , const SkDLine&);
252 int vertical(const SkDLine&, double x);
253 int vertical(const SkDLine&, double top, double bottom, double x, bool flipped);
254 int vertical(const SkDQuad&, double top, double bottom, double x, bool flipped);
255 int vertical(const SkDCubic&, double top, double bottom, double x, bool flipped);
256 int verticalCubic(const SkPoint a[4], SkScalar top, SkScalar bottom, SkScalar x, bool flipped);
257 int verticalLine(const SkPoint a[2], SkScalar top, SkScalar bottom, SkScalar x, bool flipped);
258 int verticalQuad(const SkPoint a[3], SkScalar top, SkScalar bottom, SkScalar x, bool flipped);
259
260 int depth() const {
261#ifdef SK_DEBUG
262 return fDepth;
263#else
264 return 0;
265#endif
266 }
267
268private:
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000269 bool cubicCheckCoincidence(const SkDCubic& c1, const SkDCubic& c2);
270 bool cubicExactEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cubic2);
271 void cubicNearEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cubic2, const SkDRect& );
272 void cleanUpParallelLines(bool parallel);
273 void computePoints(const SkDLine& line, int used);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000274 // used by addCoincident to remove ordinary intersections in range
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000275 // void remove(double one, double two, const SkDPoint& startPt, const SkDPoint& endPt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000276
caryclark@google.com570863f2013-09-16 15:55:01 +0000277 SkDPoint fPt[9]; // FIXME: since scans store points as SkPoint, this should also
caryclark@google.com07393ca2013-04-08 11:47:37 +0000278 double fT[2][9];
caryclark@google.com570863f2013-09-16 15:55:01 +0000279 uint16_t fIsCoincident[2]; // bit set for each curve's coincident T
280 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 +0000281 unsigned char fUsed;
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000282 unsigned char fMax;
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000283 bool fAllowNear;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000284 bool fSwap;
285#ifdef SK_DEBUG
286 int fDepth;
287#endif
288};
289
290extern int (SkIntersections::*CurveRay[])(const SkPoint[], const SkDLine& );
291extern int (SkIntersections::*CurveVertical[])(const SkPoint[], SkScalar top, SkScalar bottom,
292 SkScalar x, bool flipped);
293
294#endif