#!/usr/local/bin/perl -w
# Specify up to 2 numbers on the command line. The first is the
# number of vertices you want the star to have (defaults to 5).
# The second is the "magic number" you want to use when generating
# the star (defaults to 2). A valid magic numbers is relatively
# prime to the number of vertices. (play with it, you'll get the
# idea)
#
# Ex: star.pl 11 5 > star.png
use GD;
use constant PI => # eh, good enough for government work...
'3.1415926535897932384626433832795028841971693993751' .
'058209749445923078164062862089986280348253421170680';
use constant STAR_SIZE => 200;
use constant IMG_SIZE => STAR_SIZE * 2.2;
# create a new image
$im = new GD::Image(IMG_SIZE, IMG_SIZE);
# allocate some colors
$black = $im->colorAllocate(0,0,0);
$blue = $im->colorAllocate(0,0,255);
$im->fill(0,0,$black); # set background
my $points = shift || 5;
my $magic = shift || 2;
my @vertices = ÷_circle(STAR_SIZE,$points);
my $poly = &make_star($magic, \@vertices);
die "not a valid magic number\n" unless defined $poly;
# move to center of image
$poly->offset(IMG_SIZE/2, IMG_SIZE/2);
$im->polygon($poly,$blue);
# make sure we are writing to a binary stream
binmode STDOUT;
# Convert the image to PNG and print it on standard output
print $im->png;
sub make_star {
# given a "magic number" and a ref for an array of vertices
# walks the vertices and constructs a GD::Polygon star using
# those vertices and that magic number.
#
# returns undef if the magic number isn't really magic.
my ($magic, $vertices) = @_;
# make a copy of $verts so we can destroy it
my @verts = @$vertices;
my $poly = new GD::Polygon;
for (my $i=0;
defined $verts[$i];
$i = ($i + $magic) % scalar(@verts)) {
my $point = $verts[$i];
$poly->addPt(@$point);
$verts[$i] = undef;
}
# if there are still vertices left,
# we don't have a valid magic number
return undef if (grep { defined; } @verts);
# we are good to go
return $poly;
}
sub divide_circle {
# given a radius and a number of points/vertices
# return a list of x,y pairs that equally divide a circle
# of that radius centered on 0,0
# (list context)
my ($radius, $points) = @_;
my @result;
for ($i = 0; $i < $points; $i ++) {
my $degree = $i * (360/$points);
$degree += 180; # hush religious fanatics
push @result, [ &get_point_on_circle($radius,$degree) ];
}
return @result;
}
sub get_point_on_circle {
# given a radius, and an angle (in degrees) returns an x,y pair
# (list context)
my ($radius, $degree) = @_;
my $radian = $degree * (PI / 180);
my $x = $radius * sin $radian;
my $y = $radius * cos $radian;
return ($x, $y);
}