rendered paste body#!/usr/bin/env perl
use strict;
use warnings;
use GD;
use Math::Trig;
my $pi = 3.14159265;
my $img = new GD::Image(200, 200);
my $white = $img->colorAllocate(255, 255, 255);
my $black = $img->colorAllocate(0, 0, 0);
$img->transparent($white);
# Draw 24 arrows uniformly in a circle.
my $A = [ 100, 100 ];
print $img->gifanimbegin();
for(my $i = 0; $i < 24; $i++){
my $frame = new GD::Image($img->getBounds());
# draw our main arrow line
my $B = polar_to_cartesian(75, $i * $pi/12);
$B->[0] += $A->[0];
$B->[1] += $A->[1];
draw_line($frame, $A, $B);
# draw the arrow
my @arrow = arrow_points($A, $B, 50);
draw_line($frame, $arrow[0], $arrow[1]);
draw_line($frame, $arrow[0], $arrow[2]);
print $frame->gifanimadd();
}
print $img->gifanimend();
# arrow_points(point A, point B, segment length)
# Returns 3 points to make the arrow head.
# First point is the common point. Last two are the segment ends.
sub arrow_points {
my ($ar, $br, $len) = @_;
# Calculate line segment AB's angle
# The domain of arccosine is from 0 to pi. If our arrow passes beyond pi,
# (B_y component is negative relative to A_y), adjust $alpha.
my $alpha = acos (($br->[0] - $ar->[0]) /
sqrt(($br->[0] - $ar->[0])**2 + ($br->[1] - $ar->[1])**2));
if($br->[1] - $ar->[1] < 0){
$alpha = 2 * $pi - $alpha;
}
# Add arrow's angle to segment AB's and convert to
# cartesian cordinates
my $X = [ $len * cos((3 * $pi)/4 + $alpha) + $br->[0],
$len * sin((3 * $pi)/4 + $alpha) + $br->[1] ];
my $Y = [ $len * cos((5 * $pi)/4 + $alpha) + $br->[0],
$len * sin((5 * $pi)/4 + $alpha) + $br->[1] ];
return ($br, $X, $Y);
}
# polar_to_cartesian(radius, theta):
# Converts a polar cordinate to a cartesian one.
# theta is in radians.
sub polar_to_cartesian {
my ($r, $theta) = @_;
return [ $r * cos($theta), $r * sin($theta) ];
}
# draw_line(image handle, point A, point B):
# Draw a line in Q1 space.
sub draw_line {
my ($img, $ar, $br) = @_;
# convert from postive-y Q4 space to Q1
my ($width, $height) = $img->getBounds();
$img->line($ar->[0], $height - $ar->[1],
$br->[0], $height - $br->[1],
$black);
}