| 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__ |