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 "SkAddIntersections.h" | 7 #include "SkAddIntersections.h" |
8 #include "SkOpCoincidence.h" | 8 #include "SkOpCoincidence.h" |
9 #include "SkOpEdgeBuilder.h" | 9 #include "SkOpEdgeBuilder.h" |
10 #include "SkPathOpsCommon.h" | 10 #include "SkPathOpsCommon.h" |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
191 *contourList = contourHead; | 191 *contourList = contourHead; |
192 for (int index = 1; index < count; ++index) { | 192 for (int index = 1; index < count; ++index) { |
193 SkOpContour* next = list[index]; | 193 SkOpContour* next = list[index]; |
194 contour->setNext(next); | 194 contour->setNext(next); |
195 contour = next; | 195 contour = next; |
196 } | 196 } |
197 contour->setNext(nullptr); | 197 contour->setNext(nullptr); |
198 return true; | 198 return true; |
199 } | 199 } |
200 | 200 |
201 class DistanceLessThan { | |
202 public: | |
203 DistanceLessThan(double* distances) : fDistances(distances) { } | |
204 double* fDistances; | |
205 bool operator()(const int one, const int two) { | |
206 return fDistances[one] < fDistances[two]; | |
207 } | |
208 }; | |
209 | |
210 /* | |
211 check start and end of each contour | |
212 if not the same, record them | |
213 match them up | |
214 connect closest | |
215 reassemble contour pieces into new path | |
216 */ | |
217 void Assemble(const SkPathWriter& path, SkPathWriter* simple) { | |
218 SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune | |
219 SkOpContourHead contour; | |
220 SkOpGlobalState globalState(&contour, &allocator SkDEBUGPARAMS(false) | |
221 SkDEBUGPARAMS(nullptr)); | |
222 #if DEBUG_SHOW_TEST_NAME | |
223 SkDebugf("</div>\n"); | |
224 #endif | |
225 #if DEBUG_PATH_CONSTRUCTION | |
226 SkDebugf("%s\n", __FUNCTION__); | |
227 #endif | |
228 SkOpEdgeBuilder builder(path, &contour, &globalState); | |
229 builder.finish(); | |
230 SkTDArray<const SkOpContour* > runs; // indices of partial contours | |
231 const SkOpContour* eContour = builder.head(); | |
232 do { | |
233 if (!eContour->count()) { | |
234 continue; | |
235 } | |
236 const SkPoint& eStart = eContour->start(); | |
237 const SkPoint& eEnd = eContour->end(); | |
238 #if DEBUG_ASSEMBLE | |
239 SkDebugf("%s contour", __FUNCTION__); | |
240 if (!SkDPoint::ApproximatelyEqual(eStart, eEnd)) { | |
241 SkDebugf("[%d]", runs.count()); | |
242 } else { | |
243 SkDebugf(" "); | |
244 } | |
245 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n", | |
246 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY); | |
247 #endif | |
248 if (SkDPoint::ApproximatelyEqual(eStart, eEnd)) { | |
249 eContour->toPath(simple); | |
250 continue; | |
251 } | |
252 *runs.append() = eContour; | |
253 } while ((eContour = eContour->next())); | |
254 int count = runs.count(); | |
255 if (count == 0) { | |
256 return; | |
257 } | |
258 SkTDArray<int> sLink, eLink; | |
259 sLink.append(count); | |
260 eLink.append(count); | |
261 int rIndex, iIndex; | |
262 for (rIndex = 0; rIndex < count; ++rIndex) { | |
263 sLink[rIndex] = eLink[rIndex] = SK_MaxS32; | |
264 } | |
265 const int ends = count * 2; // all starts and ends | |
266 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) /
2 | |
267 SkTDArray<double> distances; | |
268 distances.append(entries); | |
269 for (rIndex = 0; rIndex < ends - 1; ++rIndex) { | |
270 const SkOpContour* oContour = runs[rIndex >> 1]; | |
271 const SkPoint& oPt = rIndex & 1 ? oContour->end() : oContour->start(); | |
272 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2) | |
273 * ends - rIndex - 1; | |
274 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) { | |
275 const SkOpContour* iContour = runs[iIndex >> 1]; | |
276 const SkPoint& iPt = iIndex & 1 ? iContour->end() : iContour->start(
); | |
277 double dx = iPt.fX - oPt.fX; | |
278 double dy = iPt.fY - oPt.fY; | |
279 double dist = dx * dx + dy * dy; | |
280 distances[row + iIndex] = dist; // oStart distance from iStart | |
281 } | |
282 } | |
283 SkTDArray<int> sortedDist; | |
284 sortedDist.append(entries); | |
285 for (rIndex = 0; rIndex < entries; ++rIndex) { | |
286 sortedDist[rIndex] = rIndex; | |
287 } | |
288 SkTQSort<int>(sortedDist.begin(), sortedDist.end() - 1, DistanceLessThan(dis
tances.begin())); | |
289 int remaining = count; // number of start/end pairs | |
290 for (rIndex = 0; rIndex < entries; ++rIndex) { | |
291 int pair = sortedDist[rIndex]; | |
292 int row = pair / ends; | |
293 int col = pair - row * ends; | |
294 int thingOne = row < col ? row : ends - row - 2; | |
295 int ndxOne = thingOne >> 1; | |
296 bool endOne = thingOne & 1; | |
297 int* linkOne = endOne ? eLink.begin() : sLink.begin(); | |
298 if (linkOne[ndxOne] != SK_MaxS32) { | |
299 continue; | |
300 } | |
301 int thingTwo = row < col ? col : ends - row + col - 1; | |
302 int ndxTwo = thingTwo >> 1; | |
303 bool endTwo = thingTwo & 1; | |
304 int* linkTwo = endTwo ? eLink.begin() : sLink.begin(); | |
305 if (linkTwo[ndxTwo] != SK_MaxS32) { | |
306 continue; | |
307 } | |
308 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]); | |
309 bool flip = endOne == endTwo; | |
310 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo; | |
311 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne; | |
312 if (!--remaining) { | |
313 break; | |
314 } | |
315 } | |
316 SkASSERT(!remaining); | |
317 #if DEBUG_ASSEMBLE | |
318 for (rIndex = 0; rIndex < count; ++rIndex) { | |
319 int s = sLink[rIndex]; | |
320 int e = eLink[rIndex]; | |
321 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : '
e', | |
322 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e :
e); | |
323 } | |
324 #endif | |
325 rIndex = 0; | |
326 do { | |
327 bool forward = true; | |
328 bool first = true; | |
329 int sIndex = sLink[rIndex]; | |
330 SkASSERT(sIndex != SK_MaxS32); | |
331 sLink[rIndex] = SK_MaxS32; | |
332 int eIndex; | |
333 if (sIndex < 0) { | |
334 eIndex = sLink[~sIndex]; | |
335 sLink[~sIndex] = SK_MaxS32; | |
336 } else { | |
337 eIndex = eLink[sIndex]; | |
338 eLink[sIndex] = SK_MaxS32; | |
339 } | |
340 SkASSERT(eIndex != SK_MaxS32); | |
341 #if DEBUG_ASSEMBLE | |
342 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's'
: 'e', | |
343 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e', | |
344 eIndex < 0 ? ~eIndex : eIndex); | |
345 #endif | |
346 do { | |
347 const SkOpContour* contour = runs[rIndex]; | |
348 if (first) { | |
349 first = false; | |
350 const SkPoint* startPtr = &contour->start(); | |
351 simple->deferredMove(startPtr[0]); | |
352 } | |
353 if (forward) { | |
354 contour->toPartialForward(simple); | |
355 } else { | |
356 contour->toPartialBackward(simple); | |
357 } | |
358 #if DEBUG_ASSEMBLE | |
359 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex
, | |
360 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex, | |
361 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)); | |
362 #endif | |
363 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) { | |
364 simple->close(); | |
365 break; | |
366 } | |
367 if (forward) { | |
368 eIndex = eLink[rIndex]; | |
369 SkASSERT(eIndex != SK_MaxS32); | |
370 eLink[rIndex] = SK_MaxS32; | |
371 if (eIndex >= 0) { | |
372 SkASSERT(sLink[eIndex] == rIndex); | |
373 sLink[eIndex] = SK_MaxS32; | |
374 } else { | |
375 SkASSERT(eLink[~eIndex] == ~rIndex); | |
376 eLink[~eIndex] = SK_MaxS32; | |
377 } | |
378 } else { | |
379 eIndex = sLink[rIndex]; | |
380 SkASSERT(eIndex != SK_MaxS32); | |
381 sLink[rIndex] = SK_MaxS32; | |
382 if (eIndex >= 0) { | |
383 SkASSERT(eLink[eIndex] == rIndex); | |
384 eLink[eIndex] = SK_MaxS32; | |
385 } else { | |
386 SkASSERT(sLink[~eIndex] == ~rIndex); | |
387 sLink[~eIndex] = SK_MaxS32; | |
388 } | |
389 } | |
390 rIndex = eIndex; | |
391 if (rIndex < 0) { | |
392 forward ^= 1; | |
393 rIndex = ~rIndex; | |
394 } | |
395 } while (true); | |
396 for (rIndex = 0; rIndex < count; ++rIndex) { | |
397 if (sLink[rIndex] != SK_MaxS32) { | |
398 break; | |
399 } | |
400 } | |
401 } while (rIndex < count); | |
402 #if DEBUG_ASSEMBLE | |
403 for (rIndex = 0; rIndex < count; ++rIndex) { | |
404 SkASSERT(sLink[rIndex] == SK_MaxS32); | |
405 SkASSERT(eLink[rIndex] == SK_MaxS32); | |
406 } | |
407 #endif | |
408 } | |
409 | |
410 static void calcAngles(SkOpContourHead* contourList) { | 201 static void calcAngles(SkOpContourHead* contourList) { |
411 SkOpContour* contour = contourList; | 202 SkOpContour* contour = contourList; |
412 do { | 203 do { |
413 contour->calcAngles(); | 204 contour->calcAngles(); |
414 } while ((contour = contour->next())); | 205 } while ((contour = contour->next())); |
415 } | 206 } |
416 | 207 |
417 static bool missingCoincidence(SkOpContourHead* contourList) { | 208 static bool missingCoincidence(SkOpContourHead* contourList) { |
418 SkOpContour* contour = contourList; | 209 SkOpContour* contour = contourList; |
419 bool result = false; | 210 bool result = false; |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
592 } | 383 } |
593 #if DEBUG_COINCIDENCE_VERBOSE | 384 #if DEBUG_COINCIDENCE_VERBOSE |
594 coincidence->debugShowCoincidence(); | 385 coincidence->debugShowCoincidence(); |
595 #endif | 386 #endif |
596 #if DEBUG_COINCIDENCE | 387 #if DEBUG_COINCIDENCE |
597 coincidence->debugValidate(); | 388 coincidence->debugValidate(); |
598 #endif | 389 #endif |
599 SkPathOpsDebug::ShowActiveSpans(contourList); | 390 SkPathOpsDebug::ShowActiveSpans(contourList); |
600 return true; | 391 return true; |
601 } | 392 } |
OLD | NEW |