
I know how to make and sell software online, and I can share my tips
with you.
Email
|
Twitter
|
LinkedIn
|
Comics
|
All articles
Simulating freehand drawing with Cairo
Posted 17 years ago
Have a look at this image. You might think I scrawled it on a napkin and scanned it in. Wrong! It was completely automatically generated by an upcoming release of www.websequencediagrams.com, with the new "napkin" style. Getting it to render this way was easy, simply with a tiny bit of math and a change to my line drawing function. The handwriting font FG Virgil.

Here's the same diagram in a different style:

Here's the C code that I use for my line drawing function, using the cairo API.
void
crazyLine( cairo_t* ctx, double fromX, double fromY, double toX, double toY)
{
// Crazyline. By Steve Hanov, 2008
// Released to the public domain.
// The idea is to draw a curve, setting two control points at random
// close to each side of the line. The longer the line, the sloppier it's drawn.
double control1x, control1y;
double control2x, control2y;
// calculate the length of the line.
double length = sqrt( (toX-fromX)*(toX-fromX) + (toY-fromY)*(toY-fromY));
// This offset determines how sloppy the line is drawn. It depends on the
// length, but maxes out at 20.
double offset = length/20;
if ( offset > 20 ) offset = 20;
// Overshoot the destination a little, as one might if drawing with a pen.
toX += ((double)rand()/RAND_MAX)*offset/4;
toY += ((double)rand()/RAND_MAX)*offset/4;
double t1X = fromX, t1Y = fromY;
double t2X = toX, t2Y = toY;
// t1 and t2 are coordinates of a line shifted under or to the right of
// our original.
t1X += offset;
t2X += offset;
t1Y += offset;
t2Y += offset;
// create a control point at random along our shifted line.
double r = (double)rand()/RAND_MAX;
control1X = t1Y + r * (t2X-t1X);
control1Y = t1Y + r * (t2Y-t1Y);
// now make t1 and t2 the coordinates of our line shifted above
// and to the left of the original.
t1X = fromX - offset;
t2X = toX - offset;
t1Y = fromY - offset;
t2Y = toY - offset;
// create a second control point at random along the shifted line.
r = (double)rand()/RAND_MAX;
control2X = t1X + r * (t2X-t1X);
control2Y = t1Y + r * (t2Y-t1Y);
// draw the line!
cairo_move_to( _ctx, fromX, fromY );
cairo_curve_to( _ctx, control1X, control1Y, control2X, control2Y, toX, toY );
}
Asana's shocking pricing practices, and how you can get away with it too

If one apple costs $1, how much would five apples cost? How about 500? If everyday life, when you buy more of something, you get more bananas for your buck. But software companies are bucking the trend.
How wide should you make your web page?

Based on 22500 unique IP addresses over the past week.
Installing the Latest Debian on an Ancient Laptop
The challenge: Install Linux on a really old laptop. The catch: It has only
32 MB of RAM, no network ports, no CD-ROM, and the floppy drive makes creaking noises. Is it possible? Yes. Is it easy? No. Is is useful? Maybe...
Experiment: Deleting a post from the Internet

Once you post something on the Internet, it is hard to get rid of it. As an experiment, I deleted one of my past posts, and I tried to remove all traces of it.
How a programmer reads your resume (comic)

People thought it was a comic, so I never corrected them.
You don't need a project/solution to use the VC++ debugger
You learn a lot of things on the job as a programmer. Years ago, at my first coop position, I was a little confused when my boss went to Visual C++, and tried to open the .EXE file as a project.
What a dolt! I thought.
That's not going to work.
Spoke.com scam
Rant: Why do companies think they can make money by posting false information about you on the Internet?
Throw away the keys: Easy, Minimal Perfect Hashing
Perfect hashing is a technique for building a hash table with no collisions in the minimum possible space. They are a easy to build with this simple python function.