在一组给定点之间绘制贝塞尔曲线

在iOS应用程序中绘制贝塞尔曲线的最佳方法是什么,它通过一组给定的点

例如,通过查看BEMSimpleLineGraph GitHub项目可以实现更通用的方法(请参阅此处了解更多信息: bemsimplelinegraph )。 在这里,我提取了一种方法,通过给定的点列表绘制贝塞尔曲线。

头文件(BezierLine.h):

#import  #import  #import  @interface BezierLine : NSObject /* Draws a bezier curved line on the given context with points: Array of CGPoint values */ -(void) drawBezierCurveInContext:(CGContextRef)context withPoints:(NSArray*)points lineColor:(UIColor*)color lineWidth:(CGFloat)lineWidth; @end 

实施(BezierLine.m):

 #import "BezierLine.h" @implementation BezierLine -(void) drawBezierCurveInContext:(CGContextRef)context withPoints:(NSArray*)points lineColor:(UIColor*)color lineWidth:(CGFloat)lineWidth { if (points.count < 2) return; CGPoint CP1; CGPoint CP2; // LINE UIBezierPath *line = [UIBezierPath bezierPath]; CGPoint p0; CGPoint p1; CGPoint p2; CGPoint p3; CGFloat tensionBezier1 = 0.3; CGFloat tensionBezier2 = 0.3; CGPoint previousPoint1; CGPoint previousPoint2; [line moveToPoint:[[points objectAtIndex:0] CGPointValue]]; for (int i = 0; i < points.count - 1; i++) { p1 = [[points objectAtIndex:i] CGPointValue]; p2 = [[points objectAtIndex:i + 1] CGPointValue]; const CGFloat maxTension = 1.0f / 3.0f; tensionBezier1 = maxTension; tensionBezier2 = maxTension; if (i > 0) { // Exception for first line because there is no previous point p0 = previousPoint1; if (p2.y - p1.y == p1.y - p0.y) tensionBezier1 = 0; } else { tensionBezier1 = 0; p0 = p1; } if (i < points.count - 2) { // Exception for last line because there is no next point p3 = [[points objectAtIndex:i + 2] CGPointValue]; if (p3.y - p2.y == p2.y - p1.y) tensionBezier2 = 0; } else { p3 = p2; tensionBezier2 = 0; } // The tension should never exceed 0.3 if (tensionBezier1 > maxTension) tensionBezier1 = maxTension; if (tensionBezier2 > maxTension) tensionBezier2 = maxTension; // First control point CP1 = CGPointMake(p1.x + (p2.x - p1.x)/3, p1.y - (p1.y - p2.y)/3 - (p0.y - p1.y)*tensionBezier1); // Second control point CP2 = CGPointMake(p1.x + 2*(p2.x - p1.x)/3, (p1.y - 2*(p1.y - p2.y)/3) + (p2.y - p3.y)*tensionBezier2); [line addCurveToPoint:p2 controlPoint1:CP1 controlPoint2:CP2]; previousPoint1 = p1; previousPoint2 = p2; } CGContextSetAllowsAntialiasing(context, YES); CGContextSetStrokeColorWithColor(context, color.CGColor); CGContextSetLineWidth(context, lineWidth); CGContextAddPath(context, line.CGPath); CGContextDrawPath(context, kCGPathStroke); } @end 

您可以通过使用UIGraphicsBeginImageContext创建图像上下文并使用UIGraphicsGetCurrentContext()检索上下文来使用它。

否则,您可能希望更改代码并将结果路径分配给CALayer并将其添加到UIView。

希望这可以帮助。

我知道这可能会迟到,但对于那些正在寻找正确答案的人来说。 而不是使用addLineToPoint绘制直线。 您可以使用addCurveToPoint绘制曲线。 例如

 [bezierPath moveToPoint:CGPointMake(0, 0)]; [bezierPath addCurveToPoint:CGPointMake(40, 100) controlPoint1:CGPointMake(20, 0) controlPoint2:CGPointMake(20, 100)]; [bezierPath addCurveToPoint:CGPointMake(80, 50) controlPoint1:CGPointMake(60, 100) controlPoint2:CGPointMake(60, 50)]; // and you may don't want to close the path // [bezierPath closePath]; 

选择曲线的控制点真的取决于你。 我只使用x = last_point_x + 20; 对于控制点1,y = last_point_y,x = current_point_x – 20; y = current_point_y;

并且您可能希望使用其他值而不是20,因为您可能具有不同的曲线段宽度。

您可以轻松谷歌一些如何在网络上创建贝塞尔曲线的示例。 我发现这个短暂的啧啧是一个例子。

您可以创建一个紧密的贝塞尔曲线,例如使用以下代码片段:

 UIBezierPath* path = [UIBezierPath bezierPath]; [path moveToPoint:pt1]; [path addLineToPoint:pt2]; [path addLineToPoint:pt3]; [path closePath]; 

我希望它有助于作为一个起点。

请试试这个。

 UIImageView *waterLevel = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,200,200)]; UIGraphicsBeginImageContext(waterLevel.frame.size); [waterLevel.image drawAtPoint:CGPointZero]; //define BezierPath UIBezierPath *bezierPath = [UIBezierPath bezierPath]; // Set the starting point of the shape. [bezierPath moveToPoint:CGPointMake(0, 0)]; [bezierPath addLineToPoint:CGPointMake(waterLevel.frame.size.width, 0)]; [bezierPath addLineToPoint:CGPointMake(waterLevel.frame.size.width, waterLevel.frame.size.height)]; [bezierPath addLineToPoint:CGPointMake(0, waterLevel.frame.size.height)]; [bezierPath closePath]; bezierPath.lineWidth = 15; //set the stoke color [[UIColor blackColor] setStroke]; //draw the path [bezierPath stroke]; // Add to the current Graphic context CGContextRef context = UIGraphicsGetCurrentContext(); CGContextAddPath(context,bezierPath.CGPath); waterLevel.image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); [self.view addSubview:waterLevel]; 

使用CGPointFromString方法可以提高效率:

  NSArray *pointArray = @[@"{3.0,2.5}",@"{100.0,30.2}", @"{100.0,200.0}", @"{3.0,200.0}"]; // draw the path UIBezierPath *aPath = [UIBezierPath bezierPath]; for (NSString *pointString in pointArray) { if ([pointArray indexOfObject:pointString] == 0) [aPath moveToPoint:CGPointFromString(pointString)]; else [aPath addLineToPoint:CGPointFromString(pointString)]; } [aPath closePath]; 
 UIBezierPath *aPath = [UIBezierPath bezierPath]; // Set the starting point of the shape. [aPath moveToPoint:CGPointMake(100.0, 0.0)]; // Draw the lines. [aPath addLineToPoint:CGPointMake(200.0, 40.0)]; [aPath addLineToPoint:CGPointMake(160, 140)]; [aPath addLineToPoint:CGPointMake(40.0, 140)]; [aPath addLineToPoint:CGPointMake(0.0, 40.0)]; [aPath closePath];