- (UIBezierPath*)pathForPoints:(NSArray*)allPoints {
UIBezierPath *path = [UIBezierPath bezierPath];
CGFloatmLineSmoothness =0.18;
CGFloatprePreviousPointX;
CGFloatprePreviousPointY;
CGFloatpreviousPointX;
CGFloatpreviousPointY;
CGFloatcurrentPointX;
CGFloatcurrentPointY;
CGFloatnextPointX;
CGFloatnextPointY;
for(inti =0; i < allPoints.count; i++) {
CGPointcurrentPoint = [allPoints[i]CGPointValue];
currentPointX = currentPoint.x;
currentPointY = currentPoint.y;
if(i >0) {
CGPointprePoint = [allPoints[i-1]CGPointValue];
previousPointX = prePoint.x;
previousPointY = prePoint.y;
}else{
previousPointX = currentPointX;
previousPointY = currentPointY;
}
if(i >1) {
CGPointprePrePoint = [allPoints[i-2]CGPointValue];
prePreviousPointX = prePrePoint.x;
prePreviousPointY = prePrePoint.y;
}
if(i < allPoints.count-1) {
CGPointnextPoint = [allPoints[i+1]CGPointValue];
nextPointX = nextPoint.x;
nextPointY = nextPoint.y;
}else{
nextPointX = currentPointX;
nextPointY = currentPointY;
}
if(i ==0) {
[pathmoveToPoint:currentPoint];
}else{
CGFloatfirstDiffX = (currentPointX - prePreviousPointX);
CGFloatfirstDiffY = (currentPointY - prePreviousPointY);
CGFloatsecondDiffX = (nextPointX - previousPointX);
CGFloatsecondDiffY = (nextPointY - previousPointY);
CGFloatfirstControlPointX = previousPointX + (mLineSmoothness * firstDiffX);
CGFloatfirstControlPointY = previousPointY + (mLineSmoothness * firstDiffY);
CGFloatsecondControlPointX = currentPointX - (mLineSmoothness * secondDiffX);
CGFloatsecondControlPointY = currentPointY - (mLineSmoothness * secondDiffY);
[pathaddCurveToPoint:CGPointMake(currentPointX, currentPointY)controlPoint1:CGPointMake(firstControlPointX, firstControlPointY)controlPoint2:CGPointMake(secondControlPointX, secondControlPointY)];//三次曲线
}
// 更新
prePreviousPointX = previousPointX;
prePreviousPointY = previousPointY;
previousPointX = currentPointX;
previousPointY = currentPointY;
currentPointX = nextPointX;
currentPointY = nextPointY;
}
returnpath;
}
- (UIBezierPath*)pathForPoints:(NSArray*)allPoints {
UIBezierPath *path = [UIBezierPath bezierPath];
//下面的方法效果更好,但是只支持4个点及以上情况
if(allPoints.count<4) {
[pathmoveToPoint:[allPoints[0]CGPointValue]];
CGPointPrePonit;
for(inti =0; i < allPoints.count; i++) {
CGPointpoint = [allPoints[i]CGPointValue];
point =CGPointMake(point.x, point.y);
if(i ==0) {
PrePonit = point;
}else{
CGPointNowPoint = [allPoints[i]CGPointValue];
[pathaddCurveToPoint:NowPointcontrolPoint1:CGPointMake((PrePonit.x+NowPoint.x)/2, PrePonit.y)controlPoint2:CGPointMake((PrePonit.x+NowPoint.x)/2, NowPoint.y)];//三次曲线
PrePonit = NowPoint;
}
}
}else{
NSIntegergranularity =10;
[pathmoveToPoint:[allPoints[0]CGPointValue]];
[pathaddLineToPoint:[allPoints[1]CGPointValue]];
for(intindex =3; index < allPoints.count; index++) {
CGPointp0 = [allPoints[index -3]CGPointValue];
CGPointp1 = [allPoints[index -2]CGPointValue];
CGPointp2 = [allPoints[index -1]CGPointValue];
CGPointp3 = [allPoints[index]CGPointValue];
for(inti =1; i < granularity; i++) {
floatt = (float)i * (1.0/ granularity);
floattt = t * t;
floatttt = tt * t;
CGPointpi;
pi.x=0.5* (2* p1.x+(p2.x- p0.x) * t +(2* p0.x-5* p1.x+4*p2.x- p3.x) * tt + (3* p1.x- p0.x-3*p2.x+ p3.x) *ttt );
pi.y=0.5* (2* p1.y+(p2.y- p0.y) * t +(2* p0.y-5* p1.y+4*p2.y- p3.y) * tt + (3* p1.y- p0.y-3*p2.y+ p3.y) *ttt );
[pathaddLineToPoint:pi];
}
[pathaddLineToPoint:p2];
}
[pathaddLineToPoint:[allPoints[allPoints.count-1]CGPointValue]];
}
returnpath;
}
在这里采用的是Catmull-Rom插值技术实现的,其实就是一个比较特殊的贝塞尔曲线,如果想用这个方式进行插值,那么在这个曲线上最少要有4个点存在,因为这种方式只能在中间的两个点进行插值,例如有4个点分别是p0、p1、p2、p3依次在这个贝塞尔曲线上,那么我们积可以将值插到p1、p2之间,在上面的代码中可以看到变量t,t的范围是[0,1],当t=0到t=1变化,那么曲线就会从p1(t=0)到p2(t=1)运动,计算出来的点的切向量和这个点的周围两个起点和终点的切向量是平行的,那么如果想要使曲线更加的平滑,那么就要取到更多的点p0、p1、p2、p3、p4,这样就可以有两组分别是p0、p1、p2、p3和p1、p2、p3、p4,就能够在p1、p2和p2、p3之间进行插值,以此类推,使曲线更加的平滑