2010-10-30 32 views
15

Imagine que tiene una curva de Bezier de cuatro puntos completamente normal (dos puntos y dos puntos de control) creados con curveToPoint: controlPoint1: controlPoint2: en la aplicación de cacao:Encuentra un punto, una distancia dada, a lo largo de una curva de bezier cúbica simple. (! En un iPhone)

simple cubic bezier curve example
Cómo hacer encuentras puntos (y las tangentes), a lo largo de la curva?


Más tarde: para un completa, simplificada, solución basado en la respuesta de Michal a continuación, hacer clic en:
Find the tangent of a point on a cubic bezier curve (on an iPhone)

Y simplemente copia y pega el código de: https://stackoverflow.com/a/31317254/294884

Respuesta

28

Hay un poco Con la matemática simple detrás del cálculo de las posiciones, puede leer al respecto en cada artículo que analiza las curvas de Bézier, incluso en la wikipedia. De todos modos, puedo relacionarme con todos los que tienen problemas para implementarlo en código, así que escribí este ejemplo de UIView ya que probablemente sea la forma más fácil de comenzar.

#import "MBBezierView.h" 

CGFloat bezierInterpolation(CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d) { 
    CGFloat t2 = t * t; 
    CGFloat t3 = t2 * t; 
    return a + (-a * 3 + t * (3 * a - a * t)) * t 
    + (3 * b + t * (-6 * b + b * 3 * t)) * t 
    + (c * 3 - c * 3 * t) * t2 
    + d * t3; 
} 

@implementation MBBezierView 

- (void)drawRect:(CGRect)rect { 
    CGPoint p1, p2, p3, p4; 
    p1 = CGPointMake(30, rect.size.height * 0.33); 
    p2 = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect)); 
    p3 = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect)); 
    p4 = CGPointMake(-30 + CGRectGetMaxX(rect), rect.size.height * 0.66); 

    [[UIColor blackColor] set]; 
    [[UIBezierPath bezierPathWithRect:rect] fill]; 

    [[UIColor redColor] setStroke]; 

    UIBezierPath *bezierPath = [[[UIBezierPath alloc] init] autorelease]; 
    [bezierPath moveToPoint:p1]; 
    [bezierPath addCurveToPoint:p4 controlPoint1:p2 controlPoint2:p3]; 
    [bezierPath stroke]; 

    [[UIColor brownColor] setStroke]; 
    for (CGFloat t = 0.0; t <= 1.00001; t += 0.05) { 
     CGPoint point = CGPointMake(bezierInterpolation(t, p1.x, p2.x, p3.x, p4.x), bezierInterpolation(t, p1.y, p2.y, p3.y, p4.y)); 
     UIBezierPath *pointPath = [UIBezierPath bezierPathWithArcCenter:point radius:5 startAngle:0 endAngle:2*M_PI clockwise:YES]; 
     [pointPath stroke]; 
    } 
} 

@end 

Esto es lo que me sale:

alt text

+1

¡math es divertido! +1! – slf

+3

@Joe Blow: ¿esto es realmente lo que querías? Dijiste que querías un punto que sea una distancia D a lo largo de la curva. Michal, corrígeme si me equivoco, pero tu código solo evalúa la curva en diferentes valores de parámetros, que no es lo mismo que la longitud. Como puede ver, los puntos están más juntos en los picos y más separados en el medio de la curva. – CromTheDestroyer

+0

Hola Crom: tienes toda la razón, están APROXIMADAMENTE equidistantes a lo largo de la curva.Aparentemente, no hay una manera realmente fácil matemáticamente de obtener espacios EXACTOS. Esta aproximación común funciona bien para motores de juegos y similares. Véase también 4089443. – Fattie

0

Cualquier curva de Bézier puede ser simplemente visto como una función polinómica con coeficientes complejos o vectores. Una curva Beziér cúbica como la que se muestra en la captura de pantalla se generaría mediante una función polinómica de orden 3, y cada punto de la curva describe el resultado B (t) del polinomio de curva, evaluado para un valor de entrada particular t. Si no me equivoco, una vez que conozca el polinomio utilizado para crear la curva, puede simplemente resolver por B (t) = a + bi, donde a + bi describe el punto en el plano complejo que desea encuentre el valor de t para. Encontrar raíces en polinomios como ese es un problema bien entendido, y se puede resolver algebraicamente para curvas de orden 2 o menores, y usando algún método como forward-newton para polinomios de mayor grado. Si conoces el polinomio generador, también debería ser muy simple encontrar los derivados. Beziér usualmente se extrae de "polinomios de plantilla" donde solo los coeficientes se cambian cuando se dibuja una curva diferente, por lo que probablemente pueda buscarla en algún lugar de la documentación.

3

La aproximación de que t es la distancia a lo largo de la curva que está proponiendo Michal puede ser problemático con algunas curvas y para algunos propósitos. Tristemente he buscado sin suerte durante bastante tiempo una implementación de Obj-C de la solución correcta.

La solución es, sin embargo, descrita de una manera bastante fantástica por Mike "Pomax" Kamermans en su sorprendente Primer on Bezier Curves. Incluso tiene todo el código, escrito en el procesamiento y en el dominio público. Estoy sorprendido de que nadie haya convertido esto en Obj-C todavía. Muy tentado, eso soy.

+0

Enlace asombrosamente útil @Daniel - gracias. Magnífico. Esta es una de esas páginas ... http://pomax.github.io/bezierinfo ... ¡eso es "simplemente demasiado útil"! Je. De nuevo, gracias, el enlace es tan útil que te estoy enriqueciendo. Increíble. – Fattie

+1

jajaja, me alegra que la cartilla encuentre un uso. Avíseme si encuentra algo faltante o poco claro = P –

Cuestiones relacionadas