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

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

Issue 14798004: path ops -- fix skp bugs (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: Created 7 years, 7 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/SkIntersections.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 "SkPathOpsCurve.h" 9 #include "SkPathOpsCurve.h"
10 #include "SkTSort.h" 10 #include "SkTSort.h"
11 11
12 #if DEBUG_SORT || DEBUG_SORT_SINGLE
13 #include "SkOpSegment.h"
14 #endif
15
12 // FIXME: this is bogus for quads and cubics 16 // FIXME: this is bogus for quads and cubics
13 // if the quads and cubics' line from end pt to ctrl pt are coincident, 17 // if the quads and cubics' line from end pt to ctrl pt are coincident,
14 // there's no obvious way to determine the curve ordering from the 18 // there's no obvious way to determine the curve ordering from the
15 // derivatives alone. In particular, if one quadratic's coincident tangent 19 // derivatives alone. In particular, if one quadratic's coincident tangent
16 // is longer than the other curve, the final control point can place the 20 // is longer than the other curve, the final control point can place the
17 // longer curve on either side of the shorter one. 21 // longer curve on either side of the shorter one.
18 // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf 22 // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf
19 // may provide some help, but nothing has been figured out yet. 23 // may provide some help, but nothing has been figured out yet.
20 24
21 /*( 25 /*(
22 for quads and cubics, set up a parameterized line (e.g. LineParameters ) 26 for quads and cubics, set up a parameterized line (e.g. LineParameters )
23 for points [0] to [1]. See if point [2] is on that line, or on one side 27 for points [0] to [1]. See if point [2] is on that line, or on one side
24 or the other. If it both quads' end points are on the same side, choose 28 or the other. If it both quads' end points are on the same side, choose
25 the shorter tangent. If the tangents are equal, choose the better second 29 the shorter tangent. If the tangents are equal, choose the better second
26 tangent angle 30 tangent angle
27 31
28 maybe I could set up LineParameters lazily 32 maybe I could set up LineParameters lazily
29 */ 33 */
30 bool SkOpAngle::operator<(const SkOpAngle& rh) const { 34 static int simple_compare(double x, double y, double rx, double ry) {
31 double y = dy();
32 double ry = rh.dy();
33 if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ? 35 if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ?
34 return y < 0; 36 return y < 0;
35 } 37 }
36 double x = dx();
37 double rx = rh.dx();
38 if (y == 0 && ry == 0 && x * rx < 0) { 38 if (y == 0 && ry == 0 && x * rx < 0) {
39 return x < rx; 39 return x < rx;
40 } 40 }
41 double x_ry = x * ry; 41 double x_ry = x * ry;
42 double rx_y = rx * y; 42 double rx_y = rx * y;
43 double cmp = x_ry - rx_y; 43 double cmp = x_ry - rx_y;
44 if (!approximately_zero(cmp)) { 44 if (!approximately_zero(cmp)) {
45 return cmp < 0; 45 return cmp < 0;
46 } 46 }
47 if (approximately_zero(x_ry) && approximately_zero(rx_y) 47 if (approximately_zero(x_ry) && approximately_zero(rx_y)
48 && !approximately_zero_squared(cmp)) { 48 && !approximately_zero_squared(cmp)) {
49 return cmp < 0; 49 return cmp < 0;
50 } 50 }
51 return -1;
52 }
53
54 bool SkOpAngle::operator<(const SkOpAngle& rh) const {
55 double x = dx();
56 double y = dy();
57 double rx = rh.dx();
58 double ry = rh.dy();
59 int simple = simple_compare(x, y, rx, ry);
60 if (simple >= 0) {
61 return simple;
62 }
51 // at this point, the initial tangent line is coincident 63 // at this point, the initial tangent line is coincident
52 // see if edges curl away from each other 64 // see if edges curl away from each other
53 if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide) 65 if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide)
54 || !approximately_zero(rh.fSide))) { 66 || !approximately_zero(rh.fSide))) {
55 // FIXME: running demo will trigger this assertion 67 // FIXME: running demo will trigger this assertion
56 // (don't know if commenting out will trigger further assertion or not) 68 // (don't know if commenting out will trigger further assertion or not)
57 // commenting it out allows demo to run in release, though 69 // commenting it out allows demo to run in release, though
58 return fSide < rh.fSide; 70 return fSide < rh.fSide;
59 } 71 }
60 // see if either curve can be lengthened and try the tangent compare again 72 // see if either curve can be lengthened and try the tangent compare again
(...skipping 25 matching lines...) Expand all
86 // FIXME: until I can think of something better, project a ray from the 98 // FIXME: until I can think of something better, project a ray from the
87 // end of the shorter tangent to midway between the end points 99 // end of the shorter tangent to midway between the end points
88 // through both curves and use the resulting angle to sort 100 // through both curves and use the resulting angle to sort
89 // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive 101 // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
90 double len = fTangent1.normalSquared(); 102 double len = fTangent1.normalSquared();
91 double rlen = rh.fTangent1.normalSquared(); 103 double rlen = rh.fTangent1.normalSquared();
92 SkDLine ray; 104 SkDLine ray;
93 SkIntersections i, ri; 105 SkIntersections i, ri;
94 int roots, rroots; 106 int roots, rroots;
95 bool flip = false; 107 bool flip = false;
108 bool useThis;
109 bool leftLessThanRight = fSide > 0;
96 do { 110 do {
97 bool useThis = (len < rlen) ^ flip; 111 useThis = (len < rlen) ^ flip;
98 const SkDCubic& part = useThis ? fCurvePart : rh.fCurvePart; 112 const SkDCubic& part = useThis ? fCurvePart : rh.fCurvePart;
99 SkPath::Verb partVerb = useThis ? fVerb : rh.fVerb; 113 SkPath::Verb partVerb = useThis ? fVerb : rh.fVerb;
100 ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(p art[1]) ? 114 ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(p art[1]) ?
101 part[2] : part[1]; 115 part[2] : part[1];
102 ray[1].fX = (part[0].fX + part[partVerb].fX) / 2; 116 ray[1].fX = (part[0].fX + part[partVerb].fX) / 2;
103 ray[1].fY = (part[0].fY + part[partVerb].fY) / 2; 117 ray[1].fY = (part[0].fY + part[partVerb].fY) / 2;
104 SkASSERT(ray[0] != ray[1]); 118 SkASSERT(ray[0] != ray[1]);
105 roots = (i.*CurveRay[fVerb])(fPts, ray); 119 roots = (i.*CurveRay[fVerb])(fPts, ray);
106 rroots = (ri.*CurveRay[rh.fVerb])(rh.fPts, ray); 120 rroots = (ri.*CurveRay[rh.fVerb])(rh.fPts, ray);
107 } while ((roots == 0 || rroots == 0) && (flip ^= true)); 121 } while ((roots == 0 || rroots == 0) && (flip ^= true));
108 if (roots == 0 || rroots == 0) { 122 if (roots == 0 || rroots == 0) {
109 // FIXME: we don't have a solution in this case. The interim solution 123 // FIXME: we don't have a solution in this case. The interim solution
110 // is to mark the edges as unsortable, exclude them from this and 124 // is to mark the edges as unsortable, exclude them from this and
111 // future computations, and allow the returned path to be fragmented 125 // future computations, and allow the returned path to be fragmented
112 fUnsortable = true; 126 fUnsortable = true;
113 rh.fUnsortable = true; 127 rh.fUnsortable = true;
114 return this < &rh; // even with no solution, return a stable sort 128 return this < &rh; // even with no solution, return a stable sort
115 } 129 }
116 SkDPoint loc; 130 SkASSERT(fSide != 0 && rh.fSide != 0);
131 SkASSERT(fSide * rh.fSide > 0); // both are the same sign
132 SkDPoint lLoc;
117 double best = SK_ScalarInfinity; 133 double best = SK_ScalarInfinity;
118 SkDVector dxy; 134 #if DEBUG_SORT
119 double dist; 135 SkDebugf("lh=%d rh=%d use-lh=%d ray={{%1.9g,%1.9g}, {%1.9g,%1.9g}} %c\n",
120 int index; 136 fSegment->debugID(), rh.fSegment->debugID(), useThis, ray[0].fX, ray [0].fY,
121 for (index = 0; index < roots; ++index) { 137 ray[1].fX, ray[1].fY, "-+"[fSide > 0]);
122 loc = (*CurveDPointAtT[fVerb])(fPts, i[0][index]); 138 #endif
123 dxy = loc - ray[0]; 139 for (int index = 0; index < roots; ++index) {
124 dist = dxy.lengthSquared(); 140 SkDPoint loc = i.pt(index);
141 SkDVector dxy = loc - ray[0];
142 double dist = dxy.lengthSquared();
143 #if DEBUG_SORT
144 SkDebugf("best=%1.9g dist=%1.9g loc={%1.9g,%1.9g} dxy={%1.9g,%1.9g}\n",
145 best, dist, loc.fX, loc.fY, dxy.fX, dxy.fY);
146 #endif
125 if (best > dist) { 147 if (best > dist) {
148 lLoc = loc;
126 best = dist; 149 best = dist;
127 } 150 }
128 } 151 }
129 for (index = 0; index < rroots; ++index) { 152 flip = false;
130 loc = (*CurveDPointAtT[rh.fVerb])(rh.fPts, ri[0][index]); 153 SkDPoint rLoc;
131 dxy = loc - ray[0]; 154 for (int index = 0; index < rroots; ++index) {
132 dist = dxy.lengthSquared(); 155 rLoc = ri.pt(index);
156 SkDVector dxy = rLoc - ray[0];
157 double dist = dxy.lengthSquared();
158 #if DEBUG_SORT
159 SkDebugf("best=%1.9g dist=%1.9g %c=(fSide < 0) rLoc={%1.9g,%1.9g} dxy={% 1.9g,%1.9g}\n",
160 best, dist, "><"[fSide < 0], rLoc.fX, rLoc.fY, dxy.fX, dxy.fY);
161 #endif
133 if (best > dist) { 162 if (best > dist) {
134 return fSide < 0; 163 flip = true;
164 break;
135 } 165 }
136 } 166 }
137 return fSide > 0; 167 #if 0
168 SkDVector lRay = lLoc - fCurvePart[0];
169 SkDVector rRay = rLoc - fCurvePart[0];
170 int rayDir = simple_compare(lRay.fX, lRay.fY, rRay.fX, rRay.fY);
171 SkASSERT(rayDir >= 0);
172 if (rayDir < 0) {
173 fUnsortable = true;
174 rh.fUnsortable = true;
175 return this < &rh; // even with no solution, return a stable sort
176 }
177 #endif
178 if (flip) {
179 leftLessThanRight = !leftLessThanRight;
180 // rayDir = !rayDir;
181 }
182 #if 0 && (DEBUG_SORT || DEBUG_SORT_SINGLE)
183 SkDebugf("%d %c %d (fSide %c 0) loc={{%1.9g,%1.9g}, {%1.9g,%1.9g}} flip=%d r ayDir=%d\n",
184 fSegment->debugID(), "><"[leftLessThanRight], rh.fSegment->debug ID(),
185 "<>"[fSide > 0], lLoc.fX, lLoc.fY, rLoc.fX, rLoc.fY, flip, rayDi r);
186 #endif
187 // SkASSERT(leftLessThanRight == (bool) rayDir);
188 return leftLessThanRight;
138 } 189 }
139 190
140 bool SkOpAngle::lengthen() { 191 bool SkOpAngle::lengthen() {
141 int newEnd = fEnd; 192 int newEnd = fEnd;
142 if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) { 193 if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
143 fEnd = newEnd; 194 fEnd = newEnd;
144 setSpans(); 195 setSpans();
145 return true; 196 return true;
146 } 197 }
147 return false; 198 return false;
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
280 #if 1 331 #if 1
281 #if DEBUG_UNSORTABLE 332 #if DEBUG_UNSORTABLE
282 SkPoint iPt = (*CurvePointAtT[fVerb])(fPts, startT); 333 SkPoint iPt = (*CurvePointAtT[fVerb])(fPts, startT);
283 SkPoint ePt = (*CurvePointAtT[fVerb])(fPts, endT); 334 SkPoint ePt = (*CurvePointAtT[fVerb])(fPts, endT);
284 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", _ _FUNCTION__, 335 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", _ _FUNCTION__,
285 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY); 336 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
286 #endif 337 #endif
287 fUnsortable = true; 338 fUnsortable = true;
288 #endif 339 #endif
289 } 340 }
OLDNEW
« no previous file with comments | « src/pathops/SkIntersections.h ('k') | src/pathops/SkOpContour.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698