File Coverage

blib/lib/Image/Flight/Suborbital.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Image::Flight::Suborbital;
2              
3 1     1   22167 use 5.008006;
  1         3  
  1         31  
4 1     1   5 use strict;
  1         1  
  1         28  
5 1     1   4 use warnings;
  1         5  
  1         30  
6 1     1   324 use GD;
  0            
  0            
7             use GD::Text::Align;
8             use Graphics::ColorNames qw( all_schemes hex2tuple );
9              
10             # This is the location of the version number for the whole package
11             our $VERSION = '0.01';
12              
13             # set up Graphics::ColorNames
14             our %ColorTable;
15             tie %ColorTable, 'Graphics::ColorNames', all_schemes();
16              
17             # default configuration values
18             our %defaults = (
19             "height" => 800,
20             "width" => 250,
21             "bg_color" => "white",
22             "bg_top_gradient_color" => undef,
23             "flight_path_color" => "black",
24             "alt_label_color" => "black",
25             "title_color" => "black",
26             "altitude_value" => 120,
27             "altitude_units" => "km",
28             );
29              
30             # instantiate a new object
31             sub new
32             {
33             my $class = shift;
34             my $self = {};
35             bless $self, $class;
36             $self->initialize( @_ );
37             return $self;
38             }
39              
40             # initialize a new object
41             sub initialize
42             {
43             my $self = shift;
44             $self->{config} = { @_ };
45             }
46              
47             # turn colors to list of Red/Green/Blue values
48             sub strtorgb
49             {
50             my $str = shift;
51              
52             if ( $str =~ /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i ) {
53             return ( hex $1, hex $2, hex $3 );
54             } elsif ( $str =~ /^([0-9]{1-3}),([0-9]{1-3}),([0-9]{1-3})/ ) {
55             return ( $1, $2, $3 );
56             } elsif ( exists $ColorTable{$str} ) {
57             return @{$ColorTable{$str}};
58             }
59             }
60              
61             # convert altitude to km
62             sub convert_to_km
63             {
64             my $val = shift;
65             my $units = shift;
66              
67             if ( $units eq "km" ) {
68             return $val;
69             } elsif ( $units eq "mi" or $units eq "miles" ) {
70             return $val * 1.609344;
71             } elsif ( $units eq "ft" or $units eq "feet" ) {
72             return $val / 3280.8399;
73             } else {
74             die "$0: unit $units unknown\n";
75             }
76             }
77              
78             # compute scale marks spacing
79             sub compute_marks
80             {
81             my $apogee = shift;
82              
83             print STDERR "debug: compute_marks: apogee=$apogee\n";
84              
85             # compute magnitude of steps
86             my $magnitude = log($apogee)/log(10);
87             print STDERR "debug: compute_marks: magnitude=$magnitude\n";
88             my $mag_int = int( $magnitude );
89             my $mag_frac = $magnitude - $mag_int;
90             print STDERR "debug: compute_marks: mag_int=$mag_int mag_frac=$mag_frac\n";
91             # compute step factor
92             my $step_factor;
93             if ( $mag_frac >= 0.95 ) {
94             $step_factor = 10;
95             } elsif ( $mag_frac >= 0.6 ) {
96             $step_factor = 5;
97             } elsif ( $mag_frac >= 0.3 ) {
98             $step_factor = 2;
99             } else {
100             $step_factor = 1;
101             }
102             print STDERR "debug: compute_marks: step_factor=$step_factor\n";
103              
104             # compute step size
105             my $step_size = 10**($mag_int - 1 ) * $step_factor;
106             print STDERR "debug: compute_marks: step_size=$step_size\n";
107              
108             return $step_size;
109             }
110              
111             # draw image
112             sub image
113             {
114             my $self = shift;
115              
116             # get configuration info
117             my $height = ( exists $self->{config}{height})
118             ? $self->{config}{height}
119             : $defaults{height};
120             my $width = ( exists $self->{config}{width})
121             ? $self->{config}{width}
122             : $defaults{width};
123             my $title_text = ( exists $self->{config}{title_text})
124             ? $self->{config}{title_text}
125             : $defaults{title_text};
126             my $altitude_value = ( exists $self->{config}{altitude_value})
127             ? $self->{config}{altitude_value}
128             : $defaults{altitude_value};
129             my $altitude_units = ( exists $self->{config}{altitude_units})
130             ? $self->{config}{altitude_units}
131             : $defaults{altitude_units};
132              
133             # set up GD drawing object
134             my $image = new GD::Image( $width, $height );
135              
136             # allocate colors
137             $self->{colors} = {};
138             foreach my $color_var ( "bg", "bg_top_gradient", "flight_path",
139             "alt_label", "title" )
140             {
141             my $color_str = ( exists $self->{config}{$color_var."_color"})
142             ? $self->{config}{$color_var."_color"}
143             : $defaults{$color_var."_color"};
144             if ( defined $color_str ) {
145             $self->{colors}{$color_var."_color"} =
146             $image->colorAllocate(
147             hex2tuple( $ColorTable{$color_str}));
148             }
149             }
150              
151             # draw background gradient if specified
152             if ( exists $self->{colors}{bg_top_gradient_color}) {
153             my $i;
154             $self->{gradient_color} = [];
155             my ( $a_r, $a_g, $a_b ) =
156             $image->rgb($self->{colors}{bg_color});
157             my ( $b_r, $b_g, $b_b ) =
158             $image->rgb($self->{colors}{bg_top_gradient_color});
159             for ( $i=0; $i<100; $i++ ) {
160             printf STDERR "debug: gradient %3d: %3d %3d %3d\n", $i,
161             $a_r + ($b_r-$a_r)*($i/100),
162             $a_g + ($b_g-$a_g)*($i/100),
163             $a_b + ($b_b-$a_b)*($i/100);
164             my $color = $image->colorAllocate(
165             $a_r + ($b_r-$a_r)*($i/100),
166             $a_g + ($b_g-$a_g)*($i/100),
167             $a_b + ($b_b-$a_b)*($i/100));
168             push @{$self->{gradient_color}}, $color;
169             $image->filledRectangle (
170             0, $height-($height-30)/100*($i+1)*((($i+1)/100)**4)-1,
171             $width, $height-($height-30)/100*$i*(($i/100)**4),
172             $color);
173             }
174              
175             # fill in the remainder at the top
176             $image->filledRectangle( 0, 0, $width, 30,
177             $self->{colors}{bg_top_gradient_color});
178             }
179              
180             # draw flight path arc
181             $image->arc( $width/2, $height-1, ($width/3)*2, ($height-30)*2,
182             180, 360, $self->{colors}{flight_path_color});
183            
184             # draw km scale along right side
185             my $alt_km = convert_to_km ( $altitude_value, $altitude_units );
186             my $km_scale_step_size = compute_marks( $alt_km );
187             my $i;
188             for ( $i=1; $i <= $alt_km / $km_scale_step_size; $i++ ) {
189             $image->line( $width - 5,
190             $height-(($height-30)/$alt_km*$km_scale_step_size)*$i,
191             $width,
192             $height-(($height-30)/$alt_km*$km_scale_step_size)*$i,
193             $self->{colors}{alt_label_color});
194             my $label_text = GD::Text::Align->new( $image,
195             text => $km_scale_step_size*$i,
196             font => gdSmallFont,
197             ptsize => 12,
198             valign => 'center',
199             halign => 'right',
200             color => $self->{colors}{alt_label_color});
201             $label_text->draw( $width - 10,
202             $height-(($height-30)/$alt_km*$km_scale_step_size)*$i,
203             0 );
204             }
205             my $km_text = GD::Text::Align->new( $image,
206             text => "km",
207             font => gdSmallFont,
208             ptsize => 14,
209             valign => 'bottom',
210             halign => 'right',
211             color => $self->{colors}{alt_label_color});
212             $km_text->draw( $width, 20, 0 );
213              
214             # draw miles scale along left side
215             my $alt_mi = $alt_km / 1.609344;
216             my $mi_scale_step_size = compute_marks( $alt_mi );
217             for ( $i=1; $i <= $alt_mi / $mi_scale_step_size; $i++ ) {
218             $image->line( 5,
219             $height-(($height-30)/$alt_mi*$mi_scale_step_size)*$i,
220             0,
221             $height-(($height-30)/$alt_mi*$mi_scale_step_size)*$i,
222             $self->{colors}{alt_label_color});
223             my $label_text = GD::Text::Align->new( $image,
224             text => $mi_scale_step_size*$i,
225             font => gdSmallFont,
226             ptsize => 12,
227             valign => 'center',
228             halign => 'left',
229             color => $self->{colors}{alt_label_color});
230             $label_text->draw( 10,
231             $height-(($height-30)/$alt_mi*$mi_scale_step_size)*$i,
232             0 );
233             }
234             my $mi_text = GD::Text::Align->new( $image,
235             text => "miles",
236             font => gdSmallFont,
237             ptsize => 14,
238             valign => 'bottom',
239             halign => 'left',
240             color => $self->{colors}{alt_label_color});
241             $mi_text->draw( 0, 20, 0 );
242              
243             # return the image
244             return $image->png;
245             }
246              
247              
248             1;
249             __END__