微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

可可 – 使用8个三次贝塞尔曲线创建(近似)圆的控制点

前提

我有一个圆圈,动画成8个贝塞尔曲线的形状.为了使过渡平滑,我需要用8个立方贝塞尔曲线制作圆.
这是我到目前为止所拥有的:

代码

- (UIBezierPath*)pathBubbleLeft {
    UIBezierPath *path = [UIBezierPath new];
    [path movetoPoint:p(sqlx,sqlMidy)];

    CGFloat r = sqlW/2;
    CGFloat sin45 = 0.7071 * r;
    CGFloat cos45 = 0.7071 * r;

    [path addRelativeCurvetoPoint:point(sqlMidx - cos45,sqlMidy - sin45) control1:vector(0,0.4) control2:vector(0.5,0.8)];
    [path addRelativeCurvetoPoint:point(sqlMidx,sqly) control1:vector(0.2,0.5) control2:vector(0.4,1)];

    [path addRelativeCurvetoPoint:point(sqlMidx + cos45,sqlMidy - sin45) control1:vector(0.6,0) control2:vector(0.8,0.5)];
    [path addRelativeCurvetoPoint:point(sqlMaxx,sqlMidy) control1:vector(0.5,0.2) control2:vector(1,0.5)];

    [path addRelativeCurvetoPoint:point(sqlMidx + cos45,sqlMidy + sin45) control1:vector(0,sqlMaxy) control1:vector(0.2,1)];

    [path addRelativeCurvetoPoint:point(sqlMidx - cos45,sqlMidy + sin45) control1:vector(0.6,0.5)];
    [path addRelativeCurvetoPoint:point(sqlx,0.5)];

    return path;
}

路径从左开始顺时针(从pi到pi / 2,3pi / 4,pi)

点和向量是CGPointMake和CGVectorMake的短路

sql’在sqlx,sqly,sqlMidx,sqlMidY,sqlMaxx& sqlMaxy代表’squareLeft’,即圆的边界矩形.这些都是CGFloats.

addRelativeCurvetoPoint用于相对于起点/终点定义控制点. (0,0)开始,(1,1)结束.更容易阅读.

- (void)addRelativeCurvetoPoint:(CGPoint)endPoint control1:(CGVector)controlPoint1 control2:(CGVector)controlPoint2 {
    CGPoint start = self.currentPoint;
    CGPoint end = endPoint;
    CGFloat x1 = start.x + controlPoint1.dx*(end.x - start.x);
    CGFloat x2 = start.x + controlPoint2.dx*(end.x - start.x);
    CGFloat y1 = start.y + controlPoint1.dy*(end.y - start.y);
    CGFloat y2 = start.y + controlPoint2.dy*(end.y - start.y);
    [self addCurvetoPoint:endPoint controlPoint1:CGPointMake(x1,y1) controlPoint2:CGPointMake(x2,y2)];
}

结果到目前为止:

static

红色圆圈有点波浪状.这就是我想解决的问题.

下面,左侧圆圈使用上面的代码,右侧圆圈由4条曲线组成,顶部插入2个零长度,底部插入2个([path addLinetoPoint:path.currentPoint];).

enter image description here

从左边到花生中间的过渡是好的,但从中间到右边是奇怪的

解决方法

使用四个分段,使用三次贝塞尔曲线的圆近似不能比@fang在评论中给出的0.55228值更圆:它只是数学上唯一的值,其中立方贝塞尔曲线最佳近似圆圈.在无限精度表示中,它实际上是您获得的值:

4        angle       4                     sqrt(2) - 1
k =  - * tan(-------)  =  - * tan(pi/8)  =  4 * -----------
     3          2         3                          3

并且是0.5522847498307933984022516322796 […].这将为您提供4段最佳近似值,因此如果您需要使用8个段,我们需要一个不同的值,这意味着我们需要使用推导给k我们的角度为pi / 2(四分之一圆),看看它为pi / 4(第八个圆圈)提供了什么.所以:我们将角度pi / 4插入到approximating circles with cubic curvesPrimer on Bezier Curve部分中概述的功能中,我们得到:

start = {
  x: 1,y: 0
}

c1 = {
  x: 1,y: 4/3 * tan(pi/16)
}

c2 = {
  x: cos(pi/4) + 4/3 * tan(pi/16) * sin(pi/4)
  y: sin(pi/4) - 4/3 * tan(pi/16) * cos(pi/4)
}

e = {
  x: cos(pi/4)
  y: sin(pi/4)
}

这给了我们这些(完全有用的)近似坐标:

s  = (1,0)
c1 = (1,0.265216...)
c2 = (0.894643...,0.51957...)
e  = (0.7071...,0.7071...)

这将是段1,然后其余的段只是通过对称得出,段2是:

s  = (0.7071...,0.7071...)
c1 = (0.51957...,0.894643...)
c2 = (0.265216...,1)
e  = (0,1)

这些坐标的演示覆盖了四分之一圆,这里是:http://jsbin.com/ridedahixu/edit?html,output

其余的是(,– ),( –,)和( –,– )象限中明显的对称性.

这些是最好的近似值,所以:如果bezierPathWithovalInRect(…)做了别的事情,那么它比我们几十年前制定的值更不正确=)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐