2011/05/08

Bezier Paths : making rectangles with rounded corners

Learning at school Bezier paths was fun for me because is when I finally got to know where all those curves come from. I like the maths, and there are a lot of them behind Bezier paths ;) .

Once the theory is known is not complicated to imagine how a path would look like just by knowing its control points position. But, off-course a normal human like me can only make an approximation inside of his/her head. In real life, you don't approximated paths, specially if you are the kind of person who care about small details like me. So, I decided to do a small research and find out the exact position the control points should have in order to approximate an arc or circle or a rounded rectangle.

My choices were: 1. get a computer graphics book or go to wikipedia, remember the maths and then get a pencil and paper and try to solve it mathematically. 2. Trial and error approach. Even though I like maths I like even more programming so decided to go for number 2 and program test my results in javascript(and put the results here)


In order to make a rounded top-left corner I need to...

First trial:

In first place, I thought: I need a cubic bezier path with one control point in the top-left corner and the other at the end of the curve. This is what I got:

Canvas not supported.

That curve starts at point P0 and ends at P1 and use a couple of control points pc0 and pc1. I obtained a nice curve ... nothing new. However the corner I have just drawn is not exactly overlapping the circle in the picture. It's actually outside.

Second trial:

Having the control points in the middle makes sense as well :
Canvas not supported.

This also looks OK. But Why now it looks like the corner was cut or cropped. It seems logical to think that control points should be at the middle like in this case.

Third Trial:

What about quadratic bezier? This seems to be fine but since we have a circle in there we notice this is not correct too.

Canvas not supported.

Fourth Trial:

So I google it and found approximation of a circle using cubic bezier curve There is a paper that has the maths I decided to skip in first place ... In page 3 Dr. Murtaza found the value of kappa: 0.55... which is the (approximated) distance of control point 1 and 2 should have from start and end point respectively. Control points should be placed as follows:

Canvas not supported.

So, if we want to have a rounded rectangle with corner radius r we have to place pc0 and pc1at (0,k)and (k,0) where k is kappa = 0.552228474...

Here we have an almost perfect rounded corner! ;)

I have implemented this in javascript with the canvas element and all the graphics here were rendered using that function. And also I have made an extension for NSBezierPath class so now I can have paths like:

Here are the sources:
NSBezierPath+Extensions.h
NSBezierPath+Extensions.m

And BezierPaths:
Canvas+BezierPaths.js

References:
Mathworks - Approximation of circle using cubic bezier
Wikipedia - Bezier Paths
MDC Docs - Drawing shapes
And maybe this too:Cocoa Dev Central - Intro to Quartz



0 comments :