Obtenir des points d'un UIBezierPath

entrez la description de l'image ici

J'ai dessiné le BezierPath ci-dessus en faisant: // location est où l'user touche l'écran. // l'location sera le maximum du graphique CGPoint origin = CGPointMake (xStart, 620.0); CGPoint endpt = CGPointMake (xEnd, 620.0); CGPoint midpt1 = midPointForPoints (origine, 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]; 

Maintenant, je veux récupérer les coordonnées y pour certaines coordonnées x qui se trouvent sur le path. Par exemple, étant donné x = 0.0, je veux get y = 0.0 ou x = 300.0, y = 50.0.

J'ai regardé quelques references comme cette question et l' échantillon de code que je ne suis pas encore sûr. Mise à jour: fondamentalement, je veux faire quelque chose comme ça. entrez la description de l'image ici

Mise à jour: Suivant le conseil de @ Fang:

Étant donné l'équation

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

Je résous pour 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)) 

ou

 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)) 

En utilisant cette valeur, trouvez Y qui correspond à X (nous avons utilisé X pour find la valeur t ci-dessus)

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

En suivant l'équation ci-dessus, je suis supposé get la valeur y du point qui se trouve sur la courbe de Bézier mais je reçois un point qui est loin du bon. Toute aide supplémentaire sera très appréciée.

Préoccupation: Je pense qu'un problème possible est que addQuadCurveToPoint() deux fois avec deux points de contrôle au lieu d'une fois avec deux points de contrôle. Cela signifie-t-il que je dessine deux paths de Bézier et que je les combine? Je regarde aussi ceci pour voir ce qui ne va pas avec mon calcul et la seule différence semble être qu'il utilise deux points de contrôle lors de l'appel de addQuadCurveToPoint() .

Mise à jour après l'intense consultation 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); } 

Dernière question: pour le second path Bezeir, la valeur y devrait diminuer à mesure que la valeur t augmente. À l'heure actuelle, la valeur y continue d'augmenter. Comment devrais-je résoudre ce problème? Après un debugging intensif, je n'ai pas trouvé pourquoi cela se produit parce que tout est conforme au document.

Il devrait être possible d'get des points le long d'un path de Bézier car addQuadCurveToPoint consiste à append un segment de Bézier quadratique dans le path. Ainsi, les trois points de contrôle de votre première courbe de Bézier quadratique sont (se référer à la pièce de code dans le message original)

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

Vous pouvez calculer autant de points que vous le souhaitez sur cette courbe de Bézier quadratique en faisant varier le paramètre t de 0 à 1 de n'importe quelle petite valeur d'incrément

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

Pour get la valeur Y à partir d'une valeur X donnée, vous devrez résoudre pour la valeur t de la valeur X donnée à partir de ce polynôme quadratique de t:

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

où X0, X1 et X2 sont les coordonnées X de P (0), P (1) et P (2), ce qui signifie que X0 = origine.x, X1 = milieu 1.x et X2 = location.x.

A partir de cela, nous pouvons get une équation quadratique

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

Vous pouvez résoudre pour t en utilisant la formule quadratique. Si vos valeurs X0, X1 et X2 arrivent à rendre le coefficient de t ^ 2 terme zéro, vous pouvez résoudre pour t directement comme t = (X-X0) / (2 * (X1-X0)).

Une fois que vous avez la valeur t, vous pouvez facilement évaluer la valeur Y correspondante.

CGPath est des types de données opaques, ie. dans ce cas, nous ne pouvons get que les points sur lesquels nous définissons sur la création, comme par exemple. le graphique que vous créez, il n'y a que trois points qui peuvent être obtenus.

Comme l'exemple de code, vous obtenez ces points en utilisant CGPathApply. Si vous ajoutez le code ci-dessous après vos codes, il produira 3 points.

  ... [shapeLayer setPath:path.CGPath]; NSMutableArray *keyPoints = [NSMutableArray array]; CGPathApply(path.CGPath, (__bridge void *)keyPoints, getPointsFromBezier); NSLog(@"Points = %@", points); } // copyd 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)]; } } 

Donc, en bref, vous ne pouvez pas get toutes les coordonnées sur ce graphique comme vous le souhaitez étant donné sa contrepartie x / y.