Найти точку, данное расстояние вдоль простой кубической кривой Безье. (На айфоне!) - PullRequest
16 голосов
/ 30 октября 2010

Представьте, что у вас есть совершенно нормальная четырехточечная кривая Безье (две точки и две контрольные точки), созданная с использованием кривойToPoint: controlPoint1: controlPoint2: в приложении какао:

simple cubic bezier curve example
Какнайти точки (и касательные) вдоль кривой?


Позже: для полного, упрощенного решения , основанного на ответе Михала ниже, нажмите:
Найти касательную точки на кубической кривой Безье (на iPhone)

И просто скопировать и вставить код из: https://stackoverflow.com/a/31317254/294884

Ответы [ 3 ]

28 голосов
/ 30 октября 2010

За вычислением позиций стоит некоторая простая математика, о которой вы можете прочитать в каждой статье, обсуждающей кривые Безье, даже в википедии.В любом случае, я могу обратиться ко всем, кто испытывает затруднения, для фактической реализации его в коде, поэтому я написал этот пример UIView, поскольку это, вероятно, самый простой способ начать работу.

#import "MBBezierView.h"

CGFloat bezierInterpolation(CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d) {
    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;
}

@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];
    for (CGFloat t = 0.0; t <= 1.00001; t += 0.05) {
        CGPoint point = CGPointMake(bezierInterpolation(t, p1.x, p2.x, p3.x, p4.x), bezierInterpolation(t, p1.y, p2.y, p3.y, p4.y));
        UIBezierPath *pointPath = [UIBezierPath bezierPathWithArcCenter:point radius:5 startAngle:0 endAngle:2*M_PI clockwise:YES];
        [pointPath stroke];
    }   
}

@end

Вот что я получаю:

alt text

3 голосов
/ 10 апреля 2014

Аппроксимация, что t - это расстояние вдоль кривой, которую предлагает Михал, может быть проблематичной с некоторыми кривыми и для некоторых целей. К сожалению, я долго безуспешно искал реализацию правильного решения в Obj-C.

Решение, однако, довольно фантастически описано Майком "Pomax" Камермансом в его удивительном учебнике по кривым Безье . Он даже имеет весь код, написанный в процессе обработки и в открытом доступе. Я удивлен, что никто еще не преобразовал это в Obj-C. Очень соблазн, что я.

0 голосов
/ 24 ноября 2010

Любую кривую Безье можно просто рассматривать как полиномиальную функцию с векторными или комплексными коэффициентами.Тогда кубическая кривая Безье, такая как на скриншоте, будет сгенерирована полиномиальной функцией порядка 3, и каждая точка на кривой описывает результат B (t) полинома кривой, оцененный дляконкретное входное значение t .Если я не ошибаюсь, когда вы знаете многочлен, использованный для создания кривой, вы можете просто решить для B (t) = a + bi , где a + bi описываетуказать на комплексной плоскости, для которой вы хотите найти значение t .Поиск корней в таких многочленах является хорошо понятной проблемой и может быть решен алгебраически для кривых порядка 2 или ниже, и с использованием некоторого метода, такого как forward-newton, для многочленов более высокой степени.Если вы знаете производящий многочлен, конечно, также будет очень просто найти производные.Безье обычно составляется из «шаблонных полиномов», где изменяются только коэффициенты при рисовании другой кривой, так что вы, вероятно, сможете найти ее где-нибудь в документации.

...