Подтвердить что ты не робот

Найдите точку, заданное расстояние, вдоль простой кубической кривой безье. (На iPhone!)

Представьте, что у вас есть полностью нормальная четырехточечная кривая безье (две точки и две контрольные точки), созданная с использованием curveToPoint: controlPoint1: controlPoint2: в приложении cocoa:

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


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

И просто скопируйте и вставьте код из: qaru.site/info/280947/...

4b9b3361

Ответ 1

Там есть простая математика для расчета позиций, вы можете прочитать об этом в каждой статье, обсуждая кривые Безье, даже в википедии. Во всяком случае, я могу рассказать всем, кто в затруднении, чтобы фактически реализовать его в коде, поэтому я написал этот образец 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

Ответ 2

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

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

Ответ 3

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