Как нарисовать от руки эллипс или круг?

Мой вопрос касается различных техник рисования линий, которые кажутся нарисованными от руки:

Как вы рисуете карандашом?

В частности, Стив Ханов опубликовал эту отличную запись в блоге.

Благодаря этому я смог реализовать красивый алгоритм для линий от руки с использованием кривых Безье. Однако я застрял в том, как реализовать эллипс, выглядящий от руки. В идеале я хотел бы дать ему прямоугольник для использования в качестве границы, аналогично другим вызовам рисования эллипса. Но я хочу, чтобы это выглядело очень от руки.

На данный момент лучшее, что я придумал:

- (UIBezierPath*) freehandEllipseFromRect:(CGRect) rect {

    // freehand ellipses need a lil more height
    rect = CGRectMake(rect.origin.x, rect.origin.y-5, rect.size.width, rect.size.height+10);

    UIBezierPath* path = [UIBezierPath bezierPath];


    CGPoint topMidPoint = CGPointMake(rect.origin.x + (rect.size.width/2), rect.origin.y);
    CGPoint bottomMidPoint = CGPointMake(rect.origin.x + (rect.size.width/2), rect.origin.y+rect.size.height);


    // random point along bottom quarter of height, cause makes it look better
    CGFloat randomY = (((CGFloat) (arc4random() % RAND_MAX) / RAND_MAX)) * (rect.size.height/4);
    CGPoint leftControlPoint = CGPointMake(rect.origin.x-(rect.size.width), rect.origin.y+(rect.size.height-randomY));


    // another random y;
    randomY = (((CGFloat) (arc4random() % RAND_MAX) / RAND_MAX)) * (rect.size.height/4);
    CGPoint rightControlPoint = CGPointMake(rect.origin.x+(rect.size.width*2), rect.origin.y+(rect.size.height-randomY));

    CGFloat overshootValueX = (((CGFloat) (arc4random() % RAND_MAX) / RAND_MAX)) * 4;
    CGFloat overshootValueY = (((CGFloat) (arc4random() % RAND_MAX) / RAND_MAX)) * 6;
    [path moveToPoint:CGPointMake(topMidPoint.x+overshootValueX, topMidPoint.y)];        
    [path addQuadCurveToPoint:bottomMidPoint controlPoint:leftControlPoint];

    // random value to overshoot
    overshootValueX = (((CGFloat) (arc4random() % RAND_MAX) / RAND_MAX)) * 20;
    overshootValueY = (((CGFloat) (arc4random() % RAND_MAX) / RAND_MAX)) * 4;
    [path addQuadCurveToPoint:CGPointMake(topMidPoint.x-overshootValueX, topMidPoint.y-overshootValueY) controlPoint:rightControlPoint];
    return path;
}

Результат выглядит так:

эллипс от руки

Мне не нравится, насколько он остроконечный, и, несмотря на все мои попытки, я просто не могу добиться большего. Кроме того, мне нравится, чтобы изгибы выглядели менее совершенными, и я не полагаюсь на выступ как на единственную деталь, выглядящую «от руки». Я думаю, что 2 квадроцикла - это просто неправильный путь ...

Может 4 дуги?

У кого-нибудь есть другое решение или образец кода для меня? (любой язык в порядке)


person pj4533    schedule 04.08.2011    source источник


Ответы (2)


Так что этот вопрос был открытым уже давно, позвольте мне попробовать. Есть две части: (1) Сделать путь не идеальным. (2) Обводка пути, как нарисовано от руки. Для (1) отделите дерьмо от вещи. Сделайте это из 100 или около того контрольных точек и искажайте их с помощью медленно меняющейся функции обертывания. Для (2) назначьте медленно меняющуюся, непрерывную толщину и угол по траектории, возможно, также добавив некоторого шума. Если вам нужен хороший человеческий шум, прочтите о шумах Перлина, это потрясающе. Также всегда полезно посмотреть, как это делают другие люди, создать контуры в Photoshop и обводить их, есть возможность сделать это естественным образом.

person starmole    schedule 03.02.2012

Лично я бы определил ваш эллипс параметрически, например:

x=(width*cos(t)/2)+centerx;
y=(height*cos(t)/2)+centery;

затем создайте функцию, которая генерирует небольшие случайные числа

создать функцию, которая находит вектор нормали к кривой (параметрически)

x=width*cos(t);
y=height*sin(t);
normal=UnitVector(x,y);

для каждой точки вашего эллипса, смещение путем масштабирования нормали в этой точке небольшим случайным числом.

Проведите кривую через точки с помощью кубической интерполяции.

person Void Star    schedule 05.02.2012