2

我想在两个形状(本问题中的矩形)之间生成一条贝塞尔曲线,使曲线以 90 度角与形状相交。这是一个 MS Paint 生成的示例:

示例曲线

出于我的目的,可以假设角度只需要垂直于轴,而不是任意的东西。也就是说,曲线在端点处的角度只需为 0、90、180 或 270 度即可。

我对贝塞尔曲线的理解告诉我,我需要 2 个端点和 2 个控制点。端点很容易计算,但我对如何操作控制点只有一个基本的了解。

有没有方便的公式来完成这个?我很难找到相关的教程。

我正在使用 Java,目前正在使用 java.awt.geom.Path2D.Double.curveTo() 绘制曲线。如果有一个预先构建的 Java 类或方法来实现这一点,那将是理想的,但如果需要,我愿意自己实现一个算法或方程。

4

2 回答 2

2

基于 Sage 的出色回答,并在玩了一段时间http://www.openprocessing.org/sketch/2123之后,这就是我的最终结果。

将控制点与您要创建的角度共线会将曲线拉向该方向。控制点离端点越远,效果就越明显。由于我只处理 90 度角,这意味着我可以将控制点的 x 或 y 坐标改变设定的距离(我像 Sage 一样将其称为 delta)以产生所需的效果。我没有使用任何花哨的东西来找到 delta - 我只是尝试了几个值,直到找到一个我满意的值。

这是我的最终代码片段。

public class BezierCurve {
    private CubicCurve2D curve;

    private static final int delta = 100;

    private double x1, y1, x2, y2;
    private double ctrlx1, ctrly1, ctrlx2, ctrly2;

    public BezierCurve(Point p1, Side side1, Point p2, Side side2) {
        this.x1 = p1.x;
        this.y1 = p1.y;
        this.x2 = p2.x;
        this.y2 = p2.y;

        Point ctrl1 = getControlPoint(p1, side1);
        Point ctrl2 = getControlPoint(p2, side2);

        ctrlx1 = ctrl1.x;
        ctrly1 = ctrl1.y;
        ctrlx2 = ctrl2.x;
        ctrly2 = ctrl2.y;

        curve = new CubicCurve2D.Double();
        curve.setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
    }

    private Point getControlPoint(Point p, Side s) {
        int x = p.x;
        int y = p.y;

        switch (s) {
        case Left:
            x -= delta;
            break;
        case Right:
            x += delta;
            break;
        case Bottom:
            y += delta;
            break;
        case Top:
            y -= delta;
            break;
        }
        return new Point(x, y);
    }

    public void draw(Graphics2D g2) {
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.draw(curve);
    }
}

这将处理顶部、底部、右侧和左侧的每种情况。

这是运行中的代码的屏幕截图。

在此处输入图像描述

于 2013-11-14T03:27:18.267 回答
1

智能使用Class CubicCurve2D应该可以实现你想要的:CubicCurve2D类实现了Shape接口。此类表示(x, y)坐标空间中的三次参数曲线段。CubicCurve2D.FloatCubicCurve2D.Double子类指定三次曲线floatdouble精度。

此类setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2); 允许设置两个控制点。如果我们在曲线开始之前(ctrlx1, ctrly1)和曲线结束之后设置控制点(ctrlx2, ctrly2)。为了保持曲线的角度为90度数的倍数,我们可以类似地计算控制点,如下所示(计算为90 deegree):

ctrlx1 = x1; // curve start x
ctrly1 = y2 - delta; // curve start y
ctrlx2 = x1 + delta; // curve end x
ctrly2 = y2; // curve end y

在下面的例子中,我假设了delta = 10

在此处输入图像描述

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g); 

    Graphics2D g2d = (Graphics2D) g.create();
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    CubicCurve2D c = new CubicCurve2D.Double();
    int x1 = 150, y1 = 150;  //p1
    int x2 = 350, y2 = 300;//p3
    int ctrlx1, ctrly1, ctrlx2, ctrly2;
    int delta = 10;

    ctrlx1 = x1; // curve start x
    ctrly1 = y2 - delta; // curve start y
    ctrlx2 = x1 + delta; // curve end x
    ctrly2 = y2; 

    g2d.drawRect(x1-50, y1-100, 100, 100);
    c.setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
    g2d.drawRect(x2, y2-50, 100, 100);
    g2d.draw(c);
}
于 2013-11-06T17:29:30.267 回答