2011-11-06 34 views
14

Estoy usando UIBezierPath, pero esta pregunta se refiere a puntos de control para las rutas, no al dibujo. Dado un conjunto de puntos, puedo renderizar un camino. Sin embargo, no he podido averiguar cómo calcular los puntos de control para tener una línea suave como en un editor de curvas de fotos (How to implement a Photoshop Curves editor in UIKit).cómo calcular los puntos de control para una ruta sin problemas dado un conjunto de puntos?

La respuesta más cercana que he visto es aquí: how can i trace the finger movement on touch for drawing smooth curves?

Sin embargo, todavía no puedo comprender el cálculo apropiado. Para resumirlo en código:

for (int i = 0; i< points; i++) 
{ 
    ... 

    [path addQuadCurveToPoint:nextPoint controlPoint:WTF]; 
} 
+5

El silencio es tan fuerte que duele. – akaru

+0

¿Desea que la curva pase exactamente por cada uno de sus puntos dados? ¿O quieres una curva más suave que pueda pasar cerca de algunos de los puntos dados? –

+0

@robmayoff Supongo que cerrar es lo suficientemente bueno si se trata de una operación mucho más simple. – akaru

Respuesta

12

La imagen se ha vinculado a un ejemplo que no utiliza curvas cuadráticas, así que voy a correr con la imagen y no el código.

Una ruta bezier en ios (y os x) debajo es básicamente una lista de comandos y puntos de dibujo. por ejemplo:

[path moveTo:CGMakePoint(1,1)]; 
[path curveToPoint:(10,10) controPoint1:(3,7) controlPoint2:(4,1)]; 
[path curveToPoint:(10,10) controPoint1:(15,17) controlPoint2:(21,11)]; 
[path closePath]; 

Resultados en:

moveto (1,1)  
curveto (10,10) (3,7) (4,1) 
curveto (20,0) (15,17) (21,11)  
closepath 

puntos de control en un trazado Bézier controlar la dirección y la velocidad de la curva de un punto. El primer punto de control (cp) controla la dirección y la velocidad de la curva que sale del punto anterior y el segundo cp controla el mismo para el punto al que se está curvando. Para una curva cuadrática (lo que obtiene usando addQuadCurveToPoint: controlPoint:), ambos puntos son los mismos, como se puede ver en los documentos para el método here.

Obtener una curva suave a lo largo de un conjunto de puntos implica hacer que cp1 y cp2 sean colineales entre sí y esa línea sea paralela a los puntos en cada extremo de ese segmento.

Annotated curve

Esto sería algo como:

[path moveTo:2]; 
[path curveTo:3 controlPoint1:cp1 controlPoint2:cp2]; 

CP1 y CP2 se pueden calcular por la elección de alguna longitud de la línea constante y haciendo un poco de geometría (no recuerdo todos mis ecuaciones de línea en este momento pero están re easily googleable)

Va a usar # -> # para designar un segmento y # -> # (cp #) para designar un punto de control para la llamada de ese segmento.

El siguiente problema es hacer que la curva sea suave desde el segmento 2-> 3 que va hacia el segmento 3-> 4. En este punto de su código, debe tener un punto de control calculado para 2-> 3 (cp2). Teniendo en cuenta la longitud de línea constante desde antes (esto controlará qué tan afilada de una curva se obtiene), puede calcular una cp1 para 3-> 4 obteniendo un punto colineal con 2-> 3 (cp2) y el punto 3 en el diagrama. Luego calcule un 3-> 4 (cp2) que es colineal con 3-> 4 (cp1) y paralelo a la línea que marca el punto 3 y el punto 4. Enjuague y repita a través de su matriz de puntos.

+1

Gracias por la respuesta. Desafortunadamente, después de leer los enlaces, aún no puedo determinar el método correcto. Yo culpo a mi cerebro. – akaru

+0

No hay forma de que escriba código para calcular los puntos de control. –

4

No estoy seguro de cuánto esto ayudará, pero tuve que hacer algo similar para implementar una ruta curva para las notas a seguir en esta aplicación, (www.app.net/hereboy). Esencialmente, es un camino con tres curvas.

Para hacer esto creé 4 puntos por curva, un punto de inicio, un punto final y dos puntos de control en la marca del 25% y la marca del 75%.

Este es el código que escribí para hacer esto:

//create points along the keypath for curve. 
CGMutablePathRef curvedPath = CGPathCreateMutable(); 
const int TOTAL_POINTS = 3; 
int horizontalWiggle = 15; 

int stepChangeX = (endPoint.x - viewOrigin.x)/TOTAL_POINTS; 
int stepChangeY = (endPoint.y - viewOrigin.y)/TOTAL_POINTS; 

for(int i = 0; i < TOTAL_POINTS; i++) { 
    int startX = (int)(viewOrigin.x + i * stepChangeX); 
    int startY = (int)(viewOrigin.y + i * stepChangeY); 

    int endX = (int)(viewOrigin.x + (i+1) * stepChangeX); 
    int endY = (int)(viewOrigin.y + (i+1) * stepChangeY); 

    int cpX1 = (int)(viewOrigin.x + (i+0.25) * stepChangeX); 
    if((i+1)%2) { 
     cpX1 -= horizontalWiggle; 
    } else { 
     cpX1 += horizontalWiggle; 
    } 
    int cpY1 = (int)(viewOrigin.y + (i+0.25) * stepChangeY); 

    int cpX2 = (int)(viewOrigin.x + (i+0.75) * stepChangeX); 
    if((i+1)%2) { 
     cpX2 -= horizontalWiggle; 
    } else { 
     cpX2 += horizontalWiggle; 
    } 
    int cpY2 = (int)(viewOrigin.y + (i+0.75) * stepChangeY); 

    CGPathMoveToPoint(curvedPath, NULL, startX, startY); 
    CGPathAddCurveToPoint(curvedPath, NULL, cpX1, cpY1, cpX2, cpY2, endX, endY); 
} 

Buena suerte!

Cuestiones relacionadas