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

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

Issue 21359002: path ops work in progress (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: remove space Created 7 years, 3 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 | Annotate | Revision Log
« no previous file with comments | « src/pathops/SkOpAngle.h ('k') | src/pathops/SkOpContour.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "SkOpAngle.h" 8 #include "SkOpAngle.h"
9 #include "SkOpSegment.h" 9 #include "SkOpSegment.h"
10 #include "SkPathOpsCurve.h" 10 #include "SkPathOpsCurve.h"
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
113 SkOpAngle rhLonger = rh; 113 SkOpAngle rhLonger = rh;
114 if ((longer.lengthen(rh) | rhLonger.lengthen(*this)) // lengthen both 114 if ((longer.lengthen(rh) | rhLonger.lengthen(*this)) // lengthen both
115 && (fUnorderable || !longer.fUnorderable) 115 && (fUnorderable || !longer.fUnorderable)
116 && (rh.fUnorderable || !rhLonger.fUnorderable)) { 116 && (rh.fUnorderable || !rhLonger.fUnorderable)) {
117 #if DEBUG_ANGLE 117 #if DEBUG_ANGLE
118 bugOut.prepend(" "); 118 bugOut.prepend(" ");
119 #endif 119 #endif
120 return COMPARE_RESULT("10 longer.lengthen(rh) ...", longer < rhLonge r); 120 return COMPARE_RESULT("10 longer.lengthen(rh) ...", longer < rhLonge r);
121 } 121 }
122 } 122 }
123 SkPath::Verb verb = fSegment->verb();
124 SkPath::Verb rVerb = rh.fSegment->verb();
123 if (y_ry != 0) { // if they aren't coincident, look for a stable cross produ ct 125 if (y_ry != 0) { // if they aren't coincident, look for a stable cross produ ct
124 // at this point, y's are the same sign, neither is zero 126 // at this point, y's are the same sign, neither is zero
125 // and x's are the same sign, or one (or both) is zero 127 // and x's are the same sign, or one (or both) is zero
126 double x_ry = x * ry; 128 double x_ry = x * ry;
127 double rx_y = rx * y; 129 double rx_y = rx * y;
128 if (!fComputed && !rh.fComputed) { 130 if (!fComputed && !rh.fComputed) {
129 if (!AlmostEqualUlps(x_ry, rx_y)) { 131 if (!SkDLine::NearRay(x, y, rx, ry) && x_ry != rx_y) {
130 return COMPARE_RESULT("7 !fComputed && !rh.fComputed", x_ry < rx _y); 132 return COMPARE_RESULT("7 !fComputed && !rh.fComputed", x_ry < rx _y);
131 } 133 }
132 } else { 134 } else {
133 // if the vector was a result of subdividing a curve, see if it is s table 135 // if the vector was a result of subdividing a curve, see if it is s table
134 bool sloppy1 = x_ry < rx_y; 136 bool sloppy1 = x_ry < rx_y;
135 bool sloppy2 = !sloppy1; 137 bool sloppy2 = !sloppy1;
136 if ((!fComputed || calcSlop(x, y, rx, ry, &sloppy1)) 138 if ((!fComputed || calcSlop(x, y, rx, ry, &sloppy1))
137 && (!rh.fComputed || rh.calcSlop(rx, ry, x, y, &sloppy2)) 139 && (!rh.fComputed || rh.calcSlop(rx, ry, x, y, &sloppy2))
138 && sloppy1 != sloppy2) { 140 && sloppy1 != sloppy2) {
139 return COMPARE_RESULT("8 CalcSlop(x, y ...", sloppy1); 141 return COMPARE_RESULT("8 CalcSlop(x, y ...", sloppy1);
140 } 142 }
141 } 143 }
142 } 144 }
143 if (fSide * rh.fSide == 0) { 145 if (fSide2 * rh.fSide2 == 0) {
144 SkASSERT(fSide + rh.fSide != 0); // hitting this assert means coincidenc e was undetected 146 // SkASSERT(fSide2 + rh.fSide2 != 0); // hitting this assert means coinci dence was undetected
145 return COMPARE_RESULT("9 fSide * rh.fSide == 0 ...", fSide < rh.fSide); 147 return COMPARE_RESULT("9a fSide2 * rh.fSide2 == 0 ...", fSide2 < rh.fSid e2);
146 } 148 }
147 // at this point, the initial tangent line is nearly coincident 149 // at this point, the initial tangent line is nearly coincident
148 // see if edges curl away from each other 150 // see if edges curl away from each other
149 if (fSide * rh.fSide < 0 && (!approximately_zero(fSide) || !approximately_ze ro(rh.fSide))) { 151 if (fSide * rh.fSide < 0 && (!approximately_zero(fSide) || !approximately_ze ro(rh.fSide))) {
150 return COMPARE_RESULT("9b fSide * rh.fSide < 0 ...", fSide < rh.fSide); 152 return COMPARE_RESULT("9b fSide * rh.fSide < 0 ...", fSide < rh.fSide);
151 } 153 }
152 if (fUnsortable || rh.fUnsortable) { 154 if (fUnsortable || rh.fUnsortable) {
153 // even with no solution, return a stable sort 155 // even with no solution, return a stable sort
154 return COMPARE_RESULT("11 fUnsortable || rh.fUnsortable", this < &rh); 156 return COMPARE_RESULT("11 fUnsortable || rh.fUnsortable", this < &rh);
155 } 157 }
156 SkPath::Verb verb = fSegment->verb();
157 SkPath::Verb rVerb = rh.fSegment->verb();
158 if ((verb == SkPath::kLine_Verb && approximately_zero(y) && approximately_ze ro(x)) 158 if ((verb == SkPath::kLine_Verb && approximately_zero(y) && approximately_ze ro(x))
159 || (rVerb == SkPath::kLine_Verb 159 || (rVerb == SkPath::kLine_Verb
160 && approximately_zero(ry) && approximately_zero(rx))) { 160 && approximately_zero(ry) && approximately_zero(rx))) {
161 // See general unsortable comment below. This case can happen when 161 // See general unsortable comment below. This case can happen when
162 // one line has a non-zero change in t but no change in x and y. 162 // one line has a non-zero change in t but no change in x and y.
163 fUnsortable = true; 163 fUnsortable = true;
164 return COMPARE_RESULT("12 verb == SkPath::kLine_Verb ...", this < &rh); 164 return COMPARE_RESULT("12 verb == SkPath::kLine_Verb ...", this < &rh);
165 } 165 }
166 if (fSegment->isTiny(this) || rh.fSegment->isTiny(&rh)) { 166 if (fSegment->isTiny(this) || rh.fSegment->isTiny(&rh)) {
167 fUnsortable = true; 167 fUnsortable = true;
168 return COMPARE_RESULT("13 verb == fSegment->isTiny(this) ...", this < &r h); 168 return COMPARE_RESULT("13 verb == fSegment->isTiny(this) ...", this < &r h);
169 } 169 }
170 SkASSERT(verb >= SkPath::kQuad_Verb); 170 SkASSERT(verb >= SkPath::kQuad_Verb);
171 SkASSERT(rVerb >= SkPath::kQuad_Verb); 171 SkASSERT(rVerb >= SkPath::kQuad_Verb);
172 // FIXME: until I can think of something better, project a ray from the 172 // FIXME: until I can think of something better, project a ray from the
173 // end of the shorter tangent to midway between the end points 173 // end of the shorter tangent to midway between the end points
174 // through both curves and use the resulting angle to sort 174 // through both curves and use the resulting angle to sort
175 // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive 175 // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
176 double len = fTangent1.normalSquared(); 176 double len = fTangentPart.normalSquared();
177 double rlen = rh.fTangent1.normalSquared(); 177 double rlen = rh.fTangentPart.normalSquared();
178 SkDLine ray; 178 SkDLine ray;
179 SkIntersections i, ri; 179 SkIntersections i, ri;
180 int roots, rroots; 180 int roots, rroots;
181 bool flip = false; 181 bool flip = false;
182 bool useThis; 182 bool useThis;
183 bool leftLessThanRight = fSide > 0; 183 bool leftLessThanRight = fSide > 0;
184 do { 184 do {
185 useThis = (len < rlen) ^ flip; 185 useThis = (len < rlen) ^ flip;
186 const SkDCubic& part = useThis ? fCurvePart : rh.fCurvePart; 186 const SkDCubic& part = useThis ? fCurvePart : rh.fCurvePart;
187 SkPath::Verb partVerb = useThis ? verb : rVerb; 187 SkPath::Verb partVerb = useThis ? verb : rVerb;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 } 262 }
263 263
264 void SkOpAngle::set(const SkOpSegment* segment, int start, int end) { 264 void SkOpAngle::set(const SkOpSegment* segment, int start, int end) {
265 fSegment = segment; 265 fSegment = segment;
266 fStart = start; 266 fStart = start;
267 fEnd = end; 267 fEnd = end;
268 setSpans(); 268 setSpans();
269 } 269 }
270 270
271 void SkOpAngle::setSpans() { 271 void SkOpAngle::setSpans() {
272 fUnorderable = false; 272 fUnorderable = fSegment->isTiny(this);
273 if (fSegment->verb() == SkPath::kLine_Verb) { 273 fLastMarked = NULL;
274 fUnsortable = false; 274 fUnsortable = false;
275 } else { 275 const SkPoint* pts = fSegment->pts();
276 // if start-1 exists and is tiny, then start pt may have moved 276 if (fSegment->verb() != SkPath::kLine_Verb) {
277 int smaller = SkMin32(fStart, fEnd); 277 fComputed = fSegment->subDivide(fStart, fEnd, &fCurvePart);
278 int tinyCheck = smaller; 278 fSegment->subDivide(fStart, fStart < fEnd ? fSegment->count() - 1 : 0, & fCurveHalf);
279 while (tinyCheck > 0 && fSegment->isTiny(tinyCheck - 1)) {
280 --tinyCheck;
281 }
282 if ((fUnsortable = smaller > 0 && tinyCheck == 0)) {
283 return;
284 }
285 int larger = SkMax32(fStart, fEnd);
286 tinyCheck = larger;
287 int max = fSegment->count() - 1;
288 while (tinyCheck < max && fSegment->isTiny(tinyCheck + 1)) {
289 ++tinyCheck;
290 }
291 if ((fUnsortable = larger < max && tinyCheck == max)) {
292 return;
293 }
294 } 279 }
295 fComputed = fSegment->subDivide(fStart, fEnd, &fCurvePart);
296 // FIXME: slight errors in subdivision cause sort trouble later on. As an ex periment, try 280 // FIXME: slight errors in subdivision cause sort trouble later on. As an ex periment, try
297 // rounding the curve part to float precision here 281 // rounding the curve part to float precision here
298 // fCurvePart.round(fSegment->verb()); 282 // fCurvePart.round(fSegment->verb());
299 switch (fSegment->verb()) { 283 switch (fSegment->verb()) {
300 case SkPath::kLine_Verb: { 284 case SkPath::kLine_Verb: {
301 // OPTIMIZATION: for pure line compares, we never need fTangent1.c 285 SkASSERT(fStart != fEnd);
302 fTangent1.lineEndPoints(*SkTCast<SkDLine*>(&fCurvePart)); 286 fCurvePart[0].set(pts[fStart > fEnd]);
287 fCurvePart[1].set(pts[fStart < fEnd]);
288 fComputed = false;
289 // OPTIMIZATION: for pure line compares, we never need fTangentPart.c
290 fTangentPart.lineEndPoints(*SkTCast<SkDLine*>(&fCurvePart));
303 fSide = 0; 291 fSide = 0;
292 fSide2 = 0;
304 } break; 293 } break;
305 case SkPath::kQuad_Verb: { 294 case SkPath::kQuad_Verb: {
295 fSide2 = -fTangentHalf.quadPart(*SkTCast<SkDQuad*>(&fCurveHalf));
306 SkDQuad& quad = *SkTCast<SkDQuad*>(&fCurvePart); 296 SkDQuad& quad = *SkTCast<SkDQuad*>(&fCurvePart);
307 fTangent1.quadEndPoints(quad); 297 fTangentPart.quadEndPoints(quad);
308 fSide = -fTangent1.pointDistance(fCurvePart[2]); // not normalized -- c ompare sign only 298 fSide = -fTangentPart.pointDistance(fCurvePart[2]); // not normalized - - compare sign only
309 if (fComputed && dx() > 0 && approximately_zero(dy())) { 299 if (fComputed && dx() > 0 && approximately_zero(dy())) {
310 SkDCubic origCurve; // can't use segment's curve in place since it m ay be flipped 300 SkDCubic origCurve; // can't use segment's curve in place since it m ay be flipped
311 int last = fSegment->count() - 1; 301 int last = fSegment->count() - 1;
312 fSegment->subDivide(fStart < fEnd ? 0 : last, fStart < fEnd ? last : 0, &origCurve); 302 fSegment->subDivide(fStart < fEnd ? 0 : last, fStart < fEnd ? last : 0, &origCurve);
313 SkLineParameters origTan; 303 SkLineParameters origTan;
314 origTan.quadEndPoints(*SkTCast<SkDQuad*>(&origCurve)); 304 origTan.quadEndPoints(*SkTCast<SkDQuad*>(&origCurve));
315 if ((fUnorderable = origTan.dx() <= 0 305 if (origTan.dx() <= 0
316 || (dy() != origTan.dy() && dy() * origTan.dy() <= 0))) { // signs match? 306 || (dy() != origTan.dy() && dy() * origTan.dy() <= 0)) { // signs match?
307 fUnorderable = true;
317 return; 308 return;
318 } 309 }
319 } 310 }
320 } break; 311 } break;
321 case SkPath::kCubic_Verb: { 312 case SkPath::kCubic_Verb: {
322 fTangent1.cubicEndPoints(fCurvePart); 313 double startT = fSegment->t(fStart);
314 fSide2 = -fTangentHalf.cubicPart(fCurveHalf);
315 fTangentPart.cubicEndPoints(fCurvePart);
323 double testTs[4]; 316 double testTs[4];
324 // OPTIMIZATION: keep inflections precomputed with cubic segment? 317 // OPTIMIZATION: keep inflections precomputed with cubic segment?
325 const SkPoint* pts = fSegment->pts();
326 int testCount = SkDCubic::FindInflections(pts, testTs); 318 int testCount = SkDCubic::FindInflections(pts, testTs);
327 double startT = fSegment->t(fStart);
328 double endT = fSegment->t(fEnd); 319 double endT = fSegment->t(fEnd);
329 double limitT = endT; 320 double limitT = endT;
330 int index; 321 int index;
331 for (index = 0; index < testCount; ++index) { 322 for (index = 0; index < testCount; ++index) {
332 if (!between(startT, testTs[index], limitT)) { 323 if (!between(startT, testTs[index], limitT)) {
333 testTs[index] = -1; 324 testTs[index] = -1;
334 } 325 }
335 } 326 }
336 testTs[testCount++] = startT; 327 testTs[testCount++] = startT;
337 testTs[testCount++] = endT; 328 testTs[testCount++] = endT;
338 SkTQSort<double>(testTs, &testTs[testCount - 1]); 329 SkTQSort<double>(testTs, &testTs[testCount - 1]);
339 double bestSide = 0; 330 double bestSide = 0;
340 int testCases = (testCount << 1) - 1; 331 int testCases = (testCount << 1) - 1;
341 index = 0; 332 index = 0;
342 while (testTs[index] < 0) { 333 while (testTs[index] < 0) {
343 ++index; 334 ++index;
344 } 335 }
345 index <<= 1; 336 index <<= 1;
346 for (; index < testCases; ++index) { 337 for (; index < testCases; ++index) {
347 int testIndex = index >> 1; 338 int testIndex = index >> 1;
348 double testT = testTs[testIndex]; 339 double testT = testTs[testIndex];
349 if (index & 1) { 340 if (index & 1) {
350 testT = (testT + testTs[testIndex + 1]) / 2; 341 testT = (testT + testTs[testIndex + 1]) / 2;
351 } 342 }
352 // OPTIMIZE: could avoid call for t == startT, endT 343 // OPTIMIZE: could avoid call for t == startT, endT
353 SkDPoint pt = dcubic_xy_at_t(pts, testT); 344 SkDPoint pt = dcubic_xy_at_t(pts, testT);
354 double testSide = fTangent1.pointDistance(pt); 345 double testSide = fTangentPart.pointDistance(pt);
355 if (fabs(bestSide) < fabs(testSide)) { 346 if (fabs(bestSide) < fabs(testSide)) {
356 bestSide = testSide; 347 bestSide = testSide;
357 } 348 }
358 } 349 }
359 fSide = -bestSide; // compare sign only 350 fSide = -bestSide; // compare sign only
351 SkASSERT(fSide == 0 || fSide2 != 0);
360 if (fComputed && dx() > 0 && approximately_zero(dy())) { 352 if (fComputed && dx() > 0 && approximately_zero(dy())) {
361 SkDCubic origCurve; // can't use segment's curve in place since it m ay be flipped 353 SkDCubic origCurve; // can't use segment's curve in place since it m ay be flipped
362 int last = fSegment->count() - 1; 354 int last = fSegment->count() - 1;
363 fSegment->subDivide(fStart < fEnd ? 0 : last, fStart < fEnd ? last : 0, &origCurve); 355 fSegment->subDivide(fStart < fEnd ? 0 : last, fStart < fEnd ? last : 0, &origCurve);
364 SkLineParameters origTan; 356 SkDCubicPair split = origCurve.chopAt(startT);
365 origTan.cubicEndPoints(origCurve); 357 SkLineParameters splitTan;
366 if ((fUnorderable = origTan.dx() <= 0)) { 358 splitTan.cubicEndPoints(fStart < fEnd ? split.second() : split.first ());
359 if (splitTan.dx() <= 0) {
360 fUnorderable = true;
367 fUnsortable = fSegment->isTiny(this); 361 fUnsortable = fSegment->isTiny(this);
368 return; 362 return;
369 } 363 }
370 // if one is < 0 and the other is >= 0 364 // if one is < 0 and the other is >= 0
371 if ((fUnorderable = (dy() < 0) ^ (origTan.dy() < 0))) { 365 if (dy() * splitTan.dy() < 0) {
366 fUnorderable = true;
372 fUnsortable = fSegment->isTiny(this); 367 fUnsortable = fSegment->isTiny(this);
373 return; 368 return;
374 } 369 }
375 SkDCubicPair split = origCurve.chopAt(startT);
376 SkLineParameters splitTan;
377 splitTan.cubicEndPoints(fStart < fEnd ? split.second() : split.first ());
378 if ((fUnorderable = splitTan.dx() <= 0)) {
379 fUnsortable = fSegment->isTiny(this);
380 return;
381 }
382 // if one is < 0 and the other is >= 0
383 if ((fUnorderable = (dy() < 0) ^ (splitTan.dy() < 0))) {
384 fUnsortable = fSegment->isTiny(this);
385 return;
386 }
387 } 370 }
388 } break; 371 } break;
389 default: 372 default:
390 SkASSERT(0); 373 SkASSERT(0);
391 } 374 }
392 if ((fUnsortable = approximately_zero(dx()) && approximately_zero(dy()))) { 375 if ((fUnsortable = approximately_zero(dx()) && approximately_zero(dy()))) {
393 return; 376 return;
394 } 377 }
378 if (fSegment->verb() == SkPath::kLine_Verb) {
379 return;
380 }
395 SkASSERT(fStart != fEnd); 381 SkASSERT(fStart != fEnd);
396 int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 t ype macro? 382 int smaller = SkMin32(fStart, fEnd);
397 for (int index = fStart; index != fEnd; index += step) { 383 int larger = SkMax32(fStart, fEnd);
398 #if 1 384 while (smaller < larger && fSegment->span(smaller).fTiny) {
399 const SkOpSpan& thisSpan = fSegment->span(index); 385 ++smaller;
400 const SkOpSpan& nextSpan = fSegment->span(index + step); 386 }
401 if (thisSpan.fTiny || precisely_equal(thisSpan.fT, nextSpan.fT)) { 387 if (precisely_equal(fSegment->span(smaller).fT, fSegment->span(larger).fT)) {
402 continue; 388 #if DEBUG_UNSORTABLE
403 } 389 SkPoint iPt = fSegment->xyAtT(fStart);
404 fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortabl eEnd; 390 SkPoint ePt = fSegment->xyAtT(fEnd);
391 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n ", __FUNCTION__,
392 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
393 #endif
394 fUnsortable = true;
395 return;
396 }
397 fUnsortable = fStart < fEnd ? fSegment->span(smaller).fUnsortableStart
398 : fSegment->span(larger).fUnsortableEnd;
405 #if DEBUG_UNSORTABLE 399 #if DEBUG_UNSORTABLE
406 if (fUnsortable) { 400 if (fUnsortable) {
407 SkPoint iPt = fSegment->xyAtT(index); 401 SkPoint iPt = fSegment->xyAtT(smaller);
408 SkPoint ePt = fSegment->xyAtT(index + step); 402 SkPoint ePt = fSegment->xyAtT(larger);
409 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __ FUNCTION__, 403 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNC TION__,
410 index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY); 404 smaller, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
411 } 405 }
412 #endif 406 #endif
413 return; 407 return;
414 #else 408 }
415 if ((*fSpans)[index].fUnsortableStart) { 409
416 fUnsortable = true; 410 #ifdef SK_DEBUG
417 return; 411 void SkOpAngle::dump() const {
418 } 412 SkDebugf("id=%d (%1.9g,%1.9g) start=%d (%1.9g) end=%d (%1.9g)\n", fSegment-> debugID(),
413 fSegment->xAtT(fStart), fSegment->yAtT(fStart), fStart, fSegment->sp an(fStart).fT,
414 fEnd, fSegment->span(fEnd).fT);
415 }
419 #endif 416 #endif
420 }
421 #if 1
422 #if DEBUG_UNSORTABLE
423 SkPoint iPt = fSegment->xyAtT(fStart);
424 SkPoint ePt = fSegment->xyAtT(fEnd);
425 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", _ _FUNCTION__,
426 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
427 #endif
428 fUnsortable = true;
429 #endif
430 }
OLDNEW
« no previous file with comments | « src/pathops/SkOpAngle.h ('k') | src/pathops/SkOpContour.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698