【问题标题】:Drawing a bezier curve between a set of given points在一组给定点之间绘制贝塞尔曲线
【发布时间】:2012-10-15 22:08:43
【问题描述】:

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

【问题讨论】:

    标签: ios bezier uibezierpath


    【解决方案1】:

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

    头文件(BezierLine.h):

    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    #import <CoreGraphics/CoreGraphics.h>
    
    @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。

    希望这会有所帮助。

    【讨论】:

      【解决方案2】:

      我知道这可能会迟到,但仅适用于正在寻找正确答案的人。而不是使用 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; y = last_point_y 用于控制点一,x = current_point_x - 20; y = current_point_y;

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

      【讨论】:

        【解决方案3】:

        您可以轻松地在网上搜索一些有关如何创建贝塞尔曲线的示例。我发现这个简短的tut 是一个例子。

        您可以创建一个封闭的贝塞尔曲线,例如使用以下代码 sn-p:

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

        我希望它会作为一个起点有所帮助。

        【讨论】:

          【解决方案4】:

          请试试这个。

          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];
          

          【讨论】:

          • 请在否决之前分享您的问题重新升级代码。
          • bechara - kheye gechilo :P
          【解决方案5】:

          使用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];
          

          【讨论】:

            【解决方案6】:
            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];
            

            【讨论】:

            • 这只是画直线,不回答问题。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-02-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-08-21
            相关资源
            最近更新 更多