从UIBezierpath获取积分

在这里输入图像说明

我通过这样做了上面的BezierPath://位置是用户触摸屏幕的地方。 //位置将是图的最大值CGPoint origin = CGPointMake(xStart,620.0); CGPoint endpt = CGPointMake(xEnd,620.0); CGPoint midpt1 = midPointForPoints(origin,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]; 

现在,我想检索位于path上的某些x坐标的y坐标。 例如,给定x = 0.0,我想得到y = 0.0,或者给定x = 300.0,y = 50.0。

我看了一些像这个问题和示例代码的引用,我仍然不确定。 更新:基本上,我想要做这样的事情。 在这里输入图像说明

更新:继方达的build议:

给定方程

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

我解决了

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

要么

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

使用这个值,find对应于X的Y(我们用X来find上面的t值)

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

根据上面的等式,我应该得到位于贝塞尔曲线上的点的y值,但是我得到了一个远离正确的点。 任何进一步的帮助将非常感激..

关注:我认为一个可能的问题是,我用两个控制点调用addQuadCurveToPoint()两次,而不是一次用两个控制点。 这是否意味着我绘制了两条贝塞尔path并将它们结合起来? 我也看着这看看我的计算有什么问题,唯一的区别似乎是他调用addQuadCurveToPoint()时使用两个控制点。

方舟子激烈的咨询后更新:

 - (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); } 

最后一个问题:对于第二个Bezeirpath,y值应该随着t值的增加而减小。 现在,y值不断增加。 我应该如何解决这个问题? 经过深入debugging,我还没有find为什么发生这种情况,因为一切都符合文件。

沿着Bezierpath应该可以得到点,因为addQuadCurveToPoint是将二次Bezier段添加到path中。 所以,你的第一个二次贝塞尔曲线的三个控制点是(参考原始文章中的代码段)

P(0)=原点
P(1)=(midpt1.x,midpt1.y + 50)
P(2)=地点

您可以根据需要在该二次贝塞尔曲线上计算任意多点,方法是将参数t从0增加到1,并使用任意小增量值

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

要从给定的X值得到Y值,必须从t的二次多项式中求出给定X值的t值:

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

其中X0,X1和X2是P(0),P(1)和P(2)的X坐标,这意味着X0 = origin.x,X1 = midpt1.x,X2 = location.x。

由此,我们可以得到一个二次方程

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

你可以使用二次公式解决t。 如果你的X0,X1和X2值碰巧使t ^ 2项的系数为零,你可以直接求解为t =(X-X0)/(2 *(X1-X0))。

一旦你有t值,你可以很容易地评估相应的Y值。

CGPath是不透明的数据types,即。 在这种情况下,我们只能得到我们在创build时定义的点,例如。 你创build的图表,只有三点可以获得。

像示例代码一样,您可以使用CGPathApply获取这些点。 如果您在代码后添加下面的代码,则会输出3个点。

  ... [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)]; } } 

所以,简而言之,就像你所要求的x / y对应关系那样,你不可能得到那个图上的每一个坐标。