Saltar al contenido

Dibujar una curva de Bézier cuadrática a través de tres puntos dados

Después de mucho luchar hemos hallado la solución de esta cuestión que tantos lectores de nuestra web presentan. Si tienes algún dato que aportar puedes compartir tu comentario.

Solución:

Sean P0, P1, P2 los puntos de control y Pc el punto fijo por el que desea que pase la curva.

Entonces la curva de Bezier está definida por

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

…donde t va de cero a 1.

Hay un número infinito de respuestas a tu pregunta, ya que podría pasar por tu punto para cualquier valor de t… Así que elige una, como t=0.5, y resuelve para P1:

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

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

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

Allí, los valores “P” son pares (x, y), así que solo aplica la ecuación una vez para x y otra para y:

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

…donde (xc,yc) es el punto por el que quieres que pase, (x0,y0) es el punto inicial y (x2,y2) es el punto final. Esto le dará un Bézier que pasa por (xc,yc) en t=0.5.

He usado la respuesta de Nemos en mi aplicación JavaFX, pero mi objetivo era dibujar la curva, de modo que el punto de inflexión visual de la curva siempre coincida con el fijo elegido (CP).

CP = Punto de control
SP = Punto de inicio
EP = punto final
BP(t) = Punto variable en BeziérCurve donde t está entre 0 y 1

Para lograr esto, hice una variable t (no fija 0.5). Si el Punto CP elegido ya no está en el medio entre SP y EP, debe variar t hacia arriba o hacia abajo un poco. Como primer paso, necesita saber si CP está más cerca de SP o EP: Deje que la distancia SP sea la distancia entre CP y SP y la distancia EP la distancia entre CP y EP, entonces defino la relación como:

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

Ahora vamos a usar esto para variar t hacia arriba y hacia abajo:

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

nota: esto sigue siendo una aproximación y 1/3 se elige por prueba y error.

Aquí está mi función Java: (Point2D es una clase de 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);

Espero que esto ayude.

Si no desea el punto medio exacto, sino cualquier valor para t (0 a 1), la ecuación es:

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

Por supuesto, esto también funcionará para el punto medio, simplemente establezca t en 0.5. ¡Simple! 🙂

Puntuaciones y comentarios

Si te ha resultado de ayuda este artículo, nos gustaría que lo compartas con el resto desarrolladores de esta manera contrubuyes a difundir este contenido.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *