# Tag Archives: bezier

Being able to draw smooth lines that connect arbitrary points is something that I find myself needing very frequently. This is a port of an old snippet that does just that. By averaging control points of a quadratic bezier curve we ensure that our resulting Bezier curves are always smooth.

The key can be seen here with the `bezierSkin` function. It draws either a closed or open curve.

```1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 // array of xy coords, closed boolean function bezierSkin(bez, closed = true) { var avg = calcAvgs(bez), leng = bez.length, i, n;   if (closed) { c.moveTo(avg[0], avg[1]); for (i = 2; i < leng; i += 2) { n = i + 1; c.quadraticCurveTo(bez[i], bez[n], avg[i], avg[n]); } c.quadraticCurveTo(bez[0], bez[1], avg[0], avg[1]); } else { c.moveTo(bez[0], bez[1]); c.lineTo(avg[0], avg[1]); for (i = 2; i < leng - 2; i += 2) { n = i + 1; c.quadraticCurveTo(bez[i], bez[n], avg[i], avg[n]); } c.lineTo(bez[leng - 2], bez[leng - 1]); } }     // create anchor points by averaging the control points function calcAvgs(p) { var avg = [], leng = p.length, prev; for (var i = 2; i < leng; i++) { prev = i - 2; avg.push((p[prev] + p[i]) / 2); } // close avg.push((p[0] + p[leng - 2]) / 2); avg.push((p[1] + p[leng - 1]) / 2); return avg; }```

The control points are then averaged to ensure that the curve contains no sharp angles.

Posted in Graphics, Math, arrays, bezier, graphics algorithms, html5, javascript | Also tagged , , , | Leave a comment

## Bezier Skin (smooth curveTo())

Actionscript:
1. // graphics, vector of xy coords, closed boolean
2. function bezierSkin(g:Graphics, bez:Vector.<Number>, closed:Boolean = true):void {
3.     var avg:Vector.<Number> = calcAvgs(bez);
4.     var i:int, n:int;
5.     var leng:int = bez.length;
6.
7.     if (closed){
8.         g.moveTo(avg[0], avg[1]);
9.         for (i = 2; i <leng; i+=2) {
10.             n=i+1;
11.             g.curveTo(bez[i], bez[n], avg[i], avg[n]);
12.         }
13.         g.curveTo(bez[0], bez[1], avg[0], avg[1]);
14.     }else{
15.         g.moveTo(bez[0], bez[1]);
16.         g.lineTo(avg[0], avg[1]);
17.         for (i = 2; i <leng-2; i+=2) {
18.             n=i+1;
19.             g.curveTo(bez[i], bez[n], avg[i], avg[n]);
20.         }
21.         g.lineTo(bez[ leng - 2], bez[ leng - 1]);
22.     }
23. }
24.
25. // create anchor points by averaging the control points
26. function calcAvgs(v:Vector.<Number>):Vector.<Number> {
27.     var avg:Vector.<Number> = new Vector.<Number>();
28.     var leng:int=v.length;
29.     for (var i:int = 2; i<leng; i+=1) {
30.         var prev:Number=i-2;
31.         avg.push( (v[prev] + v[i]) / 2 );
32.     }
33.     // close
34.     avg.push( (v[0] + v[ leng - 2]) / 2 );
35.     avg.push( (v[1] + v[ leng - 1]) / 2 );
36.     return avg;
37. }
38.
39. // test out the functions:
40.
41. graphics.lineStyle(0,0x000000);
42.
43. // draw a very rounded rect
44. bezierSkin(graphics, Vector.<Number>([100,100,200,100,200,200,100,200]) );
45.
46. // draw a random curve with 10 xy coords
47. var rnd:Vector.<Number> = new Vector.<Number>();
48. for (var i:int = 0; i<20; i++) rnd.push(Math.random()*100);
49. bezierSkin(graphics, rnd);
50.
51. // erase everything and allow the used to draw a smooth curve with the mouse
53. var index:int = 0;
54. var pnts:Vector.<Number> = new Vector.<Number>();
55.
56. function onLoop(evt:MouseEvent):void {
57.      pnts.push(mouseX);
58.      pnts.push(mouseY);
59.
60.      graphics.clear();
61.      graphics.lineStyle(0,0x000000);
62.
63.       // draw a smooth curved line
64.      bezierSkin(graphics,pnts,false);
65. }

The above code uses averaging to generate anchor points for curveTo() calls. This is an easy way to always draw smooth curves.

This is an old one that I've seen floating around since the drawing api first came out... but I it's an important snippet, so I figured I'd post it.

Actionscript:
1. var canvas:BitmapData=new BitmapData(280,280,false,0x000000);
3. var color:uint;
4. // anchor x1, anchor y1,
5. // control-handle x2, control-handle y2,
6. // anchor x3, anchor y3, [resolution incremental value between 0-1]
7. function quadBezier(x1:Number, y1:Number, x2:Number, y2:Number, x3:Number, y3:Number, resolution:Number=.03):void {
8.     var b:Number,pre1:Number,pre2:Number,pre3:Number,pre4:Number;
9.     for (var a:Number = 0; a <1;a+=resolution) {
10.
11.         b=1-a;
12.         pre1=(a*a);
13.         pre2=2*a*b;
14.         pre3=(b*b);
15.
16.         canvas.setPixel(pre1*x1 + pre2*x2  + pre3*x3 ,
17.                                      pre1*y1 + pre2*y2 + pre3*y3, color);
18.     }
19. }
20.
21. // draw a few
22. color = 0xFFFFFF;
23.
24. for (var i:int = 0; i<20; i++){
25. quadBezier(40,100, 150 , 20 + i * 10 , 200, 100,.01);
26. }
27.
28. color = 0xFF0000;
29.
30. for (i= 0; i<20; i++){
31. quadBezier(150,200, 100 + i * 10, 100  , 120, 30,.01);
32. }

The above demos a function that draws quadratic bezier curves using setPixel().

One of the first posts on this site was a snippet that used setPixel() to draw a cubic bezier curve. I recently needed to do the exact same thing but I wanted to use a quadratic bezier... I knew I had the code laying around somewhere, but I couldn't seem to find it so I just looked on wikipedia and changed the previous cubicBezier() function accordingly.

| Also tagged , | 2 Comments