Understanding Quadratic Bézier Curves

August 27, 2011

In a client project I had to draw by hand a quadratic Bézier curve, because the html5 canvas quadraticCurveTo does not return the information about the path drawn and I needed it.

Some basic explanation of a quadratic Bézier curve. You have a start point P1, an end point P2 and a control point C. Both the x and y of each point on the path is dependant on t, which will vary from 0 to 1. t=0 at the begining of the curve and t=1 and the end of the curve.

You draw an imaginary line between P1 and C (P1C line) and another one between C and P2 (CP2 line). For each value of t, you mark an imaginary point on P1C and CP2. The point on P1C is at t of the line, starting at P1, and the point on the CP2 line is at t of the line, starting at C. Let's call those points C1 and C2.

Then, you draw an imaginary line between C1 and C2, and you mark a real point at t of the C1C2 line.

You repeat the procedure for every value of t, where t varies from 0 to 1. All the points you marked on the line C1C2 are showing the quadratic Bézier curve.

Here's a little animation I made to explain it better:

t = 0

You can have a look at the source for a complete understanding, but here's the important part, edited for clarity:

// constants
var CANVAS_WIDTH = 301;
var CANVAS_HEIGHT = 301;
var p1x = 20;
var p1y = 200;
var cx = 140;
var cy = 20;
var p2x = 280;
var p2y = 280;

// basic setup
var $t = $('#bezier-example-1-t span');

var animationCanvas = $('#bezier-example-1 .animation').get(0);
var animationContext = animationCanvas.getContext('2d');
animationCanvas.width = CANVAS_WIDTH;
animationCanvas.height = CANVAS_HEIGHT;

var curveCanvas = $('#bezier-example-1 .curve').get(0);
var curveContext = curveCanvas.getContext('2d');
curveCanvas.width = CANVAS_WIDTH;
curveCanvas.height = CANVAS_HEIGHT;
curveContext.strokeStyle = "#777";
curveContext.lineWidth = 2;
curveContext.beginPath();
curveContext.moveTo(p1x, p1y);
curveContext.stroke();

setInterval(updateDemo, 1000/30);

var t = 0;
var d = 1; // direction

function updateDemo() { // called 30 times/second to animate
if (t > 1 || t < 0) {
d *= -1; // change direction
curveContext.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
curveContext.beginPath();
}
t += 0.01 * d; // continue moving
$t.html(Math.round(t*100)/100);
// update values
var c1x = p1x + (cx - p1x) * t;
var c1y = p1y + (cy - p1y) * t;
var c2x = cx + (p2x - cx) * t;
var c2y = cy + (p2y - cy) * t;
var tx = c1x + (c2x - c1x) * t;
var ty = c1y + (c2y - c1y) * t;

animationContext.save();
// clear old sketch
animationContext.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
// draw new line
animationContext.beginPath();
animationContext.strokeStyle = '#aaa';
animationContext.lineWidth = 1;
animationContext.moveTo(c1x, c1y);
animationContext.lineTo(c2x, c2y);
animationContext.stroke();
// draw points on lines
drawPoint(animationContext, c1x, c1y, 2, '#0f0');
drawPoint(animationContext, c2x, c2y, 2, '#0f0');
// draw point on curve
drawPoint(animationContext, tx, ty, 3, '#f0f');
animationContext.restore();

// draw the new Bezier curve segment
curveContext.lineTo(tx, ty);
curveContext.stroke();
}

The code is on Github.

Some Fun With Android and Python

July 11, 2011

For those who don't know, the Android Scripting Environment allows you to use scripting languages to experiment with Android.

I wanted to try it, so I wrote this little web server that takes pictures when you make an HTTP request to it.

import BaseHTTPServer, android
from os import path

droid = android.Android()
FILENAME = "/sdcard/sl4a/spy/pic.jpg"
PORT = 9090

class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(s):
"""Respond to a GET request."""
droid.cameraCapturePicture(FILENAME)
picture = open(FILENAME, 'rb')
s.send_response(200)
s.send_header("Content-Type", "image/jpeg")
s.end_headers()
s.wfile.write(picture.read())

server_class = BaseHTTPServer.HTTPServer
httpd = server_class(('', PORT), Handler)
httpd.serve_forever()

The code is on Github.