Exemplo n.º 1
0
void
ApplyGameIntroduce<Solver>::save_value(const Assignment_f* alpha,
				       const MCGame_f* game,
				       const void* oldvalue) const {
    assert(game->get()->outcome() != MCGame::FALSIFIER);
    boost::scoped_ptr<const Assignment_f> intersection(compute_intersection(alpha));
    const void *intersec_elem = _solver->evaluation()->elem(_bag, intersection.get()->get());
    const void *new_elem = _solver->evaluation()->elem(_bag, alpha->get());
    const void *val = _solver->evaluation()->mult(oldvalue, new_elem, intersec_elem);
    _solver->table(_node)->update_value(alpha, game, val);
}
// The objective here is to inset all of the edges by the given distance, and then
// remove any invalid inset edges by detecting right-hand turns. In a ccw polygon,
// we should only be making left-hand turns (for cw polygons, we use the winding
// parameter to reverse this). We detect this by checking whether the second intersection
// on an edge is closer to its tail than the first one.
//
// We might also have the case that there is no intersection between two neighboring inset edges.
// In this case, one edge will lie to the right of the other and should be discarded along with
// its previous intersection (if any).
//
// Note: the assumption is that inputPolygon is convex and has no coincident points.
//
bool SkInsetConvexPolygon(const SkPoint* inputPolygonVerts, int inputPolygonSize,
                          std::function<SkScalar(int index)> insetDistanceFunc,
                          SkTDArray<SkPoint>* insetPolygon) {
    if (inputPolygonSize < 3) {
        return false;
    }

    int winding = get_winding(inputPolygonVerts, inputPolygonSize);
    if (0 == winding) {
        return false;
    }

    // set up
    struct EdgeData {
        InsetSegment fInset;
        SkPoint      fIntersection;
        SkScalar     fTValue;
        bool         fValid;
    };

    SkAutoSTMalloc<64, EdgeData> edgeData(inputPolygonSize);
    for (int i = 0; i < inputPolygonSize; ++i) {
        int j = (i + 1) % inputPolygonSize;
        SkOffsetSegment(inputPolygonVerts[i], inputPolygonVerts[j],
                        insetDistanceFunc(i), insetDistanceFunc(j),
                        winding,
                        &edgeData[i].fInset.fP0, &edgeData[i].fInset.fP1);
        edgeData[i].fIntersection = edgeData[i].fInset.fP0;
        edgeData[i].fTValue = SK_ScalarMin;
        edgeData[i].fValid = true;
    }

    int prevIndex = inputPolygonSize - 1;
    int currIndex = 0;
    int insetVertexCount = inputPolygonSize;
    while (prevIndex != currIndex) {
        if (!edgeData[prevIndex].fValid) {
            prevIndex = (prevIndex + inputPolygonSize - 1) % inputPolygonSize;
            continue;
        }

        SkScalar s, t;
        SkPoint intersection;
        if (compute_intersection(edgeData[prevIndex].fInset, edgeData[currIndex].fInset,
                                 &intersection, &s, &t)) {
            // if new intersection is further back on previous inset from the prior intersection
            if (s < edgeData[prevIndex].fTValue) {
                // no point in considering this one again
                edgeData[prevIndex].fValid = false;
                --insetVertexCount;
                // go back one segment
                prevIndex = (prevIndex + inputPolygonSize - 1) % inputPolygonSize;
            // we've already considered this intersection, we're done
            } else if (edgeData[currIndex].fTValue > SK_ScalarMin &&
                       intersection.equalsWithinTolerance(edgeData[currIndex].fIntersection,
                                                          1.0e-6f)) {
                break;
            } else {
                // add intersection
                edgeData[currIndex].fIntersection = intersection;
                edgeData[currIndex].fTValue = t;

                // go to next segment
                prevIndex = currIndex;
                currIndex = (currIndex + 1) % inputPolygonSize;
            }
        } else {
            // if prev to right side of curr
            int side = winding*compute_side(edgeData[currIndex].fInset.fP0,
                                            edgeData[currIndex].fInset.fP1,
                                            edgeData[prevIndex].fInset.fP1);
            if (side < 0 && side == winding*compute_side(edgeData[currIndex].fInset.fP0,
                                                         edgeData[currIndex].fInset.fP1,
                                                         edgeData[prevIndex].fInset.fP0)) {
                // no point in considering this one again
                edgeData[prevIndex].fValid = false;
                --insetVertexCount;
                // go back one segment
                prevIndex = (prevIndex + inputPolygonSize - 1) % inputPolygonSize;
            } else {
                // move to next segment
                edgeData[currIndex].fValid = false;
                --insetVertexCount;
                currIndex = (currIndex + 1) % inputPolygonSize;
            }
        }
    }

    // store all the valid intersections that aren't nearly coincident
    // TODO: look at the main algorithm and see if we can detect these better
    static constexpr SkScalar kCleanupTolerance = 0.01f;

    insetPolygon->reset();
    insetPolygon->setReserve(insetVertexCount);
    currIndex = -1;
    for (int i = 0; i < inputPolygonSize; ++i) {
        if (edgeData[i].fValid && (currIndex == -1 ||
            !edgeData[i].fIntersection.equalsWithinTolerance((*insetPolygon)[currIndex],
                                                             kCleanupTolerance))) {
            *insetPolygon->push() = edgeData[i].fIntersection;
            currIndex++;
        }
    }
    // make sure the first and last points aren't coincident
    if (currIndex >= 1 &&
        (*insetPolygon)[0].equalsWithinTolerance((*insetPolygon)[currIndex],
                                                 kCleanupTolerance)) {
        insetPolygon->pop();
    }
    SkASSERT(is_convex(*insetPolygon));

    return (insetPolygon->count() >= 3);
}