Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to draw a freehand-looking ellipse or circle?

My question involves various techniques for drawing lines that appear to be freehand:

How do you draw like a Crayon?

Specifically Steve Hanov posted this excellent blog entry.

From that I was able to implement a nice looking algorithm for freehand lines using bezier curves. However, I am stuck on how to implement a freehand looking ellipse. Ideally, I'd like to give it a rect to use as a boundary, similar to other ellipse drawing calls. But, I want it to look very freehand.

So far, the best I have come up with this:

- (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;
}

The result looks like this:

freehand ellipse

I don't like how pointed it is on top, and despite all my trying I just can't get it much better. Plus, I like the curves to look less perfect, and not rely on the overhang as the only "freehand" looking part. I think 2 quad curves are just the wrong way to go.....

Maybe 4 arcs?

Anyone have another solution or some sample code for me? (any language is fine)

like image 900
pj4533 Avatar asked Aug 04 '11 00:08

pj4533


People also ask

How do you manually draw an ellipse?

A vertical line is drawn from the center of the bottom line receding towards the vanishing point. A horizontal line is drawn across the middle of the "square". These two lines will intersect at the middle of what will become the ellipse.

What are the three methods in sketching an ellipse?

Methods of constructing Ellipse include: i Concentric circles method ii The focal point method iii The rectangular method.


1 Answers

So this question has been open for a long time, let me try to give it a shot. There are two parts: (1) Making the path look not perfect. (2) Stroking the path like drawn by hand. For (1), subdivide the shit out of the thing. Make it out of 100 or so control points and distort them with a wrapping function that varies slowly. For (2) assign a slowly varying, continuous thickness and angle over the path, maybe also adding some noise. For a good human looking noise read up on Perlin noise, it's awesome. Also it's always a good idea to look at how other people do it, create paths in Photoshop and stroke them, it has an option to do it naturally looking.

like image 152
starmole Avatar answered Sep 19 '22 22:09

starmole