示例#1
0
bool SkOpAngle::merge(SkOpAngle* angle) {
    SkASSERT(fNext);
    SkASSERT(angle->fNext);
    SkOpAngle* working = angle;
    do {
        if (this == working) {
            return false;
        }
        working = working->fNext;
    } while (working != angle);
    do {
        SkOpAngle* next = working->fNext;
        working->fNext = NULL;
        insert(working);
        working = next;
    } while (working != angle);
    // it's likely that a pair of the angles are unorderable
#if DEBUG_ANGLE
    SkOpAngle* last = angle;
    working = angle->fNext;
    do {
        SkASSERT(last->fNext == working);
        last->fNext = working->fNext;
        SkASSERT(working->after(last));
        last->fNext = working;
        last = working;
        working = working->fNext;
    } while (last != angle);
#endif
    debugValidateNext();
    return true;
}
示例#2
0
bool SkOpAngle::checkParallel(const SkOpAngle& rh) const {
    SkDVector scratch[2];
    const SkDVector* sweep, * tweep;
    if (!fUnorderedSweep) {
        sweep = fSweep;
    } else {
        scratch[0] = fCurvePart[1] - fCurvePart[0];
        sweep = &scratch[0];
    }
    if (!rh.fUnorderedSweep) {
        tweep = rh.fSweep;
    } else {
        scratch[1] = rh.fCurvePart[1] - rh.fCurvePart[0];
        tweep = &scratch[1];
    }
    double s0xt0 = sweep->crossCheck(*tweep);
    if (tangentsDiverge(rh, s0xt0)) {
        return s0xt0 < 0;
    }
    SkDVector m0 = fSegment->dPtAtT(midT()) - fCurvePart[0];
    SkDVector m1 = rh.fSegment->dPtAtT(rh.midT()) - rh.fCurvePart[0];
    double m0xm1 = m0.crossCheck(m1);
    if (m0xm1 == 0) {
        fUnorderable = true;
        rh.fUnorderable = true;
        return true;
    }
    return m0xm1 < 0;
}
示例#3
0
// returns -1 if overlaps   0 if no overlap cw    1 if no overlap ccw
int SkOpAngle::convexHullOverlaps(const SkOpAngle& rh) const {
    const SkDVector* sweep = fSweep;
    const SkDVector* tweep = rh.fSweep;
    double s0xs1 = sweep[0].crossCheck(sweep[1]);
    double s0xt0 = sweep[0].crossCheck(tweep[0]);
    double s1xt0 = sweep[1].crossCheck(tweep[0]);
    bool tBetweenS = s0xs1 > 0 ? s0xt0 > 0 && s1xt0 < 0 : s0xt0 < 0 && s1xt0 > 0;
    double s0xt1 = sweep[0].crossCheck(tweep[1]);
    double s1xt1 = sweep[1].crossCheck(tweep[1]);
    tBetweenS |= s0xs1 > 0 ? s0xt1 > 0 && s1xt1 < 0 : s0xt1 < 0 && s1xt1 > 0;
    double t0xt1 = tweep[0].crossCheck(tweep[1]);
    if (tBetweenS) {
        return -1;
    }
    if ((s0xt0 == 0 && s1xt1 == 0) || (s1xt0 == 0 && s0xt1 == 0)) {  // s0 to s1 equals t0 to t1
        return -1;
    }
    bool sBetweenT = t0xt1 > 0 ? s0xt0 < 0 && s0xt1 > 0 : s0xt0 > 0 && s0xt1 < 0;
    sBetweenT |= t0xt1 > 0 ? s1xt0 < 0 && s1xt1 > 0 : s1xt0 > 0 && s1xt1 < 0;
    if (sBetweenT) {
        return -1;
    }
    // if all of the sweeps are in the same half plane, then the order of any pair is enough
    if (s0xt0 >= 0 && s0xt1 >= 0 && s1xt0 >= 0 && s1xt1 >= 0) {
        return 0;
    }
    if (s0xt0 <= 0 && s0xt1 <= 0 && s1xt0 <= 0 && s1xt1 <= 0) {
        return 1;
    }
    // if the outside sweeps are greater than 180 degress:
        // first assume the inital tangents are the ordering
        // if the midpoint direction matches the inital order, that is enough
    SkDVector m0 = fSegment->dPtAtT(midT()) - fCurvePart[0];
    SkDVector m1 = rh.fSegment->dPtAtT(rh.midT()) - rh.fCurvePart[0];
    double m0xm1 = m0.crossCheck(m1);
    if (s0xt0 > 0 && m0xm1 > 0) {
        return 0;
    }
    if (s0xt0 < 0 && m0xm1 < 0) {
        return 1;
    }
    if (tangentsDiverge(rh, s0xt0)) {
        return s0xt0 < 0;
    }
    return m0xm1 < 0;
}
示例#4
0
bool SkOpAngle::orderable(const SkOpAngle& rh) const {
    int result;
    if (!fIsCurve) {
        if (!rh.fIsCurve) {
            double leftX = fTangentHalf.dx();
            double leftY = fTangentHalf.dy();
            double rightX = rh.fTangentHalf.dx();
            double rightY = rh.fTangentHalf.dy();
            double x_ry = leftX * rightY;
            double rx_y = rightX * leftY;
            if (x_ry == rx_y) {
                if (leftX * rightX < 0 || leftY * rightY < 0) {
                    return true;  // exactly 180 degrees apart
                }
                goto unorderable;
            }
            SkASSERT(x_ry != rx_y); // indicates an undetected coincidence -- worth finding earlier
            return x_ry < rx_y;
        }
        if ((result = allOnOneSide(rh)) >= 0) {
            return result;
        }
        if (fUnorderable || approximately_zero(rh.fSide)) {
            goto unorderable;
        }
    } else if (!rh.fIsCurve) {
        if ((result = rh.allOnOneSide(*this)) >= 0) {
            return !result;
        }
        if (rh.fUnorderable || approximately_zero(fSide)) {
            goto unorderable;
        }
    }
    if ((result = convexHullOverlaps(rh)) >= 0) {
        return result;
    }
    return endsIntersect(rh);
unorderable:
    fUnorderable = true;
    rh.fUnorderable = true;
    return true;
}
示例#5
0
 static int ConvexHullOverlaps(SkOpAngle& lh, SkOpAngle& rh) {
     return lh.convexHullOverlaps(&rh);
 }
示例#6
0
 static int AllOnOneSide(SkOpAngle& lh, SkOpAngle& rh) {
     return lh.lineOnOneSide(&rh, false);
 }
示例#7
0
 static int After(SkOpAngle& lh, SkOpAngle& rh) {
     return lh.after(&rh);
 }
示例#8
0
/*(
for quads and cubics, set up a parameterized line (e.g. LineParameters )
for points [0] to [1]. See if point [2] is on that line, or on one side
or the other. If it both quads' end points are on the same side, choose
the shorter tangent. If the tangents are equal, choose the better second
tangent angle

maybe I could set up LineParameters lazily
*/
bool SkOpAngle::operator<(const SkOpAngle& rh) const {
    double y = dy();
    double ry = rh.dy();
    if ((y < 0) ^ (ry < 0)) {  // OPTIMIZATION: better to use y * ry < 0 ?
        return y < 0;
    }
    double x = dx();
    double rx = rh.dx();
    if (y == 0 && ry == 0 && x * rx < 0) {
        return x < rx;
    }
    double x_ry = x * ry;
    double rx_y = rx * y;
    double cmp = x_ry - rx_y;
    if (!approximately_zero(cmp)) {
        return cmp < 0;
    }
    if (approximately_zero(x_ry) && approximately_zero(rx_y)
            && !approximately_zero_squared(cmp)) {
        return cmp < 0;
    }
    // at this point, the initial tangent line is coincident
    // see if edges curl away from each other
    if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide)
            || !approximately_zero(rh.fSide))) {
        // FIXME: running demo will trigger this assertion
        // (don't know if commenting out will trigger further assertion or not)
        // commenting it out allows demo to run in release, though
        return fSide < rh.fSide;
    }
    // see if either curve can be lengthened and try the tangent compare again
    if (/* cmp && */ (*fSpans)[fEnd].fOther != rh.fSegment  // tangents not absolutely identical
            && (*rh.fSpans)[rh.fEnd].fOther != fSegment) {  // and not intersecting
        SkOpAngle longer = *this;
        SkOpAngle rhLonger = rh;
        if (longer.lengthen() | rhLonger.lengthen()) {
            return longer < rhLonger;
        }
    }
    if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y))
            || (rh.fVerb == SkPath::kLine_Verb
            && approximately_zero(rx) && approximately_zero(ry))) {
        // See general unsortable comment below. This case can happen when
        // one line has a non-zero change in t but no change in x and y.
        fUnsortable = true;
        rh.fUnsortable = true;
        return this < &rh;  // even with no solution, return a stable sort
    }
    if ((*rh.fSpans)[SkMin32(rh.fStart, rh.fEnd)].fTiny
            || (*fSpans)[SkMin32(fStart, fEnd)].fTiny) {
        fUnsortable = true;
        rh.fUnsortable = true;
        return this < &rh;  // even with no solution, return a stable sort
    }
    SkASSERT(fVerb >= SkPath::kQuad_Verb);
    SkASSERT(rh.fVerb >= SkPath::kQuad_Verb);
    // FIXME: until I can think of something better, project a ray from the
    // end of the shorter tangent to midway between the end points
    // through both curves and use the resulting angle to sort
    // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
    double len = fTangent1.normalSquared();
    double rlen = rh.fTangent1.normalSquared();
    SkDLine ray;
    SkIntersections i, ri;
    int roots, rroots;
    bool flip = false;
    do {
        bool useThis = (len < rlen) ^ flip;
        const SkDCubic& part = useThis ? fCurvePart : rh.fCurvePart;
        SkPath::Verb partVerb = useThis ? fVerb : rh.fVerb;
        ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(part[1]) ?
            part[2] : part[1];
        ray[1].fX = (part[0].fX + part[partVerb].fX) / 2;
        ray[1].fY = (part[0].fY + part[partVerb].fY) / 2;
        SkASSERT(ray[0] != ray[1]);
        roots = (i.*CurveRay[fVerb])(fPts, ray);
        rroots = (ri.*CurveRay[rh.fVerb])(rh.fPts, ray);
    } while ((roots == 0 || rroots == 0) && (flip ^= true));
    if (roots == 0 || rroots == 0) {
        // FIXME: we don't have a solution in this case. The interim solution
        // is to mark the edges as unsortable, exclude them from this and
        // future computations, and allow the returned path to be fragmented
        fUnsortable = true;
        rh.fUnsortable = true;
        return this < &rh;  // even with no solution, return a stable sort
    }
    SkDPoint loc;
    double best = SK_ScalarInfinity;
    SkDVector dxy;
    double dist;
    int index;
    for (index = 0; index < roots; ++index) {
        loc = (*CurveDPointAtT[fVerb])(fPts, i[0][index]);
        dxy = loc - ray[0];
        dist = dxy.lengthSquared();
        if (best > dist) {
            best = dist;
        }
    }
    for (index = 0; index < rroots; ++index) {
        loc = (*CurveDPointAtT[rh.fVerb])(rh.fPts, ri[0][index]);
        dxy = loc - ray[0];
        dist = dxy.lengthSquared();
        if (best > dist) {
            return fSide < 0;
        }
    }
    return fSide > 0;
}
示例#9
0
 static int After(const SkOpAngle& lh, const SkOpAngle& rh) {
     return lh.after(&rh);
 }
示例#10
0
// FIXME: this and find chase should be merge together, along with
// other code that walks winding in angles
// OPTIMIZATION: Probably, the walked winding should be rolled into the angle structure
// so it isn't duplicated by walkers like this one
static SkOpSegment* findChaseOp(SkTDArray<SkOpSpan*>& chase, int& nextStart, int& nextEnd) {
    while (chase.count()) {
        SkOpSpan* span;
        chase.pop(&span);
        const SkOpSpan& backPtr = span->fOther->span(span->fOtherIndex);
        SkOpSegment* segment = backPtr.fOther;
        nextStart = backPtr.fOtherIndex;
        SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
        int done = 0;
        if (segment->activeAngle(nextStart, &done, &angles)) {
            SkOpAngle* last = angles.end() - 1;
            nextStart = last->start();
            nextEnd = last->end();
   #if TRY_ROTATE
            *chase.insert(0) = span;
   #else
            *chase.append() = span;
   #endif
            return last->segment();
        }
        if (done == angles.count()) {
            continue;
        }
        SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
        bool sortable = SkOpSegment::SortAngles(angles, &sorted,
                SkOpSegment::kMayBeUnordered_SortAngleKind);
        int angleCount = sorted.count();
#if DEBUG_SORT
        sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, sortable);
#endif
        if (!sortable) {
            continue;
        }
        // find first angle, initialize winding to computed fWindSum
        int firstIndex = -1;
        const SkOpAngle* angle;
        bool foundAngle = true;
        do {
            ++firstIndex;
            if (firstIndex >= angleCount) {
                foundAngle = false;
                break;
            }
            angle = sorted[firstIndex];
            segment = angle->segment();
        } while (segment->windSum(angle) == SK_MinS32);
        if (!foundAngle) {
            continue;
        }
    #if DEBUG_SORT
        segment->debugShowSort(__FUNCTION__, sorted, firstIndex, sortable);
    #endif
        int sumMiWinding = segment->updateWindingReverse(angle);
        int sumSuWinding = segment->updateOppWindingReverse(angle);
        if (segment->operand()) {
            SkTSwap<int>(sumMiWinding, sumSuWinding);
        }
        int nextIndex = firstIndex + 1;
        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
        SkOpSegment* first = NULL;
        do {
            SkASSERT(nextIndex != firstIndex);
            if (nextIndex == angleCount) {
                nextIndex = 0;
            }
            angle = sorted[nextIndex];
            segment = angle->segment();
            int start = angle->start();
            int end = angle->end();
            int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
            segment->setUpWindings(start, end, &sumMiWinding, &sumSuWinding,
                    &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
            if (!segment->done(angle)) {
                if (!first) {
                    first = segment;
                    nextStart = start;
                    nextEnd = end;
                }
                (void) segment->markAngle(maxWinding, sumWinding, oppMaxWinding,
                    oppSumWinding, angle);
            }
        } while (++nextIndex != lastIndex);
        if (first) {
       #if TRY_ROTATE
            *chase.insert(0) = span;
       #else
            *chase.append() = span;
       #endif
            return first;
        }
    }
    return NULL;
}
示例#11
0
SkOpSegment* FindChase(SkTDArray<SkOpSpan*>& chase, int& tIndex, int& endIndex) {
    while (chase.count()) {
        SkOpSpan* span;
        chase.pop(&span);
        const SkOpSpan& backPtr = span->fOther->span(span->fOtherIndex);
        SkOpSegment* segment = backPtr.fOther;
        tIndex = backPtr.fOtherIndex;
        SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
        int done = 0;
        if (segment->activeAngle(tIndex, &done, &angles)) {
            SkOpAngle* last = angles.end() - 1;
            tIndex = last->start();
            endIndex = last->end();
   #if TRY_ROTATE
            *chase.insert(0) = span;
   #else
            *chase.append() = span;
   #endif
            return last->segment();
        }
        if (done == angles.count()) {
            continue;
        }
        SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
        bool sortable = SkOpSegment::SortAngles(angles, &sorted,
                SkOpSegment::kMayBeUnordered_SortAngleKind);
        int angleCount = sorted.count();
#if DEBUG_SORT
        sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
#endif
        if (!sortable) {
            continue;
        }
        // find first angle, initialize winding to computed fWindSum
        int firstIndex = -1;
        const SkOpAngle* angle;
        int winding;
        do {
            angle = sorted[++firstIndex];
            segment = angle->segment();
            winding = segment->windSum(angle);
        } while (winding == SK_MinS32);
        int spanWinding = segment->spanSign(angle->start(), angle->end());
    #if DEBUG_WINDING
        SkDebugf("%s winding=%d spanWinding=%d\n",
                __FUNCTION__, winding, spanWinding);
    #endif
        // turn span winding into contour winding
        if (spanWinding * winding < 0) {
            winding += spanWinding;
        }
    #if DEBUG_SORT
        segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
    #endif
        // we care about first sign and whether wind sum indicates this
        // edge is inside or outside. Maybe need to pass span winding
        // or first winding or something into this function?
        // advance to first undone angle, then return it and winding
        // (to set whether edges are active or not)
        int nextIndex = firstIndex + 1;
        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
        angle = sorted[firstIndex];
        winding -= angle->segment()->spanSign(angle);
        do {
            SkASSERT(nextIndex != firstIndex);
            if (nextIndex == angleCount) {
                nextIndex = 0;
            }
            angle = sorted[nextIndex];
            segment = angle->segment();
            int maxWinding = winding;
            winding -= segment->spanSign(angle);
    #if DEBUG_SORT
            SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
                    segment->debugID(), maxWinding, winding, angle->sign());
    #endif
            tIndex = angle->start();
            endIndex = angle->end();
            int lesser = SkMin32(tIndex, endIndex);
            const SkOpSpan& nextSpan = segment->span(lesser);
            if (!nextSpan.fDone) {
            // FIXME: this be wrong? assign startWinding if edge is in
            // same direction. If the direction is opposite, winding to
            // assign is flipped sign or +/- 1?
                if (SkOpSegment::UseInnerWinding(maxWinding, winding)) {
                    maxWinding = winding;
                }
                segment->markAndChaseWinding(angle, maxWinding, 0);
                break;
            }
        } while (++nextIndex != lastIndex);
        *chase.insert(0) = span;
        return segment;
    }
    return NULL;
}
示例#12
0
 static int EndsIntersect(const SkOpAngle& lh, const SkOpAngle& rh) {
     return lh.endsIntersect(rh);
 }
示例#13
0
 static int Orderable(const SkOpAngle& lh, const SkOpAngle& rh) {
     return lh.orderable(rh);
 }
示例#14
0
 static int ConvexHullOverlaps(const SkOpAngle& lh, const SkOpAngle& rh) {
     return lh.convexHullOverlaps(rh);
 }
示例#15
0
 static int Orderable(SkOpAngle& lh, SkOpAngle& rh) {
     return lh.orderable(&rh);
 }
示例#16
0
 static int EndsIntersect(SkOpAngle& lh, SkOpAngle& rh) {
     return lh.endsIntersect(&rh);
 }
示例#17
0
static void testOne(skiatest::Reporter* reporter, const SortSetTests& test) {
    SkTDArray<SkOpAngle> angles;
    bool unsortable = false;
    bool unorderable = false;
    SkTArray<SkOpSegment> segs;
    for (size_t idx = 0; idx < test.count; ++idx) {
        int ts[2];
        const SortSet* set = test.set;
        SkOpSegment& seg = segs.push_back();
        setup(set, idx, &seg, ts, test.startPt);
        SkOpAngle* angle = angles.append();
        angle->set(&seg, ts[0], ts[1]);
#if DEBUG_ANGLE
        angle->setID(idx);
#endif
        if (angle->unsortable()) {
#if DEBUG_ANGLE
            SkDebugf("%s test[%s]:  angle[%d] unsortable\n", __FUNCTION__, test.name, idx);
#endif
            unsortable = true;
        }
        if (angle->unorderable()) {
#if DEBUG_ANGLE
            SkDebugf("%s test[%s]:  angle[%d] unorderable\n", __FUNCTION__, test.name, idx);
#endif
            unorderable = true;
        }
        reporter->bumpTestCount();
    }
    if (unsortable || unorderable) {
        return;
    }
#if DEBUG_ANGLE
    SkDebugf("%s test[%s]\n", __FUNCTION__, test.name);
#endif
    for (size_t idxL = 0; idxL < test.count; ++idxL) {
        const SkOpAngle& first = angles[idxL];
        for (size_t idxG = 0; idxG < test.count; ++idxG) {
            if (idxL == idxG) {
                continue;
            }
            const SkOpAngle& second = angles[idxG];
            bool compare = first < second;
            if (idxL < idxG) {
                if (!compare) {
                    SkDebugf("%s test[%s]:  first[%d] > second[%d]\n", __FUNCTION__,
                            test.name,  idxL,  idxG);
                    compare = first < second;
                }
                REPORTER_ASSERT(reporter, compare);
            } else {
                SkASSERT(idxL > idxG);
                if (compare) {
                    SkDebugf("%s test[%s]:  first[%d] < second[%d]\n", __FUNCTION__,
                            test.name,  idxL,  idxG);
                    compare = first < second;
                }
                REPORTER_ASSERT(reporter, !compare);
            }
            compare = second < first;
            if (idxL < idxG) {
                if (compare) {
                    SkDebugf("%s test[%s]:  second[%d] < first[%d]\n", __FUNCTION__,
                            test.name,  idxL,  idxG);
                    compare = second < first;
                }
                REPORTER_ASSERT(reporter, !compare);
            } else {
                SkASSERT(idxL > idxG);
                if (!compare) {
                    SkDebugf("%s test[%s]:  second[%d] > first[%d]\n", __FUNCTION__,
                            test.name,  idxL,  idxG);
                    compare = second < first;
                }
                REPORTER_ASSERT(reporter, compare);
            }
        }
    }
}