#!/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); }