在三次贝塞尔曲线上找到点的切线

在三次贝塞尔曲线上找到点的切线,第1张

在三次贝塞尔曲线上找到点的切线

这是经过完全测试的代码,可以复制和粘贴:

它沿着曲线绘制 近似 点, 绘制切线。

bezierInterpolation
找到要点

bezierTangent
找到切线

两个版本

bezierInterpolation
下面提供:

bezierInterpolation
完美地工作。

altBezierInterpolation
完全相同,但以扩展,清晰,解释性的方式编写。它使算法更容易理解。

使用这两个例程之一:结果相同。

在这两种情况下,

bezierTangent
都可用于查找切线。

drawRect:
还包括如何使用with的完整示例。

// 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    // 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 pre 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];    }   }@endto 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确实没有提供任何方法来从UIBezierPath中提取点。截至2019年为准。

(2)不要忘记, 沿着 UIBezierPath
进行动画设置就像馅饼一样容易。Google的例子很多。

(3)许多人问: “不能使用CGPathApply从UIBezierPath中提取点吗?” 不, CGPathApply是完全不相关的
:它只是为您提供“进行任何路径的说明”的列表(因此,“从此处开始”,“到此处画一条直线”等)。名称令人困惑,但CGPathApply与贝塞尔曲线完全无关。


对于游戏程序员-正如@Engineer指出的那样,您可能想要切线的法线,幸运的是Apple内置了矢量数学:

https://developer.apple.com/documentation/accelerate/simd/working_with_vectors


https://developer.apple.com/documentation/simd/2896658-simd_normalize



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/4936125.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-13
下一篇 2022-11-13

发表评论

登录后才能评论

评论列表(0条)

保存