三次贝塞尔公式返回错误的结果

问题描述 投票:0回答:2

我在Java中创建了一个非常简单的三次贝塞尔曲线形式,以便在给定时间(t)的情况下检索点的Y值。在我的实现中,我的第一个(P1)点和最后一个(P4)点分别始终分别是(0,0)和(1,1),而我只打算操纵P1和P2。这样做的目的是创建一条可修改的曲线,用于检索一个值,该值将用于乘法和操纵其他值,例如视频游戏中的难度提升。

我已经使用P2 =(0.1,0.1)和P3 =(0.9,0.9)测试了我的实现,因此曲线实际上应该是一条直线,无论我的输入值(t)是多少,输出都应该模仿:

Cubic Bézier with P2=(0.1, 0.1) and P3=(0.9,0.9)

这是我的CubicBezier课:

@AllArgsConstructor
public class CubicBezier {

    private static final Point P1 = new Point(0, 0);
    private static final Point P4 = new Point(1, 1);

    private Point p2;
    private Point p3;

    public double getValue(double t) {
        double dt = 1d - t;
        double dt2 = dt*dt;
        double t2 = t*t;

        Point temp = p2.copy();

        return P1.copy()
                 .scale(dt2 * dt)
                 .add(temp.scale(3 * dt2 * t))
                 .add(temp.set(p3).scale(3 * dt * t2))
                 .add(temp.set(P4).scale(t2 * t))
                 .getY();
    }
}

和我的Point类:

@Data
@AllArgsConstructor
public class Point {
    private double x;
    private double y;

    public Point(Point point) {
        this.x = point.x;
        this.y = point.y;
    }

    public Point copy() {
        return new Point(this);
    }

    public Point set(Point point) {
        this.x = point.x;
        this.y = point.y;
        return this;
    }

    public Point add(double scalar) {
        this.x += scalar;
        this.y += scalar;
        return this;
    }

    public Point add(double x, double y) {
        this.x += x;
        this.y += y;
        return this;
    }

    public Point add(Point point) {
        return add(point.x, point.y);
    }

    public Point scale(double scalar) {
        this.x *= scalar;
        this.y *= scalar;
        return this;
    }

    public Point scale(double x, double y) {
        this.x *= x;
        this.y *= y;
        return this;
    }

    public Point scale(Point point) {
        return scale(point.x, point.y);
    }

}

我的主要方法:

public static void main(String[] args) {
    CubicBezier bezier = new CubicBezier(new Point(0.1d, 0.1d), new Point(0.9d, 0.9d));

    double value = 0.4;
    System.out.println(value + ": " + bezier.getValue(value));
}

预期的输出应该是:

0.4: 0.4

但是,我收到的输出是:

0.4: 0.36640000000000006

而且我不明白为什么。我的getValue方法是使用Cubic Bézier explicit form specified on Wikipedia建模的。我想念什么吗?

注意:我正在使用Lombok删除一些样板。如果需要,我可以指定此样板。

编辑:

[因此,看来我的贝塞尔曲线实际上正在按预期方式工作,并且我一直误以为t作为x轴上的值,假设计算出的贝塞尔曲线的y值为相对于x轴。我想要的功能是,给定结果曲线,给定值x,并返回y值。因此,在上面的屏幕截图中,曲线是一条直线,x应该等于y

java bezier curve
2个回答
0
投票

您可能会在浮点运算中失去精度。

尝试使用BigDecimal代替double


0
投票

我想出了我问题的答案。我的代码从来没有任何错误,错误是缺乏理解。我假设因为P1p2p3P4都是在x和y轴上都位于0和1之间的直线上的点,所以无论它们位于该位置上线,时间将相同地反映进度,即x等于y

但是,由于p2p3分别更接近P0P4,所以沿曲线的进度相对于时间伸展开了。

为了使三次贝塞尔曲线具有与时间(y)值相同的级数(t),其中P1 = (0, 0)P4 = (1, 1)的两个内点都必须沿曲线均匀分布轴。因此,p2必须为(0.33333, 0.33333)p3必须为(0.66666, 0.66666)

this video here中显示了此问题的示例。当这些点分开时,结果值会受到影响。

© www.soinside.com 2019 - 2024. All rights reserved.