OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 #include "SkIntersections.h" | 7 #include "SkIntersections.h" |
8 #include "SkPathOpsCubic.h" | 8 #include "SkPathOpsCubic.h" |
9 #include "SkPathOpsLine.h" | 9 #include "SkPathOpsLine.h" |
10 | 10 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 3 e t^2 - 6 f t^2 + 3 g t^2 - | 73 3 e t^2 - 6 f t^2 + 3 g t^2 - |
74 e t^3 + 3 f t^3 - 3 g t^3 + h t^3 | 74 e t^3 + 3 f t^3 - 3 g t^3 + h t^3 |
75 */ | 75 */ |
76 | 76 |
77 class LineCubicIntersections { | 77 class LineCubicIntersections { |
78 public: | 78 public: |
79 | 79 |
80 LineCubicIntersections(const SkDCubic& c, const SkDLine& l, SkIntersections& i) | 80 LineCubicIntersections(const SkDCubic& c, const SkDLine& l, SkIntersections& i) |
81 : cubic(c) | 81 : cubic(c) |
82 , line(l) | 82 , line(l) |
83 , intersections(i) { | 83 , intersections(i) |
| 84 , fAllowNear(true) { |
| 85 } |
| 86 |
| 87 void allowNear(bool allow) { |
| 88 fAllowNear = allow; |
84 } | 89 } |
85 | 90 |
86 // see parallel routine in line quadratic intersections | 91 // see parallel routine in line quadratic intersections |
87 int intersectRay(double roots[3]) { | 92 int intersectRay(double roots[3]) { |
88 double adj = line[1].fX - line[0].fX; | 93 double adj = line[1].fX - line[0].fX; |
89 double opp = line[1].fY - line[0].fY; | 94 double opp = line[1].fY - line[0].fY; |
90 SkDCubic r; | 95 SkDCubic r; |
91 for (int n = 0; n < 4; ++n) { | 96 for (int n = 0; n < 4; ++n) { |
92 r[n].fX = (cubic[n].fY - line[0].fY) * adj - (cubic[n].fX - line[0].fX)
* opp; | 97 r[n].fX = (cubic[n].fY - line[0].fY) * adj - (cubic[n].fX - line[0].fX)
* opp; |
93 } | 98 } |
94 double A, B, C, D; | 99 double A, B, C, D; |
95 SkDCubic::Coefficients(&r[0].fX, &A, &B, &C, &D); | 100 SkDCubic::Coefficients(&r[0].fX, &A, &B, &C, &D); |
96 return SkDCubic::RootsValidT(A, B, C, D, roots); | 101 return SkDCubic::RootsValidT(A, B, C, D, roots); |
97 } | 102 } |
98 | 103 |
99 int intersect() { | 104 int intersect() { |
100 addEndPoints(); | 105 addExactEndPoints(); |
101 double rootVals[3]; | 106 double rootVals[3]; |
102 int roots = intersectRay(rootVals); | 107 int roots = intersectRay(rootVals); |
103 for (int index = 0; index < roots; ++index) { | 108 for (int index = 0; index < roots; ++index) { |
104 double cubicT = rootVals[index]; | 109 double cubicT = rootVals[index]; |
105 double lineT = findLineT(cubicT); | 110 double lineT = findLineT(cubicT); |
106 if (pinTs(&cubicT, &lineT)) { | 111 if (pinTs(&cubicT, &lineT)) { |
107 SkDPoint pt = line.xyAtT(lineT); | 112 SkDPoint pt = line.xyAtT(lineT); |
108 #if ONE_OFF_DEBUG | 113 #if ONE_OFF_DEBUG |
109 SkDPoint cPt = cubic.xyAtT(cubicT); | 114 SkDPoint cPt = cubic.xyAtT(cubicT); |
110 SkDebugf("%s pt=(%1.9g,%1.9g) cPt=(%1.9g,%1.9g)\n", __FUNCTION__, pt
.fX, pt.fY, | 115 SkDebugf("%s pt=(%1.9g,%1.9g) cPt=(%1.9g,%1.9g)\n", __FUNCTION__, pt
.fX, pt.fY, |
111 cPt.fX, cPt.fY); | 116 cPt.fX, cPt.fY); |
112 #endif | 117 #endif |
113 intersections.insert(cubicT, lineT, pt); | 118 intersections.insert(cubicT, lineT, pt); |
114 } | 119 } |
115 } | 120 } |
| 121 if (fAllowNear) { |
| 122 addNearEndPoints(); |
| 123 } |
116 return intersections.used(); | 124 return intersections.used(); |
117 } | 125 } |
118 | 126 |
119 int horizontalIntersect(double axisIntercept, double roots[3]) { | 127 int horizontalIntersect(double axisIntercept, double roots[3]) { |
120 double A, B, C, D; | 128 double A, B, C, D; |
121 SkDCubic::Coefficients(&cubic[0].fY, &A, &B, &C, &D); | 129 SkDCubic::Coefficients(&cubic[0].fY, &A, &B, &C, &D); |
122 D -= axisIntercept; | 130 D -= axisIntercept; |
123 return SkDCubic::RootsValidT(A, B, C, D, roots); | 131 return SkDCubic::RootsValidT(A, B, C, D, roots); |
124 } | 132 } |
125 | 133 |
126 int horizontalIntersect(double axisIntercept, double left, double right, bool fl
ipped) { | 134 int horizontalIntersect(double axisIntercept, double left, double right, bool fl
ipped) { |
127 addHorizontalEndPoints(left, right, axisIntercept); | 135 addExactHorizontalEndPoints(left, right, axisIntercept); |
128 double rootVals[3]; | 136 double rootVals[3]; |
129 int roots = horizontalIntersect(axisIntercept, rootVals); | 137 int roots = horizontalIntersect(axisIntercept, rootVals); |
130 for (int index = 0; index < roots; ++index) { | 138 for (int index = 0; index < roots; ++index) { |
131 double cubicT = rootVals[index]; | 139 double cubicT = rootVals[index]; |
132 SkDPoint pt = cubic.xyAtT(cubicT); | 140 SkDPoint pt = cubic.xyAtT(cubicT); |
133 double lineT = (pt.fX - left) / (right - left); | 141 double lineT = (pt.fX - left) / (right - left); |
134 if (pinTs(&cubicT, &lineT)) { | 142 if (pinTs(&cubicT, &lineT)) { |
135 intersections.insert(cubicT, lineT, pt); | 143 intersections.insert(cubicT, lineT, pt); |
136 } | 144 } |
137 } | 145 } |
| 146 if (fAllowNear) { |
| 147 addNearHorizontalEndPoints(left, right, axisIntercept); |
| 148 } |
138 if (flipped) { | 149 if (flipped) { |
139 intersections.flip(); | 150 intersections.flip(); |
140 } | 151 } |
141 return intersections.used(); | 152 return intersections.used(); |
142 } | 153 } |
143 | 154 |
144 int verticalIntersect(double axisIntercept, double roots[3]) { | 155 int verticalIntersect(double axisIntercept, double roots[3]) { |
145 double A, B, C, D; | 156 double A, B, C, D; |
146 SkDCubic::Coefficients(&cubic[0].fX, &A, &B, &C, &D); | 157 SkDCubic::Coefficients(&cubic[0].fX, &A, &B, &C, &D); |
147 D -= axisIntercept; | 158 D -= axisIntercept; |
148 return SkDCubic::RootsValidT(A, B, C, D, roots); | 159 return SkDCubic::RootsValidT(A, B, C, D, roots); |
149 } | 160 } |
150 | 161 |
151 int verticalIntersect(double axisIntercept, double top, double bottom, bool flip
ped) { | 162 int verticalIntersect(double axisIntercept, double top, double bottom, bool flip
ped) { |
152 addVerticalEndPoints(top, bottom, axisIntercept); | 163 addExactVerticalEndPoints(top, bottom, axisIntercept); |
153 double rootVals[3]; | 164 double rootVals[3]; |
154 int roots = verticalIntersect(axisIntercept, rootVals); | 165 int roots = verticalIntersect(axisIntercept, rootVals); |
155 for (int index = 0; index < roots; ++index) { | 166 for (int index = 0; index < roots; ++index) { |
156 double cubicT = rootVals[index]; | 167 double cubicT = rootVals[index]; |
157 SkDPoint pt = cubic.xyAtT(cubicT); | 168 SkDPoint pt = cubic.xyAtT(cubicT); |
158 double lineT = (pt.fY - top) / (bottom - top); | 169 double lineT = (pt.fY - top) / (bottom - top); |
159 if (pinTs(&cubicT, &lineT)) { | 170 if (pinTs(&cubicT, &lineT)) { |
160 intersections.insert(cubicT, lineT, pt); | 171 intersections.insert(cubicT, lineT, pt); |
161 } | 172 } |
162 } | 173 } |
| 174 if (fAllowNear) { |
| 175 addNearVerticalEndPoints(top, bottom, axisIntercept); |
| 176 } |
163 if (flipped) { | 177 if (flipped) { |
164 intersections.flip(); | 178 intersections.flip(); |
165 } | 179 } |
166 return intersections.used(); | 180 return intersections.used(); |
167 } | 181 } |
168 | 182 |
169 protected: | 183 protected: |
170 | 184 |
171 void addEndPoints() { | 185 void addExactEndPoints() { |
172 for (int cIndex = 0; cIndex < 4; cIndex += 3) { | 186 for (int cIndex = 0; cIndex < 4; cIndex += 3) { |
173 bool foundEnd = false; | 187 double lineT = line.exactPoint(cubic[cIndex]); |
174 for (int lIndex = 0; lIndex < 2; lIndex++) { | 188 if (lineT < 0) { |
175 if (cubic[cIndex] == line[lIndex]) { | |
176 intersections.insert(cIndex >> 1, lIndex, line[lIndex]); | |
177 foundEnd = true; | |
178 } | |
179 } | |
180 // for the test case this was written for, the dist / error ratio was 17
0.6667 | |
181 // it looks like the cubic stops short of touching the line, but this fi
xed it. | |
182 if (foundEnd) { | |
183 continue; | 189 continue; |
184 } | 190 } |
185 // See if the cubic end touches the line. | 191 double cubicT = (double) (cIndex >> 1); |
186 double dist = line.isLeft(cubic[cIndex]); // this distance isn't cartesi
an | 192 intersections.insert(cubicT, lineT, cubic[cIndex]); |
187 SkDVector lineLen = line[1] - line[0]; // the x/y magnitudes of the line | |
188 // compute the ULPS of the larger of the x/y deltas | |
189 double larger = SkTMax(SkTAbs(lineLen.fX), SkTAbs(lineLen.fY)); | |
190 if (!RoughlyEqualUlps(larger, larger + dist)) { // is the dist within UL
PS tolerance? | |
191 continue; | |
192 } | |
193 double lineT = findLineT(cIndex >> 1); | |
194 if (!between(0, lineT, 1)) { | |
195 continue; | |
196 } | |
197 SkDPoint linePt = line.xyAtT(lineT); | |
198 if (linePt.approximatelyEqual(cubic[cIndex])) { | |
199 intersections.insert(cIndex >> 1, lineT, cubic[cIndex]); | |
200 } | |
201 } | 193 } |
202 } | 194 } |
203 | 195 |
204 void addHorizontalEndPoints(double left, double right, double y) { | 196 void addNearEndPoints() { |
205 for (int cIndex = 0; cIndex < 4; cIndex += 3) { | 197 for (int cIndex = 0; cIndex < 4; cIndex += 3) { |
206 if (cubic[cIndex].fY != y) { | 198 double cubicT = (double) (cIndex >> 1); |
| 199 if (intersections.hasT(cubicT)) { |
207 continue; | 200 continue; |
208 } | 201 } |
209 if (cubic[cIndex].fX == left) { | 202 double lineT = line.nearPoint(cubic[cIndex]); |
210 intersections.insert(cIndex >> 1, 0, cubic[cIndex]); | 203 if (lineT < 0) { |
| 204 continue; |
211 } | 205 } |
212 if (cubic[cIndex].fX == right) { | 206 intersections.insert(cubicT, lineT, cubic[cIndex]); |
213 intersections.insert(cIndex >> 1, 1, cubic[cIndex]); | |
214 } | |
215 } | 207 } |
216 } | 208 } |
217 | 209 |
218 void addVerticalEndPoints(double top, double bottom, double x) { | 210 void addExactHorizontalEndPoints(double left, double right, double y) { |
219 for (int cIndex = 0; cIndex < 4; cIndex += 3) { | 211 for (int cIndex = 0; cIndex < 4; cIndex += 3) { |
220 if (cubic[cIndex].fX != x) { | 212 double lineT = SkDLine::ExactPointH(cubic[cIndex], left, right, y); |
| 213 if (lineT < 0) { |
221 continue; | 214 continue; |
222 } | 215 } |
223 if (cubic[cIndex].fY == top) { | 216 double cubicT = (double) (cIndex >> 1); |
224 intersections.insert(cIndex >> 1, 0, cubic[cIndex]); | 217 intersections.insert(cubicT, lineT, cubic[cIndex]); |
225 } | |
226 if (cubic[cIndex].fY == bottom) { | |
227 intersections.insert(cIndex >> 1, 1, cubic[cIndex]); | |
228 } | |
229 } | 218 } |
230 } | 219 } |
231 | 220 |
| 221 void addNearHorizontalEndPoints(double left, double right, double y) { |
| 222 for (int cIndex = 0; cIndex < 4; cIndex += 3) { |
| 223 double cubicT = (double) (cIndex >> 1); |
| 224 if (intersections.hasT(cubicT)) { |
| 225 continue; |
| 226 } |
| 227 double lineT = SkDLine::NearPointH(cubic[cIndex], left, right, y); |
| 228 if (lineT < 0) { |
| 229 continue; |
| 230 } |
| 231 intersections.insert(cubicT, lineT, cubic[cIndex]); |
| 232 } |
| 233 // FIXME: see if line end is nearly on cubic |
| 234 } |
| 235 |
| 236 void addExactVerticalEndPoints(double top, double bottom, double x) { |
| 237 for (int cIndex = 0; cIndex < 4; cIndex += 3) { |
| 238 double lineT = SkDLine::ExactPointV(cubic[cIndex], top, bottom, x); |
| 239 if (lineT < 0) { |
| 240 continue; |
| 241 } |
| 242 double cubicT = (double) (cIndex >> 1); |
| 243 intersections.insert(cubicT, lineT, cubic[cIndex]); |
| 244 } |
| 245 } |
| 246 |
| 247 void addNearVerticalEndPoints(double top, double bottom, double x) { |
| 248 for (int cIndex = 0; cIndex < 4; cIndex += 3) { |
| 249 double cubicT = (double) (cIndex >> 1); |
| 250 if (intersections.hasT(cubicT)) { |
| 251 continue; |
| 252 } |
| 253 double lineT = SkDLine::NearPointV(cubic[cIndex], top, bottom, x); |
| 254 if (lineT < 0) { |
| 255 continue; |
| 256 } |
| 257 intersections.insert(cubicT, lineT, cubic[cIndex]); |
| 258 } |
| 259 // FIXME: see if line end is nearly on cubic |
| 260 } |
| 261 |
232 double findLineT(double t) { | 262 double findLineT(double t) { |
233 SkDPoint xy = cubic.xyAtT(t); | 263 SkDPoint xy = cubic.xyAtT(t); |
234 double dx = line[1].fX - line[0].fX; | 264 double dx = line[1].fX - line[0].fX; |
235 double dy = line[1].fY - line[0].fY; | 265 double dy = line[1].fY - line[0].fY; |
236 if (fabs(dx) > fabs(dy)) { | 266 if (fabs(dx) > fabs(dy)) { |
237 return (xy.fX - line[0].fX) / dx; | 267 return (xy.fX - line[0].fX) / dx; |
238 } | 268 } |
239 return (xy.fY - line[0].fY) / dy; | 269 return (xy.fY - line[0].fY) / dy; |
240 } | 270 } |
241 | 271 |
(...skipping 15 matching lines...) Expand all Loading... |
257 *lineT = 1; | 287 *lineT = 1; |
258 } | 288 } |
259 return true; | 289 return true; |
260 } | 290 } |
261 | 291 |
262 private: | 292 private: |
263 | 293 |
264 const SkDCubic& cubic; | 294 const SkDCubic& cubic; |
265 const SkDLine& line; | 295 const SkDLine& line; |
266 SkIntersections& intersections; | 296 SkIntersections& intersections; |
| 297 bool fAllowNear; |
267 }; | 298 }; |
268 | 299 |
269 int SkIntersections::horizontal(const SkDCubic& cubic, double left, double right
, double y, | 300 int SkIntersections::horizontal(const SkDCubic& cubic, double left, double right
, double y, |
270 bool flipped) { | 301 bool flipped) { |
271 LineCubicIntersections c(cubic, *(static_cast<SkDLine*>(0)), *this); | 302 LineCubicIntersections c(cubic, *(static_cast<SkDLine*>(0)), *this); |
272 return c.horizontalIntersect(y, left, right, flipped); | 303 return c.horizontalIntersect(y, left, right, flipped); |
273 } | 304 } |
274 | 305 |
275 int SkIntersections::vertical(const SkDCubic& cubic, double top, double bottom,
double x, | 306 int SkIntersections::vertical(const SkDCubic& cubic, double top, double bottom,
double x, |
276 bool flipped) { | 307 bool flipped) { |
277 LineCubicIntersections c(cubic, *(static_cast<SkDLine*>(0)), *this); | 308 LineCubicIntersections c(cubic, *(static_cast<SkDLine*>(0)), *this); |
278 return c.verticalIntersect(x, top, bottom, flipped); | 309 return c.verticalIntersect(x, top, bottom, flipped); |
279 } | 310 } |
280 | 311 |
281 int SkIntersections::intersect(const SkDCubic& cubic, const SkDLine& line) { | 312 int SkIntersections::intersect(const SkDCubic& cubic, const SkDLine& line) { |
282 LineCubicIntersections c(cubic, line, *this); | 313 LineCubicIntersections c(cubic, line, *this); |
| 314 c.allowNear(fAllowNear); |
283 return c.intersect(); | 315 return c.intersect(); |
284 } | 316 } |
285 | 317 |
286 int SkIntersections::intersectRay(const SkDCubic& cubic, const SkDLine& line) { | 318 int SkIntersections::intersectRay(const SkDCubic& cubic, const SkDLine& line) { |
287 LineCubicIntersections c(cubic, line, *this); | 319 LineCubicIntersections c(cubic, line, *this); |
288 fUsed = c.intersectRay(fT[0]); | 320 fUsed = c.intersectRay(fT[0]); |
289 for (int index = 0; index < fUsed; ++index) { | 321 for (int index = 0; index < fUsed; ++index) { |
290 fPt[index] = cubic.xyAtT(fT[0][index]); | 322 fPt[index] = cubic.xyAtT(fT[0][index]); |
291 } | 323 } |
292 return fUsed; | 324 return fUsed; |
293 } | 325 } |
OLD | NEW |