commented and cleaned up code is in the spoiler:
#!/usr/bin/perl
open f, ">o.bmp";
# print the bmp file header, and the colour pallette
# (3 entries : 0=black, 1 = blue, 2 = dark blue);
print f pack "a2V9x20C2x2C1016", BM, 18318, 0, 1078, 40, 140, 130, 524
+289, 0,
18200, 168, 0, 98;
# make a string of null bytes for the image;
$image = pack "x18200";
# PIE!
$pi = 4 * atan2( 1, 1 );
# rotate around the origin 0 to 2000 degrees
# (*10 so we do it in increments of .1 degrees)
for $angle ( 0 .. 20000 ) {
# convert to radians and change it to .1 degrees
# (1 rad = degrees * pi / 180)
$radians = $angle * $pi / 1800;
map {
# polar equation of a logarithmic spiral ($radius=exp($angle));
# the /9 is shorter than /10 :) and makes it a tighter spiral
# $_ holds the offset within this map - which gives the spiral a width
# (thinking about it i could have just added it to the radius)
$radius = exp( ( $radians + $_ / 9 ) / 9 ) / 9;
# this is the reiman projection (project from a plane through a sphere
# to its north pole - mark where it meets the sphere)
# also the conversion to cartesian coords
$x = ( 1 / ( $radius + 1 / $radius ) ) * cos $radians;
$y = ( 1 / ( $radius + 1 / $radius ) ) * sin $radians;
# this sets the pixel in the image
vec(
$image,
# and this works out the offset for the correct byte to set
# (offset=$x+$width(140) *$y)
int(
# this is the new $x - using an isometric conversion:
# ($x'= $x+$y - rotate through 45 degrees)
70 * ( 1 + $x + $y ) +
# this is new $y - ($y'=$z+($y-$x)/2 (squish it)
140 * (
10 +
int( 15 + 80 *
# the height at which the projection meets the sphere ($z)
$radius**2 / ( 1 + $radius**2 )
+ 40 * ( $y - $x ) )
)
),
8
)
# and this changes the colour based on the angle of our rotation
= ( $pi / 2 + $radians ) % ( 2 * $pi ) > $pi
? 2
: 1
# /map to give width
} 0 .. 15
}
# print the image
print f $image