生成可变宽度曲线的控制点

时间:2014-09-09 12:56:01

标签: java javafx bezier

好的,所以我有一个应用程序,它使用连接到节点的可变宽度曲线,并且我使用一个控制点就可以正常工作。我自己生成控制点,具体取决于相对于它所连接的节点的曲线位置。因此,当节点的角度为0°,90°,180°,270°或360°时,曲线根本不会弯曲。

就像我说的那样,我只使用一个控制点,现在我想添加另一个控制点以获得更平滑的曲线..但是我无法理解我在这里做错了什么。

以下是相关的代码段。希望它们相对简单。

// Creates, or "projects" a Vector from the given angle and length
public static Point2D project(double angle, double length) {
    double x = length;
    double y = 0;

    double cos = Math.cos(Math.toRadians(angle - 90));
    double sin = Math.sin(Math.toRadians(angle - 90));

    double newX = x * cos - y * sin;
    double newY = x * sin + y * cos;

    return new Point2D(newX, newY);
}

// Linear interpolation
public static double lerp(double a, double b, double ratio) {
    return a + ratio * (b - a);
}

// Linear interpolation for a line
public static Point2D interpolate(Point2D start, Point2D end, double ratio) {
    double x = lerp(start.getX(), end.getX(), ratio);
    double y = lerp(start.getY(), end.getY(), ratio);
    return new Point2D(x, y);
}

// Generates one (or two) control points for a Bezier Curve
public static PointPair calculateCurveControls(Point2D from, Point2D to, double angle) {

    double curvatureAmount = 0;
    double curvatureDirection = 0;

    if (angle >= 0 && angle <= 45) {
        curvatureDirection = 90;
        curvatureAmount = lerp(0, 1, angle / 45);
    }
    if (angle > 45 && angle <= 90) {
        curvatureDirection = 90;
        curvatureAmount = lerp(1, 0, (angle - 45) / 45);
    }
    if (angle > 90 && angle <= 135) {
        curvatureDirection = -90;
        curvatureAmount = lerp(0, 1, (angle - 90) / 45);
    }
    if (angle > 135 && angle <= 180) {
        curvatureDirection = -90;
        curvatureAmount = lerp(1, 0, (angle - 135) / 45);
    }
    if (angle > 180 && angle <= 225) {
        curvatureDirection = 90;
        curvatureAmount = lerp(0, 1, (angle - 180) / 45);
    }
    if (angle > 225 && angle <= 270) {
        curvatureDirection = 90;
        curvatureAmount = lerp(1, 0, (angle - 225) / 45);
    }
    if (angle > 270 && angle <= 315) {
        curvatureDirection = -90;
        curvatureAmount = lerp(0, 1, (angle - 270) / 45);
    }
    if (angle > 315 && angle <= 360) {
        curvatureDirection = -90;
        curvatureAmount = lerp(1, 0, (angle - 315) / 45);
    }

    double distance = from.distance(to);

    // Only one control point, this works just fine!
    // Point2D midpoint = interpolate(from, to, 0.5);
    // Point2D c1 = project(angle + curvatureDirection + 180, curvatureAmount * (distance * 0.15f));
    //  c1 = c1.add(midpoint);
    // Point2D c2 = new Point2D(c1.getX(), c1.getY());

    // An attempt to generate two control points
    Point2D first = interpolate(from, to, 0.25);
    Point2D second = interpolate(from, to, 0.75);

    Point2D c1 = project(angle + curvatureDirection + 180, curvatureAmount * (distance * 0.15));
    c1 = c1.add(first);

    Point2D c2 = project(angle + curvatureDirection + 180, curvatureAmount * (distance * 0.15));
    c2 = c2.add(second);

    return new PointPair(c1, c2);
}

我在我的应用程序中创建了一些视觉辅助工具来显示控制点和曲线的直线......但我仍然不能为我的生活弄清楚我做错了什么..控件无论曲线的角度如何,它们看起来都处于正确的位置。

我有一种预感,我在&#34;渲染&#34;代码的一部分,但是当我只使用一个控制点时(即两个控制点都相同),它可以正常工作。它在这里:

// A method from a custom Curve class, which uses a Path to render a variable width curve

public void set(Point2D from, Point2D to) {
            path.getElements().clear();

            this.from = from;
            this.to = to;

            if (developerMode) {
                line.setStartX(from.getX());
                line.setStartY(from.getY());

                line.setEndX(to.getX());
                line.setEndY(to.getY());
            }

            double angle = Utils.angle(from, to);

            Point2D leftStart = Utils.project(angle - 90, thicknessStart / 2);
            leftStart = leftStart.add(from);
            MoveTo moveLeftStart = new MoveTo();
            moveLeftStart.setX(leftStart.getX());
            moveLeftStart.setY(leftStart.getY());

            Point2D leftEnd = Utils.project(angle - 90, thicknessEnd / 2);
            leftEnd = leftEnd.add(to);
            MoveTo moveLeftEnd = new MoveTo();
            moveLeftEnd.setX(leftEnd.getX());
            moveLeftEnd.setY(leftEnd.getY());

            Point2D rightStart = Utils.project(angle + 90, thicknessStart / 2);
            rightStart = rightStart.add(from);
            MoveTo moveRightStart = new MoveTo();
            moveRightStart.setX(rightStart.getX());
            moveRightStart.setY(rightStart.getY());

            Point2D rightEnd = Utils.project(angle + 90, thicknessEnd / 2);
            rightEnd = rightEnd.add(to);
            MoveTo moveRightEnd = new MoveTo();
            moveRightEnd.setX(rightEnd.getX());
            moveRightEnd.setY(rightEnd.getY());

            Utils.PointPair cc1 = Utils.calculateCurveControls(leftStart, leftEnd, angle);

            CubicCurveTo curveLeft = new CubicCurveTo();
            curveLeft.setX(leftEnd.getX());
            curveLeft.setY(leftEnd.getY());
            curveLeft.setControlX1(cc1.p1.getX());
            curveLeft.setControlY1(cc1.p1.getY());
            curveLeft.setControlX2(cc1.p2.getX());
            curveLeft.setControlY2(cc1.p2.getY());

            if (developerMode) {
                c11.setLayoutX(cc1.p1.getX());
                c11.setLayoutY(cc1.p1.getY());
                c12.setLayoutX(cc1.p2.getX());
                c12.setLayoutY(cc1.p2.getY());
            }

            Utils.PointPair cc2 = Utils.calculateCurveControls(rightStart, rightEnd, angle);

            CubicCurveTo curveRight = new CubicCurveTo();
            curveRight.setX(rightStart.getX());
            curveRight.setY(rightStart.getY());
            curveRight.setControlX1(cc2.p1.getX());
            curveRight.setControlY1(cc2.p1.getY());
            curveRight.setControlX2(cc2.p2.getX());
            curveRight.setControlY2(cc2.p2.getY());

            if (developerMode) {
                c21.setLayoutX(cc2.p1.getX());
                c21.setLayoutY(cc2.p1.getY());
                c22.setLayoutX(cc2.p2.getX());
                c22.setLayoutY(cc2.p2.getY());
            }

            path.getElements().add(moveLeftStart);
            path.getElements().add(curveLeft);
            path.getElements().add(new LineTo(moveRightEnd.getX(), moveRightEnd.getY()));
            path.getElements().add(curveRight);
            path.getElements().add(new LineTo(moveLeftStart.getX(), moveLeftStart.getY()));
        }

以下是错误曲线曲线的截图,曲线与控制点之间的线:http://i.imgur.com/JG21U0T.png

非常感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

我完美地运作了!我唯一错误的是我绘制了正确的曲线&#34;颠倒了#34;所以我只需要将第一个控制点作为第二个控制点传递。