예제 #1
0
bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidence,
        SkChunkAlloc* allocator) {
    SkOpGlobalState* globalState = contourList->globalState();
    // combine t values when multiple intersections occur on some segments but not others
    moveMultiples(contourList);
    findCollapsed(contourList);
    // move t values and points together to eliminate small/tiny gaps
    moveNearby(contourList);
    align(contourList);  // give all span members common values
    coincidence->fixAligned();  // aligning may have marked a coincidence pt-t deleted
#if DEBUG_VALIDATE
    globalState->setPhase(SkOpGlobalState::kIntersecting);
#endif
    // look for intersections on line segments formed by moving end points
    addAlignIntersections(contourList, allocator);
    coincidence->addMissing(allocator);
#if DEBUG_VALIDATE
    globalState->setPhase(SkOpGlobalState::kWalking);
#endif
    // check to see if, loosely, coincident ranges may be expanded
    if (coincidence->expand()) {
        coincidence->addExpanded(allocator  PATH_OPS_DEBUG_VALIDATE_PARAMS(globalState));
    }
    // the expanded ranges may not align -- add the missing spans
    coincidence->mark();  // mark spans of coincident segments as coincident
    // look for coincidence missed earlier
    if (missingCoincidence(contourList, coincidence, allocator)) {
        (void) coincidence->expand();
        coincidence->addExpanded(allocator  PATH_OPS_DEBUG_VALIDATE_PARAMS(globalState));
        coincidence->mark();
    }
    SkOpCoincidence overlaps;
    do {
        SkOpCoincidence* pairs = overlaps.isEmpty() ? coincidence : &overlaps;
        if (!pairs->apply()) {  // adjust the winding value to account for coincident edges
            return false;
        }
        // For each coincident pair that overlaps another, when the receivers (the 1st of the pair)
        // are different, construct a new pair to resolve their mutual span
        pairs->findOverlaps(&overlaps, allocator);
    } while (!overlaps.isEmpty());
    calcAngles(contourList, allocator);
    sortAngles(contourList);
    if (globalState->angleCoincidence()) {
        (void) missingCoincidence(contourList, coincidence, allocator);
        if (!coincidence->apply()) {
            return false;
        }
    }
#if DEBUG_ACTIVE_SPANS
    coincidence->debugShowCoincidence();
    DebugShowActiveSpans(contourList);
#endif
    return true;
}
예제 #2
0
bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidence) {
    SkOpGlobalState* globalState = contourList->globalState();
    DEBUG_COINCIDENCE_HEALTH(contourList, "start");
#if DEBUG_VALIDATE
    globalState->setPhase(SkOpGlobalState::kIntersecting);
#endif

    // match up points within the coincident runs
    if (!coincidence->addExpanded()) {
        return false;
    }
    DEBUG_COINCIDENCE_HEALTH(contourList, "addExpanded");
#if DEBUG_VALIDATE
    globalState->setPhase(SkOpGlobalState::kWalking);
#endif
    // combine t values when multiple intersections occur on some segments but not others
    if (!moveMultiples(contourList)) {
        return false;
    }
    DEBUG_COINCIDENCE_HEALTH(contourList, "moveMultiples");
    // move t values and points together to eliminate small/tiny gaps
    (void) moveNearby(contourList);
    DEBUG_COINCIDENCE_HEALTH(contourList, "moveNearby");
#if DEBUG_VALIDATE
    globalState->setPhase(SkOpGlobalState::kIntersecting);
#endif
    // add coincidence formed by pairing on curve points and endpoints
    coincidence->correctEnds();
    if (!coincidence->addEndMovedSpans()) {
        return false;
    }
    DEBUG_COINCIDENCE_HEALTH(contourList, "addEndMovedSpans");

    const int SAFETY_COUNT = 100;  // FIXME: tune
    int safetyHatch = SAFETY_COUNT;
    // look for coincidence present in A-B and A-C but missing in B-C
    while (coincidence->addMissing()) {
        if (!--safetyHatch) {
            SkASSERT(0);  // FIXME: take this out after verifying std tests don't trigger
            return false;
        }
        DEBUG_COINCIDENCE_HEALTH(contourList, "addMissing");
        moveNearby(contourList);
        DEBUG_COINCIDENCE_HEALTH(contourList, "moveNearby");
    }
    DEBUG_COINCIDENCE_HEALTH(contourList, "addMissing2");
    // FIXME: only call this if addMissing modified something when returning false
    moveNearby(contourList);
    DEBUG_COINCIDENCE_HEALTH(contourList, "moveNearby2");
    // check to see if, loosely, coincident ranges may be expanded
    if (coincidence->expand()) {
        DEBUG_COINCIDENCE_HEALTH(contourList, "expand1");
        coincidence->addMissing();
        DEBUG_COINCIDENCE_HEALTH(contourList, "addMissing2");
        if (!coincidence->addExpanded()) {
            return false;
        }
        DEBUG_COINCIDENCE_HEALTH(contourList, "addExpanded2");
        if (!moveMultiples(contourList)) {
            return false;
        }
        DEBUG_COINCIDENCE_HEALTH(contourList, "moveMultiples2");
        moveNearby(contourList);
    }
#if DEBUG_VALIDATE
    globalState->setPhase(SkOpGlobalState::kWalking);
#endif
    DEBUG_COINCIDENCE_HEALTH(contourList, "expand2");
    // the expanded ranges may not align -- add the missing spans
    if (!coincidence->addExpanded()) {
        SkASSERT(globalState->debugSkipAssert());
        return false;
    }
    DEBUG_COINCIDENCE_HEALTH(contourList, "addExpanded3");
    coincidence->correctEnds();
    if (!coincidence->mark()) {  // mark spans of coincident segments as coincident
        return false;
    }
    DEBUG_COINCIDENCE_HEALTH(contourList, "mark1");
    // look for coincidence lines and curves undetected by intersection
    if (missingCoincidence(contourList)) {
#if DEBUG_VALIDATE
        globalState->setPhase(SkOpGlobalState::kIntersecting);
#endif
        DEBUG_COINCIDENCE_HEALTH(contourList, "missingCoincidence1");
        (void) coincidence->expand();
        DEBUG_COINCIDENCE_HEALTH(contourList, "expand3");
        if (!coincidence->addExpanded()) {
            return false;
        }
#if DEBUG_VALIDATE
        globalState->setPhase(SkOpGlobalState::kWalking);
#endif
        DEBUG_COINCIDENCE_HEALTH(contourList, "addExpanded3");
        if (!coincidence->mark()) {
            return false;
        }
    } else {
        DEBUG_COINCIDENCE_HEALTH(contourList, "missingCoincidence2");
        (void) coincidence->expand();
    }
    DEBUG_COINCIDENCE_HEALTH(contourList, "missingCoincidence3");

    (void) coincidence->expand();

#if 0  // under development
    // coincident runs may cross two or more spans, but the opposite spans may be out of order
    if (!coincidence->reorder()) {
      return false;
    }
#endif
    DEBUG_COINCIDENCE_HEALTH(contourList, "coincidence.reorder");
    SkOpCoincidence overlaps(globalState);
    do {
        SkOpCoincidence* pairs = overlaps.isEmpty() ? coincidence : &overlaps;
        if (!pairs->apply()) {  // adjust the winding value to account for coincident edges
            return false;
        }
        DEBUG_COINCIDENCE_HEALTH(contourList, "pairs->apply");
        // For each coincident pair that overlaps another, when the receivers (the 1st of the pair)
        // are different, construct a new pair to resolve their mutual span
        if (!pairs->findOverlaps(&overlaps)) {
            return false;
        }
        DEBUG_COINCIDENCE_HEALTH(contourList, "pairs->findOverlaps");
    } while (!overlaps.isEmpty());
    calcAngles(contourList);
    sortAngles(contourList);
    if (globalState->angleCoincidence()) {
        (void) missingCoincidence(contourList);
        if (!coincidence->apply()) {
            return false;
        }
    }
#if DEBUG_COINCIDENCE_VERBOSE
    coincidence->debugShowCoincidence();
#endif
#if DEBUG_COINCIDENCE
    coincidence->debugValidate();
#endif
    SkPathOpsDebug::ShowActiveSpans(contourList);
    return true;
}