Drawing a bezier curve between a set of given poin

2020-06-09 03:47发布

What is the best way to draw a bezier curve, in iOS application, that passes through a set of given points

6条回答
可以哭但决不认输i
2楼-- · 2020-06-09 04:23

I know this might be late, but just for anyone who is looking for the right answer. Instead of using addLineToPoint to draw the straight line. You can use addCurveToPoint to draw the curve. e.g.

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

It's really up to you to choose the control points of the curve. I just use the x = last_point_x + 20; y = last_point_y for control point one, and x = current_point_x - 20; y = current_point_y;

and you may want to use other value instead of the 20 as you may have different segment width of the curve.

查看更多
Evening l夕情丶
3楼-- · 2020-06-09 04:23

You can easily google some example of how to create bezier curve on the web. I found this short tut as an example.

You can create a close bezier curve for e.g. with the following code snippet:

UIBezierPath* path = [UIBezierPath bezierPath];

[path moveToPoint:pt1];
[path addLineToPoint:pt2];
[path addLineToPoint:pt3];

[path closePath];

I hope it will help as a starting point.

查看更多
手持菜刀,她持情操
4楼-- · 2020-06-09 04:25

You can be much more efficient by using the CGPointFromString method:

 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];
查看更多
祖国的老花朵
5楼-- · 2020-06-09 04:31

A little more generic way to do it can be achieved by, for example, looking at the BEMSimpleLineGraph GitHub Project (see here for more info: ). Here I extracted a method to draw a bezier curve through a given list of points.

The header file (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

The implementation (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

You can use it by for example creating an image context using UIGraphicsBeginImageContext and retrieving the context with UIGraphicsGetCurrentContext().

Otherwise you may want to change the code and assign the resulting Path to a CALayer and add that to an UIView.

Hope this helps.

查看更多
小情绪 Triste *
6楼-- · 2020-06-09 04:40
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];
查看更多
老娘就宠你
7楼-- · 2020-06-09 04:48

Please try this.

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];
查看更多
登录 后发表回答