示例#1
0
bool isLinear(const Cubic& cubic, int startIndex, int endIndex) {
    LineParameters lineParameters;
    lineParameters.cubicEndPoints(cubic, startIndex, endIndex);
    // FIXME: maybe it's possible to avoid this and compare non-normalized
    lineParameters.normalize();
    double distance = lineParameters.controlPtDistance(cubic, 1);
    if (!approximately_zero(distance)) {
        return false;
    }
    distance = lineParameters.controlPtDistance(cubic, 2);
    return approximately_zero(distance);
}
示例#2
0
bool isLinear(const Cubic& cubic, int startIndex, int endIndex) {
    LineParameters lineParameters;
    lineParameters.cubicEndPoints(cubic, startIndex, endIndex);
    double normalSquared = lineParameters.normalSquared();
    double distance[2]; // distance is not normalized
    int mask = other_two(startIndex, endIndex);
    int inner1 = startIndex ^ mask;
    int inner2 = endIndex ^ mask;
    lineParameters.controlPtDistance(cubic, inner1, inner2, distance);
    double limit = normalSquared;
    int index;
    for (index = 0; index < 2; ++index) {
        double distSq = distance[index];
        distSq *= distSq;
        if (approximately_greater(distSq, limit)) {
            return false;
        }
    }
    return true;
}
示例#3
0
void LineParameter_Test() {
    for (size_t index = firstLineParameterTest; index < tests_count; ++index) {
        LineParameters lineParameters;
        const Cubic& cubic = tests[index];
        lineParameters.cubicEndPoints(cubic);
        double denormalizedDistance[2];
        denormalizedDistance[0] = lineParameters.controlPtDistance(cubic, 1);
        denormalizedDistance[1] = lineParameters.controlPtDistance(cubic, 2);
        double normalSquared = lineParameters.normalSquared();
        size_t inner;
        for (inner = 0; inner < 2; ++inner) {
            double distSq = denormalizedDistance[inner];
            distSq *= distSq;
            double answersSq = answers[index][inner];
            answersSq *= answersSq;
            if (AlmostEqualUlps(distSq, normalSquared * answersSq)) {
                continue;
            }
            SkDebugf("%s [%d,%d] denormalizedDistance:%g != answer:%g"
                    " distSq:%g answerSq:%g normalSquared:%g\n",
                    __FUNCTION__, (int)index, (int)inner,
                    denormalizedDistance[inner], answers[index][inner],
                    distSq, answersSq, normalSquared);
        }
        lineParameters.normalize();
        double normalizedDistance[2];
        normalizedDistance[0] = lineParameters.controlPtDistance(cubic, 1);
        normalizedDistance[1] = lineParameters.controlPtDistance(cubic, 2);
        for (inner = 0; inner < 2; ++inner) {
            if (AlmostEqualUlps(fabs(normalizedDistance[inner]), answers[index][inner])) {
                continue;
            }
            SkDebugf("%s [%d,%d] normalizedDistance:%1.10g != answer:%g\n",
                    __FUNCTION__, (int)index, (int)inner,
                    normalizedDistance[inner], answers[index][inner]);
        }
    }
}
示例#4
0
static int check_linear(const Cubic& cubic, Cubic& reduction,
        int minX, int maxX, int minY, int maxY) {
    int startIndex = 0;
    int endIndex = 3;
    while (cubic[startIndex].approximatelyEqual(cubic[endIndex])) {
        --endIndex;
        if (endIndex == 0) {
            printf("%s shouldn't get here if all four points are about equal", __FUNCTION__);
            assert(0);
        }
    }
    LineParameters lineParameters;
    lineParameters.cubicEndPoints(cubic, startIndex, endIndex);
    double normalSquared = lineParameters.normalSquared();
    double distance[2]; // distance is not normalized
    int mask = other_two(startIndex, endIndex);
    int inner1 = startIndex ^ mask;
    int inner2 = endIndex ^ mask;
    lineParameters.controlPtDistance(cubic, inner1, inner2, distance);
    double limit = normalSquared * SquaredEpsilon;
    int index;
    for (index = 0; index < 2; ++index) {
        double distSq = distance[index];
        distSq *= distSq;
        if (distSq > limit) {
            return 0;
        }
    }
    // four are colinear: return line formed by outside
    reduction[0] = cubic[0];
    reduction[1] = cubic[3];
    int sameSide1;
    int sameSide2;
    bool useX = cubic[maxX].x - cubic[minX].x >= cubic[maxY].y - cubic[minY].y;
    if (useX) {
        sameSide1 = sign(cubic[0].x - cubic[1].x) + sign(cubic[3].x - cubic[1].x);
        sameSide2 = sign(cubic[0].x - cubic[2].x) + sign(cubic[3].x - cubic[2].x);
    } else {
        sameSide1 = sign(cubic[0].y - cubic[1].y) + sign(cubic[3].y - cubic[1].y);
        sameSide2 = sign(cubic[0].y - cubic[2].y) + sign(cubic[3].y - cubic[2].y);
    }
    if (sameSide1 == sameSide2 && (sameSide1 & 3) != 2) {
        return 2;
    }
    double tValues[2];
    int roots;
    if (useX) {
        roots = SkFindCubicExtrema(cubic[0].x, cubic[1].x, cubic[2].x, cubic[3].x, tValues);
    } else {
        roots = SkFindCubicExtrema(cubic[0].y, cubic[1].y, cubic[2].y, cubic[3].y, tValues);
    }
    for (index = 0; index < roots; ++index) {
        _Point extrema;
        extrema.x = interp_cubic_coords(&cubic[0].x, tValues[index]);
        extrema.y = interp_cubic_coords(&cubic[0].y, tValues[index]);
        // sameSide > 0 means mid is smaller than either [0] or [3], so replace smaller
        int replace;
        if (useX) {
            if (extrema.x < cubic[0].x ^ extrema.x < cubic[3].x) {
                continue;
            }
            replace = (extrema.x < cubic[0].x | extrema.x < cubic[3].x)
                    ^ cubic[0].x < cubic[3].x;
        } else {
            if (extrema.y < cubic[0].y ^ extrema.y < cubic[3].y) {
                continue;
            }
            replace = (extrema.y < cubic[0].y | extrema.y < cubic[3].y)
                    ^ cubic[0].y < cubic[3].y;
        }
        reduction[replace] = extrema;
    }
    return 2;
}
示例#5
0
// return false if unable to clip (e.g., unable to create implicit line)
// caller should subdivide, or create degenerate if the values are too small
bool bezier_clip(const Cubic& cubic1, const Cubic& cubic2, double& minT, double& maxT) {
    minT = 1;
    maxT = 0;
    // determine normalized implicit line equation for pt[0] to pt[3]
    //   of the form ax + by + c = 0, where a*a + b*b == 1
    
    // find the implicit line equation parameters
    LineParameters endLine;
    endLine.cubicEndPoints(cubic1);
    if (!endLine.normalize()) {
        printf("line cannot be normalized: need more code here\n");
        return false;
    }

    double distance[2];
    endLine.controlPtDistance(cubic1, distance);
    
    // find fat line
    double top = distance[0];
    double bottom = distance[1];
    if (top > bottom) {
        std::swap(top, bottom);
    }
    if (top * bottom >= 0) {
        const double scale = 3/4.0; // http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf (13)
        if (top < 0) {
            top *= scale;
            bottom = 0;
        } else {
            top = 0;
            bottom *= scale;
        }
    } else {
        const double scale = 4/9.0; // http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf (15)
        top *= scale;
        bottom *= scale;
    }
    
    // compute intersecting candidate distance
    Cubic distance2y; // points with X of (0, 1/3, 2/3, 1)
    endLine.cubicDistanceY(cubic2, distance2y);
    
    int flags = 0;
    if (approximately_lesser(distance2y[0].y, top)) {
        flags |= kFindTopMin;
    } else if (approximately_greater(distance2y[0].y, bottom)) {
        flags |= kFindBottomMin;
    } else {
        minT = 0;
    }

    if (approximately_lesser(distance2y[3].y, top)) {
        flags |= kFindTopMax;
    } else if (approximately_greater(distance2y[3].y, bottom)) {
        flags |= kFindBottomMax;
    } else {
        maxT = 1;
    }
    // Find the intersection of distance convex hull and fat line.
    char to_0[2];
    char to_3[2];
    bool do_1_2_edge = convex_x_hull(distance2y, to_0, to_3);
    x_at(distance2y[0], distance2y[to_0[0]], top, bottom, flags, minT, maxT);
    if (to_0[0] != to_0[1]) {
        x_at(distance2y[0], distance2y[to_0[1]], top, bottom, flags, minT, maxT);
    }
    x_at(distance2y[to_3[0]], distance2y[3], top, bottom, flags, minT, maxT);
    if (to_3[0] != to_3[1]) {
        x_at(distance2y[to_3[1]], distance2y[3], top, bottom, flags, minT, maxT);
    }
    if (do_1_2_edge) {
        x_at(distance2y[1], distance2y[2], top, bottom, flags, minT, maxT);
    }
    
    return minT < maxT; // returns false if distance shows no intersection
}