如何通过3个点画圆弧

How to draw arc through 3 points

假设我有一个 UIView 作为可移动线的中点,如何绘制如图所示的圆弧。

我在 CGPoint 名称 lineStartPoint 中存储了线的起点,并将终点作为 lineEndPoint。

可以通过名为 movingPoint 的 CGPoint 访问移动对象。

在此先感谢您的帮助。

下面是如何计算 bezierPathWithArcCenter:radius:startAngle:endAngle:clockwise: 方法所需参数的示例。

- (void)viewDidLoad {
    [super viewDidLoad];

    // for example
    CGPoint lineStartPoint = {100,100};
    CGPoint lineEndPoint =   {100,200};
    CGPoint movingPoint =    {30,150};


    CGFloat eps = 1e-5;

    CGVector v1 = {movingPoint.x-lineEndPoint.x, movingPoint.y-lineEndPoint.y};
    CGFloat dist1 = sqrt(v1.dx*v1.dx + v1.dy*v1.dy);
    v1.dx = v1.dx/dist1;
    v1.dy = v1.dy/dist1;

    CGVector v2 = {movingPoint.x-lineStartPoint.x, movingPoint.y-lineStartPoint.y};
    CGFloat dist2 = sqrt(v2.dx*v2.dx + v2.dy*v2.dy);
    v2.dx = v2.dx/dist2;
    v2.dy = v2.dy/dist2;


    CGFloat det = v1.dx*v2.dy - v1.dy*v2.dx;
    if (fabs(det) < eps) {
        // the three points are collinear
        // TODO: draw a line from lineStartPoint to lineEndPoint
        return;
    }

    CGPoint mid1 = {(movingPoint.x+lineEndPoint.x)/2, (movingPoint.y+lineEndPoint.y)/2};
    CGPoint mid2 = {(movingPoint.x+lineStartPoint.x)/2, (movingPoint.y+lineStartPoint.y)/2};

    CGFloat b1 = v1.dx*mid1.x + v1.dy*mid1.y;
    CGFloat b2 = v2.dx*mid2.x + v2.dy*mid2.y;

    CGFloat centerX = v2.dy/det*b1 - v1.dy/det*b2;
    CGFloat centerY = -v2.dx/det*b1 + v1.dx/det*b2;

    CGPoint center = {centerX, centerY};
    CGFloat radius = sqrtf((movingPoint.x-center.x)*(movingPoint.x-center.x) + (movingPoint.y-center.y)*(movingPoint.y-center.y));
    CGFloat startAngle = atan2f(lineStartPoint.y-center.y, lineStartPoint.x-center.x);
    CGFloat movingAngle = atan2f(movingPoint.y-center.y, movingPoint.x-center.x);
    CGFloat endAngle = atan2f(lineEndPoint.y-center.y, lineEndPoint.x-center.x);

    BOOL isClockwise;
    if ((endAngle>startAngle && startAngle<movingAngle && movingAngle<endAngle) ||
        (endAngle<startAngle && !(endAngle<movingAngle && movingAngle<startAngle))) {
        isClockwise = YES;
    } else {
        isClockwise = NO;
    }


    //Show results

    CAShapeLayer* startPointLayer = [[CAShapeLayer alloc] init];
    startPointLayer.path = [UIBezierPath bezierPathWithArcCenter:lineStartPoint radius:2 startAngle:0 endAngle:2*M_PI clockwise:YES].CGPath;
    [self.view.layer addSublayer:startPointLayer];

    CAShapeLayer* endPointLayer = [[CAShapeLayer alloc] init];
    endPointLayer.path = [UIBezierPath bezierPathWithArcCenter:lineEndPoint radius:2 startAngle:0 endAngle:2*M_PI clockwise:YES].CGPath;
    [self.view.layer addSublayer:endPointLayer];

    CAShapeLayer* movingPointLayer = [[CAShapeLayer alloc] init];
    movingPointLayer.path = [UIBezierPath bezierPathWithArcCenter:movingPoint radius:2 startAngle:0 endAngle:2*M_PI clockwise:YES].CGPath;
    [self.view.layer addSublayer:movingPointLayer];

    CAShapeLayer* arcLayer = [[CAShapeLayer alloc] init];
    [arcLayer setFillColor:[UIColor clearColor].CGColor];
    [arcLayer setStrokeColor:[UIColor blueColor].CGColor];
    arcLayer.path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:isClockwise].CGPath;
    [self.view.layer addSublayer:arcLayer];

}