Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/pathops/SkDConicLineIntersection.cpp

Issue 1037953004: add conics to path ops (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: fix linux build Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2015 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 #include "SkIntersections.h"
8 #include "SkPathOpsConic.h"
9 #include "SkPathOpsLine.h"
10
11 class LineConicIntersections {
12 public:
13 enum PinTPoint {
14 kPointUninitialized,
15 kPointInitialized
16 };
17
18 LineConicIntersections(const SkDConic& c, const SkDLine& l, SkIntersections* i)
19 : fConic(c)
20 , fLine(l)
21 , fIntersections(i)
22 , fAllowNear(true) {
23 i->setMax(3); // allow short partial coincidence plus discrete intersec tion
24 }
25
26 void allowNear(bool allow) {
27 fAllowNear = allow;
28 }
29
30 void checkCoincident() {
31 int last = fIntersections->used() - 1;
32 for (int index = 0; index < last; ) {
33 double conicMidT = ((*fIntersections)[0][index] + (*fIntersections)[ 0][index + 1]) / 2;
34 SkDPoint conicMidPt = fConic.ptAtT(conicMidT);
35 double t = fLine.nearPoint(conicMidPt, NULL);
36 if (t < 0) {
37 ++index;
38 continue;
39 }
40 if (fIntersections->isCoincident(index)) {
41 fIntersections->removeOne(index);
42 --last;
43 } else if (fIntersections->isCoincident(index + 1)) {
44 fIntersections->removeOne(index + 1);
45 --last;
46 } else {
47 fIntersections->setCoincident(index++);
48 }
49 fIntersections->setCoincident(index);
50 }
51 }
52
53 #ifdef SK_DEBUG
54 static bool close_to(double a, double b, const double c[3]) {
55 double max = SkTMax(-SkTMin(SkTMin(c[0], c[1]), c[2]), SkTMax(SkTMax(c[0 ], c[1]), c[2]));
56 return approximately_zero_when_compared_to(a - b, max);
57 }
58 #endif
59
60 int horizontalIntersect(double axisIntercept, double left, double right, boo l flipped) {
61 this->addExactHorizontalEndPoints(left, right, axisIntercept);
62 if (fAllowNear) {
63 this->addNearHorizontalEndPoints(left, right, axisIntercept);
64 }
65 double roots[2];
66 double conicVals[] = { fConic[0].fY, fConic[1].fY, fConic[2].fY };
67 int count = this->validT(conicVals, axisIntercept, roots);
68 for (int index = 0; index < count; ++index) {
69 double conicT = roots[index];
70 SkDPoint pt = fConic.ptAtT(conicT);
71 SkASSERT(close_to(pt.fY, axisIntercept, conicVals));
72 double lineT = (pt.fX - left) / (right - left);
73 if (this->pinTs(&conicT, &lineT, &pt, kPointInitialized)
74 && this->uniqueAnswer(conicT, pt)) {
75 fIntersections->insert(conicT, lineT, pt);
76 }
77 }
78 if (flipped) {
79 fIntersections->flip();
80 }
81 this->checkCoincident();
82 return fIntersections->used();
83 }
84
85 int intersect() {
86 this->addExactEndPoints();
87 if (fAllowNear) {
88 this->addNearEndPoints();
89 }
90 double rootVals[2];
91 int roots = this->intersectRay(rootVals);
92 for (int index = 0; index < roots; ++index) {
93 double conicT = rootVals[index];
94 double lineT = this->findLineT(conicT);
95 SkDEBUGCODE(SkDPoint conicPt = fConic.ptAtT(conicT));
96 SkDEBUGCODE(SkDPoint linePt = fLine.ptAtT(lineT));
97 SkASSERT(conicPt.approximatelyEqual(linePt));
98 SkDPoint pt;
99 if (this->pinTs(&conicT, &lineT, &pt, kPointUninitialized)
100 && this->uniqueAnswer(conicT, pt)) {
101 fIntersections->insert(conicT, lineT, pt);
102 }
103 }
104 this->checkCoincident();
105 return fIntersections->used();
106 }
107
108 int intersectRay(double roots[2]) {
109 double adj = fLine[1].fX - fLine[0].fX;
110 double opp = fLine[1].fY - fLine[0].fY;
111 double r[3];
112 for (int n = 0; n < 3; ++n) {
113 r[n] = (fConic[n].fY - fLine[0].fY) * adj - (fConic[n].fX - fLine[0] .fX) * opp;
114 }
115 return this->validT(r, 0, roots);
116 }
117
118 int validT(double r[3], double axisIntercept, double roots[2]) {
119 double A = r[2];
120 double B = r[1] * fConic.fWeight - axisIntercept * fConic.fWeight + axis Intercept;
121 double C = r[0];
122 A += C - 2 * B; // A = a + c - 2*(b*w - xCept*w + xCept)
123 B -= C; // B = b*w - w * xCept + xCept - a
124 C -= axisIntercept;
125 return SkDQuad::RootsValidT(A, 2 * B, C, roots);
126 }
127
128 int verticalIntersect(double axisIntercept, double top, double bottom, bool flipped) {
129 this->addExactVerticalEndPoints(top, bottom, axisIntercept);
130 if (fAllowNear) {
131 this->addNearVerticalEndPoints(top, bottom, axisIntercept);
132 }
133 double roots[2];
134 double conicVals[] = { fConic[0].fX, fConic[1].fX, fConic[2].fX };
135 int count = this->validT(conicVals, axisIntercept, roots);
136 for (int index = 0; index < count; ++index) {
137 double conicT = roots[index];
138 SkDPoint pt = fConic.ptAtT(conicT);
139 SkASSERT(close_to(pt.fX, axisIntercept, conicVals));
140 double lineT = (pt.fY - top) / (bottom - top);
141 if (this->pinTs(&conicT, &lineT, &pt, kPointInitialized)
142 && this->uniqueAnswer(conicT, pt)) {
143 fIntersections->insert(conicT, lineT, pt);
144 }
145 }
146 if (flipped) {
147 fIntersections->flip();
148 }
149 this->checkCoincident();
150 return fIntersections->used();
151 }
152
153 protected:
154 // OPTIMIZE: Functions of the form add .. points are indentical to the conic rou tines.
155 // add endpoints first to get zero and one t values exactly
156 void addExactEndPoints() {
157 for (int cIndex = 0; cIndex < SkDConic::kPointCount; cIndex += SkDConic: :kPointLast) {
158 double lineT = fLine.exactPoint(fConic[cIndex]);
159 if (lineT < 0) {
160 continue;
161 }
162 double conicT = (double) (cIndex >> 1);
163 fIntersections->insert(conicT, lineT, fConic[cIndex]);
164 }
165 }
166
167 void addNearEndPoints() {
168 for (int cIndex = 0; cIndex < SkDConic::kPointCount; cIndex += SkDConic: :kPointLast) {
169 double conicT = (double) (cIndex >> 1);
170 if (fIntersections->hasT(conicT)) {
171 continue;
172 }
173 double lineT = fLine.nearPoint(fConic[cIndex], NULL);
174 if (lineT < 0) {
175 continue;
176 }
177 fIntersections->insert(conicT, lineT, fConic[cIndex]);
178 }
179 // FIXME: see if line end is nearly on conic
180 }
181
182 void addExactHorizontalEndPoints(double left, double right, double y) {
183 for (int cIndex = 0; cIndex < SkDConic::kPointCount; cIndex += SkDConic: :kPointLast) {
184 double lineT = SkDLine::ExactPointH(fConic[cIndex], left, right, y);
185 if (lineT < 0) {
186 continue;
187 }
188 double conicT = (double) (cIndex >> 1);
189 fIntersections->insert(conicT, lineT, fConic[cIndex]);
190 }
191 }
192
193 void addNearHorizontalEndPoints(double left, double right, double y) {
194 for (int cIndex = 0; cIndex < SkDConic::kPointCount; cIndex += SkDConic: :kPointLast) {
195 double conicT = (double) (cIndex >> 1);
196 if (fIntersections->hasT(conicT)) {
197 continue;
198 }
199 double lineT = SkDLine::NearPointH(fConic[cIndex], left, right, y);
200 if (lineT < 0) {
201 continue;
202 }
203 fIntersections->insert(conicT, lineT, fConic[cIndex]);
204 }
205 // FIXME: see if line end is nearly on conic
206 }
207
208 void addExactVerticalEndPoints(double top, double bottom, double x) {
209 for (int cIndex = 0; cIndex < SkDConic::kPointCount; cIndex += SkDConic: :kPointLast) {
210 double lineT = SkDLine::ExactPointV(fConic[cIndex], top, bottom, x);
211 if (lineT < 0) {
212 continue;
213 }
214 double conicT = (double) (cIndex >> 1);
215 fIntersections->insert(conicT, lineT, fConic[cIndex]);
216 }
217 }
218
219 void addNearVerticalEndPoints(double top, double bottom, double x) {
220 for (int cIndex = 0; cIndex < SkDConic::kPointCount; cIndex += SkDConic: :kPointLast) {
221 double conicT = (double) (cIndex >> 1);
222 if (fIntersections->hasT(conicT)) {
223 continue;
224 }
225 double lineT = SkDLine::NearPointV(fConic[cIndex], top, bottom, x);
226 if (lineT < 0) {
227 continue;
228 }
229 fIntersections->insert(conicT, lineT, fConic[cIndex]);
230 }
231 // FIXME: see if line end is nearly on conic
232 }
233
234 double findLineT(double t) {
235 SkDPoint xy = fConic.ptAtT(t);
236 double dx = fLine[1].fX - fLine[0].fX;
237 double dy = fLine[1].fY - fLine[0].fY;
238 if (fabs(dx) > fabs(dy)) {
239 return (xy.fX - fLine[0].fX) / dx;
240 }
241 return (xy.fY - fLine[0].fY) / dy;
242 }
243
244 bool pinTs(double* conicT, double* lineT, SkDPoint* pt, PinTPoint ptSet) {
245 if (!approximately_one_or_less_double(*lineT)) {
246 return false;
247 }
248 if (!approximately_zero_or_more_double(*lineT)) {
249 return false;
250 }
251 double qT = *conicT = SkPinT(*conicT);
252 double lT = *lineT = SkPinT(*lineT);
253 if (lT == 0 || lT == 1 || (ptSet == kPointUninitialized && qT != 0 && qT != 1)) {
254 *pt = fLine.ptAtT(lT);
255 } else if (ptSet == kPointUninitialized) {
256 *pt = fConic.ptAtT(qT);
257 }
258 SkPoint gridPt = pt->asSkPoint();
259 if (SkDPoint::ApproximatelyEqual(gridPt, fLine[0].asSkPoint())) {
260 *pt = fLine[0];
261 *lineT = 0;
262 } else if (SkDPoint::ApproximatelyEqual(gridPt, fLine[1].asSkPoint())) {
263 *pt = fLine[1];
264 *lineT = 1;
265 }
266 if (fIntersections->used() > 0 && approximately_equal((*fIntersections)[ 1][0], *lineT)) {
267 return false;
268 }
269 if (gridPt == fConic[0].asSkPoint()) {
270 *pt = fConic[0];
271 *conicT = 0;
272 } else if (gridPt == fConic[2].asSkPoint()) {
273 *pt = fConic[2];
274 *conicT = 1;
275 }
276 return true;
277 }
278
279 bool uniqueAnswer(double conicT, const SkDPoint& pt) {
280 for (int inner = 0; inner < fIntersections->used(); ++inner) {
281 if (fIntersections->pt(inner) != pt) {
282 continue;
283 }
284 double existingConicT = (*fIntersections)[0][inner];
285 if (conicT == existingConicT) {
286 return false;
287 }
288 // check if midway on conic is also same point. If so, discard this
289 double conicMidT = (existingConicT + conicT) / 2;
290 SkDPoint conicMidPt = fConic.ptAtT(conicMidT);
291 if (conicMidPt.approximatelyEqual(pt)) {
292 return false;
293 }
294 }
295 #if ONE_OFF_DEBUG
296 SkDPoint qPt = fConic.ptAtT(conicT);
297 SkDebugf("%s pt=(%1.9g,%1.9g) cPt=(%1.9g,%1.9g)\n", __FUNCTION__, pt.fX, pt.fY,
298 qPt.fX, qPt.fY);
299 #endif
300 return true;
301 }
302
303 private:
304 const SkDConic& fConic;
305 const SkDLine& fLine;
306 SkIntersections* fIntersections;
307 bool fAllowNear;
308 };
309
310 int SkIntersections::horizontal(const SkDConic& conic, double left, double right , double y,
311 bool flipped) {
312 SkDLine line = {{{ left, y }, { right, y }}};
313 LineConicIntersections c(conic, line, this);
314 return c.horizontalIntersect(y, left, right, flipped);
315 }
316
317 int SkIntersections::vertical(const SkDConic& conic, double top, double bottom, double x,
318 bool flipped) {
319 SkDLine line = {{{ x, top }, { x, bottom }}};
320 LineConicIntersections c(conic, line, this);
321 return c.verticalIntersect(x, top, bottom, flipped);
322 }
323
324 int SkIntersections::intersect(const SkDConic& conic, const SkDLine& line) {
325 LineConicIntersections c(conic, line, this);
326 c.allowNear(fAllowNear);
327 return c.intersect();
328 }
329
330 int SkIntersections::intersectRay(const SkDConic& conic, const SkDLine& line) {
331 LineConicIntersections c(conic, line, this);
332 fUsed = c.intersectRay(fT[0]);
333 for (int index = 0; index < fUsed; ++index) {
334 fPt[index] = conic.ptAtT(fT[0][index]);
335 }
336 return fUsed;
337 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698