Obtenga puntos de un UIBezierPath

introduzca la descripción de la imagen aquí

Dibujé el BezierPath anterior haciendo: // la location es donde el usuario toca la pantalla. // location será el máximo del gráfico CGPoint origin = CGPointMake (xStart, 620.0); CGPoint endpt = CGPointMake (xEnd, 620.0); CGPoint midpt1 = midPointForPoints (origen, location); CGPoint midpt2 = midPointForPoints (location, endpt);

UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:origin]; [path addQuadCurveToPoint:location controlPoint:CGPointMake(midpt1.x, midpt1.y+50)]; [path addQuadCurveToPoint:endpt controlPoint:CGPointMake(midpt2.x, midpt2.y+50)]; [shapeLayer setPath:path.CGPath]; 

Ahora, quiero recuperar coorderadas y para ciertas coorderadas x que se encuentran en la ruta. Por ejemplo, dado x = 0.0, quiero get y = 0.0, o dar x = 300.0, y = 50.0.

Miré algunas references como esta pregunta y el código de ejemplo , todavía no estoy seguro. Actualización: básicamente, quiero hacer algo como esto. introduzca la descripción de la imagen aquí

Actualización: Siguiendo el consejo de @ Fang:

Dada la ecuación

 X = (1-t)^2*X0 + 2*t*(1-t)*X1 + t^2 *X2 

Resuelvo por t

 t = ((2.0 * x0 - x1) + sqrt(((-2.0 * x0 + x1) ** 2.0) - ((4 * (x0 - 2.0 * x1 + x2)) * (x0 - x)))) / (2.0 * (x0 - 2.0 * x1 + x2)) 

o

 t = ((2.0 * x0 - x1) - sqrt(((-2.0 * x0 + x1) ** 2.0) - ((4 * (x0 - 2.0 * x1 + x2)) * (x0 - x)))) / (2.0 * (x0 - 2.0 * x1 + x2)) 

Usando este valor, encuentre Y que corresponda a X (usamos X para encontrar el valor t anterior)

 Y = (1-t)^2*Y0 + 2*t*(1-t)*Y1 + t^2 *Y2 

Siguiendo la ecuación anterior, se supone que debo get el valor y del punto que se encuentra en la curva de Bézier, pero obtengo un punto que está muy lejos del correcto. Cualquier otra ayuda será muy apreciada.

Preocupación: Creo que un posible problema es que estoy llamando a addQuadCurveToPoint() dos veces con dos puntos de control en lugar de una vez con dos puntos de control. ¿Significa que dibujo dos paths de Bezier y los combino? También miro esto para ver qué ocurre con mi cálculo y la única diferencia parece ser que usa dos puntos de control al llamar a addQuadCurveToPoint() .

Actualización después de la intensa consulta de Fang:

 - (float)getYFromBezierPath:(float)x location:(CGPoint)location ctrlpt1:(CGPoint)ctrlpt1 ctrlpt2:(CGPoint)ctrlpt2 endpt:(CGPoint)endpt { float yVal; float tVal; if (x <= location.x) { tVal = [self getTvalFromBezierPath:x x0Val:0.0 x1Val:ctrlpt1.x x2Val:location.x]; yVal = [self getCoordFromBezierPath:tVal origin:0.0 p1Val:ctrlpt1.y p2Val:location.y]; } else { // THIS PART IS THE PROBLEM // tVal = [self getTvalFromBezierPath:x x0Val:location.x x1Val:ctrlpt2.x x2Val:endpt.x]; yVal = [self getCoordFromBezierPath:tVal origin:location.y p1Val:ctrlpt2.y p2Val:endpt.y]; } return yVal; } - (float)getTvalFromBezierPath:(float)x x0Val:(float)x0 x1Val:(float)x1 x2Val:(float)x2 { float tVal = (x-x0)/(2*(x1-x0)); return tVal; } - (float)getCoordFromBezierPath:(float)t origin: (float)origin p1Val: (float)p1 p2Val: (float)p2 { // tVal = (sqrt((-2.0 * x * x1) + (x * x0) + (x * x2) + pow(x1, 2) - (x0 * x2)) + x0 - x1) / (x0 - (2.0 * x1) + x2); return (pow((1-t),2) * origin) + (2 * t * (1-t) * p1) + (pow(t,2) * p2); } 

Última pregunta: para el segundo path de Bezeir, el valor de y debería disminuir a medida que aumenta el valor de t. En este momento, el valor y sigue aumentando. ¿Cómo debería arreglar esto? Después de una debugging intensiva, no he encontrado por qué sucede esto porque todo se ajusta al documento.

Debería ser posible get puntos a lo largo de una ruta Bezier como addQuadCurveToPoint para agregar un segmento Bezier cuadrático en la ruta. Entonces, los tres puntos de control de su primera curva de Bezier cuadrática son (consulte la pieza de código en la publicación original)

P (0) = origen
P (1) = (midpt1.x, midpt1.y + 50)
P (2) = location

Puede calcular tantos puntos en esta curva de Bezier cuadrática como desee variando el parámetro t de 0 a 1 por cualquier pequeño valor de incremento como

C (t) = (1-t) ^ 2 * P (0) + 2 * t * (1-t) * P (1) + t ^ 2 * P (2)

Para get el valor Y de un valor X dado, tendrá que resolver para el valor t del valor X dado a partir de este polinomio cuadrático de t:

X = (1-t) ^ 2 * X0 + 2 * t * (1-t) * X1 + t ^ 2 * X2

donde X0, X1 y X2 son las coorderadas X de P (0), P (1) y P (2), lo que significa X0 = origen.x, X1 = midpt1.x y X2 = location.x.

A partir de esto, podemos get una ecuación cuadrática

(X0-2 * X1 + X2) t ^ 2 + 2 (X1-X0) * t + (X0-X) = 0

Puedes resolver para t usando la fórmula cuadrática. Si sus valores X0, X1 y X2 hacen que el coeficiente de t ^ 2 sea cero, puede resolver t directamente como t = (X-X0) / (2 * (X1-X0)).

Una vez que tenga el valor t, puede evaluar fácilmente el valor Y correspondiente.

CGPath es un tipo de datos opaco, es decir. en este caso, solo podemos get los puntos en los que definimos la creación, como, por ejemplo, El gráfico que crea, solo hay tres puntos que se pueden get.

Al igual que el código de muestra, obtienes esos puntos usando CGPathApply. Si anexa el código siguiente después de sus códigos, arrojará 3 puntos.

  ... [shapeLayer setPath:path.CGPath]; NSMutableArray *keyPoints = [NSMutableArray array]; CGPathApply(path.CGPath, (__bridge void *)keyPoints, getPointsFromBezier); NSLog(@"Points = %@", points); } // copied from the sample code. void getPointsFromBezier(void *info, const CGPathElement *element) { NSMutableArray *bezierPoints = (__bridge NSMutableArray *)info; CGPathElementType type = element->type; CGPoint *points = element->points; if (type != kCGPathElementCloseSubpath) { if ((type == kCGPathElementAddLineToPoint) || (type == kCGPathElementMoveToPoint)) [bezierPoints addObject:VALUE(0)]; else if (type == kCGPathElementAddQuadCurveToPoint) [bezierPoints addObject:VALUE(1)]; else if (type == kCGPathElementAddCurveToPoint) [bezierPoints addObject:VALUE(2)]; } } 

Por lo tanto, en resumen, no puede get todas las coorderadas individuales en ese gráfico como lo requería dada su contraparte x / y.