Bra*_*son 35
曲线的正切只是它的导数.Michal使用的参数方程:
P(t) = (1 - t)^3 * P0 + 3t(1-t)^2 * P1 + 3t^2 (1-t) * P2 + t^3 * P3
应该有一个衍生物
dP(t) / dt =  -3(1-t)^2 * P0 + 3(1-t)^2 * P1 - 6t(1-t) * P1 - 3t^2 * P2 + 6t(1-t) * P2 + 3t^2 * P3 
顺便说一句,在你之前的问题中,这似乎是错误的.我相信你在那里使用斜率为二次贝塞尔曲线,而不是立方.
从那里开始,实现执行此计算的C函数应该是微不足道的,就像Michal已经为曲线本身提供的那样.
以下是经过全面测试的复制和粘贴代码:
它沿曲线绘制近似点,并绘制切线.
bezierInterpolation 找到要点
bezierTangent 找到切线
有两个版本的bezierInterpolation下面提供:
bezierInterpolation 工作得很好
altBezierInterpolation是完全相同的,但它是以扩展的,非常清晰的,解释性的方式编写的.它使算术更容易理解.
使用这两个例程中的任何一个:结果是相同的.
在这两种情况下,用于bezierTangent找到切线.(注意:Michal 在这里很棒的代码库.)
drawRect:还包括如何使用的完整示例.
// MBBezierView.m    original BY MICHAL stackoverflow #4058979
#import "MBBezierView.h"
CGFloat bezierInterpolation(
    CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d) {
// see also below for another way to do this, that follows the 'coefficients'
// idea, and is a little clearer
    CGFloat t2 = t * t;
    CGFloat t3 = t2 * t;
    return a + (-a * 3 + t * (3 * a - a * t)) * t
    + (3 * b + t * (-6 * b + b * 3 * t)) * t
    + (c * 3 - c * 3 * t) * t2
    + d * t3;
}
CGFloat altBezierInterpolation(
   CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d)
    {
// here's an alternative to Michal's bezierInterpolation above.
// the result is absolutely identical.
// of course, you could calculate the four 'coefficients' only once for
// both this and the slope calculation, if desired.
    CGFloat C1 = ( d - (3.0 * c) + (3.0 * b) - a );
    CGFloat C2 = ( (3.0 * c) - (6.0 * b) + (3.0 * a) );
    CGFloat C3 = ( (3.0 * b) - (3.0 * a) );
    CGFloat C4 = ( a );
    // it's now easy to calculate the point, using those coefficients:
    return ( C1*t*t*t + C2*t*t + C3*t + C4  );
    }
CGFloat bezierTangent(CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d)
 {
    // note that abcd are aka x0 x1 x2 x3
/*  the four coefficients ..
    A = x3 - 3 * x2 + 3 * x1 - x0
    B = 3 * x2 - 6 * x1 + 3 * x0
    C = 3 * x1 - 3 * x0
    D = x0
    and then...
    Vx = 3At2 + 2Bt + C         */
    // first calcuate what are usually know as the coeffients,
    // they are trivial based on the four control points:
    CGFloat C1 = ( d - (3.0 * c) + (3.0 * b) - a );
    CGFloat C2 = ( (3.0 * c) - (6.0 * b) + (3.0 * a) );
    CGFloat C3 = ( (3.0 * b) - (3.0 * a) );
    CGFloat C4 = ( a );  // (not needed for this calculation)
    // finally it is easy to calculate the slope element,
    // using those coefficients:
    return ( ( 3.0 * C1 * t* t ) + ( 2.0 * C2 * t ) + C3 );
    // note that this routine works for both the x and y side;
    // simply run this routine twice, once for x once for y
    // note that there are sometimes said to be 8 (not 4) coefficients,
    // these are simply the four for x and four for y,
    // calculated as above in each case.
 }
@implementation MBBezierView
- (void)drawRect:(CGRect)rect {
    CGPoint p1, p2, p3, p4;
    p1 = CGPointMake(30, rect.size.height * 0.33);
    p2 = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
    p3 = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));
    p4 = CGPointMake(-30 + CGRectGetMaxX(rect), rect.size.height * 0.66);
    [[UIColor blackColor] set];
    [[UIBezierPath bezierPathWithRect:rect] fill];
    [[UIColor redColor] setStroke];
    UIBezierPath *bezierPath = [[[UIBezierPath alloc] init] autorelease];   
    [bezierPath moveToPoint:p1];
    [bezierPath addCurveToPoint:p4 controlPoint1:p2 controlPoint2:p3];
    [bezierPath stroke];
    [[UIColor brownColor] setStroke];
 // now mark in points along the bezier!
    for (CGFloat t = 0.0; t <= 1.00001; t += 0.05) {
  [[UIColor brownColor] setStroke];
        CGPoint point = CGPointMake(
            bezierInterpolation(t, p1.x, p2.x, p3.x, p4.x),
            bezierInterpolation(t, p1.y, p2.y, p3.y, p4.y));
            // there, use either bezierInterpolation or altBezierInterpolation,
            // identical results for the position
        // just draw that point to indicate it...
        UIBezierPath *pointPath =
           [UIBezierPath bezierPathWithArcCenter:point
             radius:5 startAngle:0 endAngle:2*M_PI clockwise:YES];
        [pointPath stroke];
        // now find the tangent if someone on stackoverflow knows how
        CGPoint vel = CGPointMake(
            bezierTangent(t, p1.x, p2.x, p3.x, p4.x),
            bezierTangent(t, p1.y, p2.y, p3.y, p4.y));
        // the following code simply draws an indication of the tangent
        CGPoint demo = CGPointMake( point.x + (vel.x*0.3),
                                      point.y + (vel.y*0.33) );
        // (the only reason for the .3 is to make the pointers shorter)
        [[UIColor whiteColor] setStroke];
        UIBezierPath *vp = [UIBezierPath bezierPath];
        [vp moveToPoint:point];
        [vp addLineToPoint:demo];
        [vp stroke];
    }   
}
@end
to draw that class...
MBBezierView *mm = [[MBBezierView alloc]
                     initWithFrame:CGRectMake(400,20, 600,700)];
[mm setNeedsDisplay];
[self addSubview:mm];
以下是计算近似等距点的两个例程,以及那些沿着贝塞尔曲线的切线.
为了清晰和可靠,这些例程以最简单,最具说明性的方式编写.
CGFloat bezierPoint(CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d)
    {
    CGFloat C1 = ( d - (3.0 * c) + (3.0 * b) - a );
    CGFloat C2 = ( (3.0 * c) - (6.0 * b) + (3.0 * a) );
    CGFloat C3 = ( (3.0 * b) - (3.0 * a) );
    CGFloat C4 = ( a );
    return ( C1*t*t*t + C2*t*t + C3*t + C4  );
    }
CGFloat bezierTangent(CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d)
    {
    CGFloat C1 = ( d - (3.0 * c) + (3.0 * b) - a );
    CGFloat C2 = ( (3.0 * c) - (6.0 * b) + (3.0 * a) );
    CGFloat C3 = ( (3.0 * b) - (3.0 * a) );
    CGFloat C4 = ( a );
    return ( ( 3.0 * C1 * t* t ) + ( 2.0 * C2 * t ) + C3 );
    }
四个预先计算的值C1 C2 C3 C4有时被称为贝塞尔曲线的系数.(回想一下,abcd通常被称为四个控制点.)
当然,t从0到1,例如每0.05.
只需为X调用一次这些例程,然后分别为Y调用一次.
希望它可以帮到某人!
重要事实:
(1)绝对的事实是:不幸的是,Apple提供的NO方法肯定是从UIBezierPath中提取点.
(2)不要忘记它的那么容易,因为馅饼动画的东西沿着一个UIBezierPath.谷歌的很多例子.
(3)许多人问:"不能使用CGPath应用程序从UIBezierPath中提取点数吗?" 不,CGPathApply完全不相关:它只是为您提供了制作任何路径的指令列表(因此,"从这里开始","直线绘制到这一点"等等)
我发现使用提供的方程太容易出错。太容易错过细微的 t 或放错位置的括号。
\n相比之下,维基百科提供了更清晰、更干净、更衍生的恕我直言:
\n\n...它可以在代码中轻松实现:
\n3f * oneMinusT * oneMinusT * (p1 - p0)\n+ 6f * t * oneMinusT * (p2 - p1)\n+ 3f * t * t * (p3 - p2)\n(假设您在选择的语言中配置了向量减;问题没有专门标记为 ObjC,并且 iOS 现在有多种可用语言)
\n| 归档时间: | 
 | 
| 查看次数: | 20382 次 | 
| 最近记录: |