Куби c формула Безье, возвращающая неверный результат - PullRequest
0 голосов
/ 17 января 2020

Я создал очень простую форму Куби c Безье в Java, чтобы получить значение Y для найденной точки по времени (t). В моей реализации Мои первая (P1) и последняя (P4) точки всегда (0, 0) и (1, 1) соответственно, и я собираюсь манипулировать только P1 и P2. Цель этого состоит в том, чтобы создать изменяемую кривую, используемую для извлечения значения, которое будет использоваться для умножения и манипулирования другими значениями, например, нарастание сложности в видеоиграх.

Я протестировал свою реализацию с использованием P2 = ( 0,1, 0,1) и P3 = (0,9,0,9), поэтому кривая должна фактически быть прямой линией, и каково бы ни было мое входное значение (t), выходной сигнал должен mimi c:

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 моделируется с использованием явной формы Cubi c Bézier, указанной в Википедии . Я что-то упустил?

Примечание: я использую Lombok, чтобы удалить шаблон. Я могу указать этот шаблон в случае необходимости.

РЕДАКТИРОВАТЬ:

Таким образом, похоже, что моя кривая Безье на самом деле работает, как и должно, и что я принял t в качестве значения на ось x, предполагая, что значение y рассчитанной кривой Безье будет относительно оси x. Функциональность, которую я хочу, заключается в том, чтобы с полученной кривой, учитывая значение x, возвращалось значение y в отношении. Так на скриншоте выше, где кривая - прямая линия, x должно равняться y.

1 Ответ

1 голос
/ 18 января 2020

Я разобрался с ответом на мой вопрос. С моим кодом никогда не было ничего плохого, ошибка заключалась в отсутствии понимания. Я предполагал, что, поскольку P1, p2, p3 и P4 - это все точки, которые лежат на прямой линии между 0 и 1 по осям x и y, что независимо от того, где они расположены линия, время будет отражать прогрессию одинаково, то есть x будет равно y.

Однако, поскольку p2 и p3 ближе к P0 и P4 соответственно, прогрессия вдоль кривая растянута относительно времени.

Чтобы кривая Куби c Безье имела то же значение прогрессии (y), что и значение времени (t), где P1 = (0, 0) и P4 = (1, 1), обе внутренние точки должны равномерно распределяться по кривой на обеих осях. Так что p2 должно быть (0.33333, 0.33333) и p3 должно быть (0.66666, 0.66666).

Пример этой проблемы показан в это видео здесь . Когда точки разбросаны, это влияет на результирующее значение.

...