/* check start and end of each contour if not the same, record them match them up connect closest reassemble contour pieces into new path */ void Assemble(const SkPathWriter& path, SkPathWriter* simple) { #if DEBUG_PATH_CONSTRUCTION SkDebugf("%s\n", __FUNCTION__); #endif SkTArray<SkOpContour> contours; SkOpEdgeBuilder builder(path, contours); builder.finish(); int count = contours.count(); int outer; SkTArray<int, true> runs(count); // indices of partial contours for (outer = 0; outer < count; ++outer) { const SkOpContour& eContour = contours[outer]; const SkPoint& eStart = eContour.start(); const SkPoint& eEnd = eContour.end(); #if DEBUG_ASSEMBLE SkDebugf("%s contour", __FUNCTION__); if (!SkDPoint::ApproximatelyEqual(eStart, eEnd)) { SkDebugf("[%d]", runs.count()); } else { SkDebugf(" "); } SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n", eStart.fX, eStart.fY, eEnd.fX, eEnd.fY); #endif if (SkDPoint::ApproximatelyEqual(eStart, eEnd)) { eContour.toPath(simple); continue; } runs.push_back(outer); } count = runs.count(); if (count == 0) { return; } SkTArray<int, true> sLink, eLink; sLink.push_back_n(count); eLink.push_back_n(count); int rIndex, iIndex; for (rIndex = 0; rIndex < count; ++rIndex) { sLink[rIndex] = eLink[rIndex] = SK_MaxS32; } const int ends = count * 2; // all starts and ends const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2 SkTArray<double, true> distances; distances.push_back_n(entries); for (rIndex = 0; rIndex < ends - 1; ++rIndex) { outer = runs[rIndex >> 1]; const SkOpContour& oContour = contours[outer]; const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start(); const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2) * ends - rIndex - 1; for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) { int inner = runs[iIndex >> 1]; const SkOpContour& iContour = contours[inner]; const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start(); double dx = iPt.fX - oPt.fX; double dy = iPt.fY - oPt.fY; double dist = dx * dx + dy * dy; distances[row + iIndex] = dist; // oStart distance from iStart } } SkTArray<int, true> sortedDist; sortedDist.push_back_n(entries); for (rIndex = 0; rIndex < entries; ++rIndex) { sortedDist[rIndex] = rIndex; } SkTQSort<int>(sortedDist.begin(), sortedDist.end() - 1, DistanceLessThan(distances.begin())); int remaining = count; // number of start/end pairs for (rIndex = 0; rIndex < entries; ++rIndex) { int pair = sortedDist[rIndex]; int row = pair / ends; int col = pair - row * ends; int thingOne = row < col ? row : ends - row - 2; int ndxOne = thingOne >> 1; bool endOne = thingOne & 1; int* linkOne = endOne ? eLink.begin() : sLink.begin(); if (linkOne[ndxOne] != SK_MaxS32) { continue; } int thingTwo = row < col ? col : ends - row + col - 1; int ndxTwo = thingTwo >> 1; bool endTwo = thingTwo & 1; int* linkTwo = endTwo ? eLink.begin() : sLink.begin(); if (linkTwo[ndxTwo] != SK_MaxS32) { continue; } SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]); bool flip = endOne == endTwo; linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo; linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne; if (!--remaining) { break; } } SkASSERT(!remaining); #if DEBUG_ASSEMBLE for (rIndex = 0; rIndex < count; ++rIndex) { int s = sLink[rIndex]; int e = eLink[rIndex]; SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e', s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e); } #endif rIndex = 0; do { bool forward = true; bool first = true; int sIndex = sLink[rIndex]; SkASSERT(sIndex != SK_MaxS32); sLink[rIndex] = SK_MaxS32; int eIndex; if (sIndex < 0) { eIndex = sLink[~sIndex]; sLink[~sIndex] = SK_MaxS32; } else { eIndex = eLink[sIndex]; eLink[sIndex] = SK_MaxS32; } SkASSERT(eIndex != SK_MaxS32); #if DEBUG_ASSEMBLE SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e', sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e', eIndex < 0 ? ~eIndex : eIndex); #endif do { outer = runs[rIndex]; const SkOpContour& contour = contours[outer]; if (first) { first = false; const SkPoint* startPtr = &contour.start(); simple->deferredMove(startPtr[0]); } if (forward) { contour.toPartialForward(simple); } else { contour.toPartialBackward(simple); } #if DEBUG_ASSEMBLE SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex, eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex, sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)); #endif if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) { simple->close(); break; } if (forward) { eIndex = eLink[rIndex]; SkASSERT(eIndex != SK_MaxS32); eLink[rIndex] = SK_MaxS32; if (eIndex >= 0) { SkASSERT(sLink[eIndex] == rIndex); sLink[eIndex] = SK_MaxS32; } else { SkASSERT(eLink[~eIndex] == ~rIndex); eLink[~eIndex] = SK_MaxS32; } } else { eIndex = sLink[rIndex]; SkASSERT(eIndex != SK_MaxS32); sLink[rIndex] = SK_MaxS32; if (eIndex >= 0) { SkASSERT(eLink[eIndex] == rIndex); eLink[eIndex] = SK_MaxS32; } else { SkASSERT(sLink[~eIndex] == ~rIndex); sLink[~eIndex] = SK_MaxS32; } } rIndex = eIndex; if (rIndex < 0) { forward ^= 1; rIndex = ~rIndex; } } while (true); for (rIndex = 0; rIndex < count; ++rIndex) { if (sLink[rIndex] != SK_MaxS32) { break; } } } while (rIndex < count); #if DEBUG_ASSEMBLE for (rIndex = 0; rIndex < count; ++rIndex) { SkASSERT(sLink[rIndex] == SK_MaxS32); SkASSERT(eLink[rIndex] == SK_MaxS32); } #endif }
/* check start and end of each contour if not the same, record them match them up connect closest reassemble contour pieces into new path */ void SkPathWriter::assemble() { #if DEBUG_SHOW_TEST_NAME SkDebugf("</div>\n"); #endif if (!this->someAssemblyRequired()) { return; } #if DEBUG_PATH_CONSTRUCTION SkDebugf("%s\n", __FUNCTION__); #endif SkOpPtT const* const* runs = fEndPtTs.begin(); // starts, ends of partial contours int endCount = fEndPtTs.count(); // all starts and ends SkASSERT(endCount > 0); SkASSERT(endCount == fPartials.count() * 2); #if DEBUG_ASSEMBLE for (int index = 0; index < endCount; index += 2) { const SkOpPtT* eStart = runs[index]; const SkOpPtT* eEnd = runs[index + 1]; SkASSERT(eStart != eEnd); SkASSERT(!eStart->contains(eEnd)); SkDebugf("%s contour start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n", __FUNCTION__, eStart->fPt.fX, eStart->fPt.fY, eEnd->fPt.fX, eEnd->fPt.fY); } #endif SkTDArray<int> sLink, eLink; int linkCount = endCount / 2; // number of partial contours sLink.append(linkCount); eLink.append(linkCount); int rIndex, iIndex; for (rIndex = 0; rIndex < linkCount; ++rIndex) { sLink[rIndex] = eLink[rIndex] = SK_MaxS32; } const int entries = endCount * (endCount - 1) / 2; // folded triangle SkSTArray<8, double, true> distances(entries); SkSTArray<8, int, true> sortedDist(entries); SkSTArray<8, int, true> distLookup(entries); int rRow = 0; int dIndex = 0; for (rIndex = 0; rIndex < endCount - 1; ++rIndex) { const SkOpPtT* oPtT = runs[rIndex]; for (iIndex = rIndex + 1; iIndex < endCount; ++iIndex) { const SkOpPtT* iPtT = runs[iIndex]; double dx = iPtT->fPt.fX - oPtT->fPt.fX; double dy = iPtT->fPt.fY - oPtT->fPt.fY; double dist = dx * dx + dy * dy; distLookup.push_back(rRow + iIndex); distances.push_back(dist); // oStart distance from iStart sortedDist.push_back(dIndex++); } rRow += endCount; } SkASSERT(dIndex == entries); SkTQSort<int>(sortedDist.begin(), sortedDist.end() - 1, DistanceLessThan(distances.begin())); int remaining = linkCount; // number of start/end pairs for (rIndex = 0; rIndex < entries; ++rIndex) { int pair = sortedDist[rIndex]; pair = distLookup[pair]; int row = pair / endCount; int col = pair - row * endCount; int ndxOne = row >> 1; bool endOne = row & 1; int* linkOne = endOne ? eLink.begin() : sLink.begin(); if (linkOne[ndxOne] != SK_MaxS32) { continue; } int ndxTwo = col >> 1; bool endTwo = col & 1; int* linkTwo = endTwo ? eLink.begin() : sLink.begin(); if (linkTwo[ndxTwo] != SK_MaxS32) { continue; } SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]); bool flip = endOne == endTwo; linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo; linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne; if (!--remaining) { break; } } SkASSERT(!remaining); #if DEBUG_ASSEMBLE for (rIndex = 0; rIndex < linkCount; ++rIndex) { int s = sLink[rIndex]; int e = eLink[rIndex]; SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e', s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e); } #endif rIndex = 0; do { bool forward = true; bool first = true; int sIndex = sLink[rIndex]; SkASSERT(sIndex != SK_MaxS32); sLink[rIndex] = SK_MaxS32; int eIndex; if (sIndex < 0) { eIndex = sLink[~sIndex]; sLink[~sIndex] = SK_MaxS32; } else { eIndex = eLink[sIndex]; eLink[sIndex] = SK_MaxS32; } SkASSERT(eIndex != SK_MaxS32); #if DEBUG_ASSEMBLE SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e', sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e', eIndex < 0 ? ~eIndex : eIndex); #endif do { const SkPath& contour = fPartials[rIndex]; if (forward) { fPathPtr->addPath(contour, first ? SkPath::kAppend_AddPathMode : SkPath::kExtend_AddPathMode); } else { SkASSERT(!first); fPathPtr->reverseAddPath(contour); } if (first) { first = false; } #if DEBUG_ASSEMBLE SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex, eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex, sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)); #endif if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) { fPathPtr->close(); break; } if (forward) { eIndex = eLink[rIndex]; SkASSERT(eIndex != SK_MaxS32); eLink[rIndex] = SK_MaxS32; if (eIndex >= 0) { SkASSERT(sLink[eIndex] == rIndex); sLink[eIndex] = SK_MaxS32; } else { SkASSERT(eLink[~eIndex] == ~rIndex); eLink[~eIndex] = SK_MaxS32; } } else { eIndex = sLink[rIndex]; SkASSERT(eIndex != SK_MaxS32); sLink[rIndex] = SK_MaxS32; if (eIndex >= 0) { SkASSERT(eLink[eIndex] == rIndex); eLink[eIndex] = SK_MaxS32; } else { SkASSERT(sLink[~eIndex] == ~rIndex); sLink[~eIndex] = SK_MaxS32; } } rIndex = eIndex; if (rIndex < 0) { forward ^= 1; rIndex = ~rIndex; } } while (true); for (rIndex = 0; rIndex < linkCount; ++rIndex) { if (sLink[rIndex] != SK_MaxS32) { break; } } } while (rIndex < linkCount); #if DEBUG_ASSEMBLE for (rIndex = 0; rIndex < linkCount; ++rIndex) { SkASSERT(sLink[rIndex] == SK_MaxS32); SkASSERT(eLink[rIndex] == SK_MaxS32); } #endif return; }