| 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 |