Нарисуйте квадратную кривую Безье через три заданные точки - PullRequest
24 голосов
/ 15 июля 2011

У меня есть три точки в 2D, и я хочу нарисовать квадратичную кривую Безье, проходящую через них.Как рассчитать среднюю контрольную точку (x1 и y1, как в quadTo)?Я знаю линейную алгебру из колледжа, но мне нужна простая помощь в этом.

Как рассчитать среднюю контрольную точку, чтобы кривая также проходила через нее?

Ответы [ 3 ]

49 голосов
/ 15 июля 2011

Пусть P0, P1, P2 - контрольные точки, а Pc - ваша фиксированная точка, через которую должна пройти кривая.

Тогда кривая Безье определяется как

P(t) = P0*t^2 + P1*2*t*(1-t) + P2*(1-t)^2

... где t переходит с нуля на 1.

Существует бесконечное количество ответов на ваш вопрос, поскольку он может пройти через вашу точку для любого значения t ... Так что просто выберите один, например, t = 0,5, и решите для P1:

Pc = P0*.25 + P1*2*.25 + P2*.25

P1 = (Pc - P0*.25 - P2*.25)/.5

   = 2*Pc - P0/2 - P2/2

Здесь значения «P» представляют собой (x, y) пары, поэтому просто примените уравнение один раз для x и один раз для y:

x1 = 2*xc - x0/2 - x2/2
y1 = 2*yc - y0/2 - y2/2

... где (xc, yc) - точка, через которую вы хотите пройти, (x0, y0) - начальная точка, а (x2, y2) - конечная точка. Это даст вам Безье, который проходит через (xc, yc) при t = 0,5.

4 голосов
/ 24 ноября 2014

Я использовал ответ Nemos в своем приложении JavaFX, но моя цель состояла в том, чтобы нарисовать кривую так, чтобы визуальная точка поворота кривой всегда соответствовала выбранной фиксированной (CP).

CP =ControlPoint
SP = StartPoint
EP = EndPoint
BP (t) = переменная Точка на BeziérCurve, где t находится в диапазоне от 0 до 1

Для этого я сделал переменную t (не исправить 0.5).Если выбранная точка CP больше не находится посередине между SP и EP, вам придется немного увеличить или уменьшить ее.В качестве первого шага вам нужно знать, ближе ли CP к SP или EP: пусть distanceSP будет расстоянием между CP и SP, а distanceEP - расстоянием между CP и EP, тогда я определю соотношение как:

ratio = (distanceSP - distanceEP) / (distanceSP + distanceEP);

Теперьмы собираемся использовать это, чтобы варьировать вверх и вниз:

ratio = 0.5 - (1/3) * ratio;

примечание: это все еще приближение, и 1/3 выбирается методом проб и ошибок.

Вот мой Java-Функция: (Point2D - это класс JavaFX)

private Point2D adjustControlPoint(Point2D start, Point2D end, Point2D visualControlPoint) {
    // CP = ControlPoint, SP = StartPoint, EP = EndPoint, BP(t) = variable Point on BeziérCurve where t is between 0 and 1
    // BP(t) = SP*t^2 + CP*2*t*(1-t) + EP*(1-t)^2
    // CP = (BP(t) - SP*t^2 - EP*(1-t)^2) / ( 2*t*(1-t) )
    // but we are missing t the goal is to approximate t
    double distanceStart  = visualControlPoint.distance(start);
    double distanceEnd    = visualControlPoint.distance(end);
    double ratio          = (distanceStart - distanceEnd) / (distanceStart + distanceEnd);
    // now approximate ratio to be t
    ratio = 0.5 - (1.0 / 3) * ratio;

    double ratioInv = 1 - ratio;
    Point2D term2 = start.multiply( ratio * ratio );
    Point2D term3 = end.multiply( ratioInv * ratioInv );
    double  term4 = 2 * ratio * ratioInv;

    return visualControlPoint.subtract(term2).subtract(term3).multiply( 1 / term4);
}

Надеюсь, это поможет.

1 голос
/ 10 июля 2014

Если вам не нужна точная средняя точка, скорее вы хотите любое значение для t (от 0 до 1), уравнение будет:

controlX = pointToPassThroughX/t - startX*t - endX*t;
controlY = pointToPassThroughY/t - startY*t - endY*t;

Конечно, это также будет работать для средней точки, просто установите t равным 0,5. Просто! : -)

...