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

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

Issue 13094010: Add implementation of path ops (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: Created 7 years, 9 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
(Empty)
1 /*
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 #include "SkIntersections.h"
8 #include "SkOpAngle.h"
9 #include "SkPathOpsCurve.h"
10
11 // FIXME: this is bogus for quads and cubics
12 // if the quads and cubics' line from end pt to ctrl pt are coincident,
13 // there's no obvious way to determine the curve ordering from the
14 // derivatives alone. In particular, if one quadratic's coincident tangent
15 // is longer than the other curve, the final control point can place the
16 // longer curve on either side of the shorter one.
17 // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf
18 // may provide some help, but nothing has been figured out yet.
19
20 /*(
21 for quads and cubics, set up a parameterized line (e.g. LineParameters )
22 for points [0] to [1]. See if point [2] is on that line, or on one side
23 or the other. If it both quads' end points are on the same side, choose
24 the shorter tangent. If the tangents are equal, choose the better second
25 tangent angle
26
27 maybe I could set up LineParameters lazily
28 */
29 bool SkOpAngle::operator<(const SkOpAngle& rh) const {
30 double y = dy();
31 double ry = rh.dy();
32 if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ?
33 return y < 0;
34 }
35 double x = dx();
36 double rx = rh.dx();
37 if (y == 0 && ry == 0 && x * rx < 0) {
38 return x < rx;
39 }
40 double x_ry = x * ry;
41 double rx_y = rx * y;
42 double cmp = x_ry - rx_y;
43 if (!approximately_zero(cmp)) {
44 return cmp < 0;
45 }
46 if (approximately_zero(x_ry) && approximately_zero(rx_y)
47 && !approximately_zero_squared(cmp)) {
48 return cmp < 0;
49 }
50 // at this point, the initial tangent line is coincident
51 // see if edges curl away from each other
52 if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide)
53 || !approximately_zero(rh.fSide))) {
54 // FIXME: running demo will trigger this assertion
55 // (don't know if commenting out will trigger further assertion or not)
56 // commenting it out allows demo to run in release, though
57 // SkASSERT(fSide != rh.fSide);
58 return fSide < rh.fSide;
59 }
60 // see if either curve can be lengthened and try the tangent compare again
61 if (cmp && (*fSpans)[fEnd].fOther != rh.fSegment // tangents not absolutely identical
62 && (*rh.fSpans)[rh.fEnd].fOther != fSegment) { // and not intersecti ng
63 SkOpAngle longer = *this;
64 SkOpAngle rhLonger = rh;
65 if (longer.lengthen() | rhLonger.lengthen()) {
66 return longer < rhLonger;
67 }
68 }
69 if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_z ero(y))
70 || (rh.fVerb == SkPath::kLine_Verb
71 && approximately_zero(rx) && approximately_zero(ry))) {
72 // See general unsortable comment below. This case can happen when
73 // one line has a non-zero change in t but no change in x and y.
74 fUnsortable = true;
75 rh.fUnsortable = true;
76 return this < &rh; // even with no solution, return a stable sort
77 }
78 if ((*rh.fSpans)[SkMin32(rh.fStart, rh.fEnd)].fTiny
79 || (*fSpans)[SkMin32(fStart, fEnd)].fTiny) {
80 fUnsortable = true;
81 rh.fUnsortable = true;
82 return this < &rh; // even with no solution, return a stable sort
83 }
84 SkASSERT(fVerb >= SkPath::kQuad_Verb);
85 SkASSERT(rh.fVerb >= SkPath::kQuad_Verb);
86 // 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
88 // 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
90 double len = fTangent1.normalSquared();
91 double rlen = rh.fTangent1.normalSquared();
92 SkDLine ray;
93 SkIntersections i, ri;
94 int roots, rroots;
95 bool flip = false;
96 do {
97 bool useThis = (len < rlen) ^ flip;
98 const SkDCubic& part = useThis ? fCurvePart : rh.fCurvePart;
99 SkPath::Verb partVerb = useThis ? fVerb : rh.fVerb;
100 ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(p art[1]) ?
101 part[2] : part[1];
102 ray[1].fX = (part[0].fX + part[partVerb].fX) / 2;
103 ray[1].fY = (part[0].fY + part[partVerb].fY) / 2;
104 SkASSERT(ray[0] != ray[1]);
105 roots = (i.*CurveRay[fVerb])(fPts, ray);
106 rroots = (ri.*CurveRay[rh.fVerb])(rh.fPts, ray);
107 } while ((roots == 0 || rroots == 0) && (flip ^= true));
108 if (roots == 0 || rroots == 0) {
109 // 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
111 // future computations, and allow the returned path to be fragmented
112 fUnsortable = true;
113 rh.fUnsortable = true;
114 return this < &rh; // even with no solution, return a stable sort
115 }
116 SkDPoint loc;
117 double best = SK_ScalarInfinity;
118 SkDVector dxy;
119 double dist;
120 int index;
121 for (index = 0; index < roots; ++index) {
122 loc = (*CurveDPointAtT[fVerb])(fPts, i[0][index]);
123 dxy = loc - ray[0];
124 dist = dxy.lengthSquared();
125 if (best > dist) {
126 best = dist;
127 }
128 }
129 for (index = 0; index < rroots; ++index) {
130 loc = (*CurveDPointAtT[rh.fVerb])(rh.fPts, ri[0][index]);
131 dxy = loc - ray[0];
132 dist = dxy.lengthSquared();
133 if (best > dist) {
134 return fSide < 0;
135 }
136 }
137 return fSide > 0;
138 }
139
140 bool SkOpAngle::lengthen() {
141 int newEnd = fEnd;
142 if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
143 fEnd = newEnd;
144 setSpans();
145 return true;
146 }
147 return false;
148 }
149
150 bool SkOpAngle::reverseLengthen() {
151 if (fReversed) {
152 return false;
153 }
154 int newEnd = fStart;
155 if (fStart > fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
156 fEnd = newEnd;
157 fReversed = true;
158 setSpans();
159 return true;
160 }
161 return false;
162 }
163
164 void SkOpAngle::set(const SkPoint* orig, SkPath::Verb verb, const SkOpSegment* s egment,
165 int start, int end, const SkTDArray<SkOpSpan>& spans) {
166 fSegment = segment;
167 fStart = start;
168 fEnd = end;
169 fPts = orig;
170 fVerb = verb;
171 fSpans = &spans;
172 fReversed = false;
173 fUnsortable = false;
174 setSpans();
175 }
176
177
178 void SkOpAngle::setSpans() {
179 double startT = (*fSpans)[fStart].fT;
180 double endT = (*fSpans)[fEnd].fT;
181 switch (fVerb) {
182 case SkPath::kLine_Verb: {
183 SkDLine l = SkDLine::SubDivide(fPts, startT, endT);
184 // OPTIMIZATION: for pure line compares, we never need fTangent1.c
185 fTangent1.lineEndPoints(l);
186 fSide = 0;
187 } break;
188 case SkPath::kQuad_Verb: {
189 SkDQuad& quad = (SkDQuad&)fCurvePart;
190 quad = SkDQuad::SubDivide(fPts, startT, endT);
191 fTangent1.quadEndPoints(quad, 0, 1);
192 if (dx() == 0 && dy() == 0) {
193 fTangent1.quadEndPoints(quad);
194 }
195 fSide = -fTangent1.pointDistance(fCurvePart[2]); // not normalized -- co mpare sign only
196 } break;
197 case SkPath::kCubic_Verb: {
198 int nextC = 2;
199 fCurvePart = SkDCubic::SubDivide(fPts, startT, endT);
200 fTangent1.cubicEndPoints(fCurvePart, 0, 1);
201 if (dx() == 0 && dy() == 0) {
202 fTangent1.cubicEndPoints(fCurvePart, 0, 2);
203 nextC = 3;
204 if (dx() == 0 && dy() == 0) {
205 fTangent1.cubicEndPoints(fCurvePart, 0, 3);
206 }
207 }
208 fSide = -fTangent1.pointDistance(fCurvePart[nextC]); // compare sign onl y
209 if (nextC == 2 && approximately_zero(fSide)) {
210 fSide = -fTangent1.pointDistance(fCurvePart[3]);
211 }
212 } break;
213 default:
214 SkASSERT(0);
215 }
216 fUnsortable = dx() == 0 && dy() == 0;
217 if (fUnsortable) {
218 return;
219 }
220 SkASSERT(fStart != fEnd);
221 int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 ty pe macro?
222 for (int index = fStart; index != fEnd; index += step) {
223 #if 1
224 const SkOpSpan& thisSpan = (*fSpans)[index];
225 const SkOpSpan& nextSpan = (*fSpans)[index + step];
226 if (thisSpan.fTiny || precisely_equal(thisSpan.fT, nextSpan.fT)) {
227 continue;
228 }
229 fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortabl eEnd;
230 #if DEBUG_UNSORTABLE
231 if (fUnsortable) {
232 SkPoint iPt = (*CurvePointAtT[fVerb])(fPts, thisSpan.fT);
233 SkPoint ePt = (*CurvePointAtT[fVerb])(fPts, nextSpan.fT);
234 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __ FUNCTION__,
235 index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
236 }
237 #endif
238 return;
239 #else
240 if ((*fSpans)[index].fUnsortableStart) {
241 fUnsortable = true;
242 return;
243 }
244 #endif
245 }
246 #if 1
247 #if DEBUG_UNSORTABLE
248 SkPoint iPt = (*CurvePointAtT[fVerb])(fPts, startT);
249 SkPoint ePt = (*CurvePointAtT[fVerb])(fPts, endT);
250 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", _ _FUNCTION__,
251 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
252 #endif
253 fUnsortable = true;
254 #endif
255 }
256
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