line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
## @file |
2
|
|
|
|
|
|
|
# Implementation of Chart::Direction |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# written by |
5
|
|
|
|
|
|
|
# @author Chart Group at Geodetic Fundamental Station Wettzell (Chart@fs.wettzell.de) |
6
|
|
|
|
|
|
|
# @date 2015-03-01 |
7
|
|
|
|
|
|
|
# @version 2.4.10 |
8
|
|
|
|
|
|
|
# |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
# @section Chart::Direction |
11
|
|
|
|
|
|
|
# Implements a circular oriented chart like rotating vectors |
12
|
|
|
|
|
|
|
# |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
## @class Chart::Direction |
15
|
|
|
|
|
|
|
# @brief Direction class derived class for Chart to implement direction |
16
|
|
|
|
|
|
|
# charts |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
package Chart::Direction; |
19
|
|
|
|
|
|
|
|
20
|
4
|
|
|
4
|
|
5765
|
use Chart::Base '2.4.10'; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
use GD; |
22
|
|
|
|
|
|
|
use Carp; |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
use strict; |
25
|
|
|
|
|
|
|
use POSIX; |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
@Chart::Direction::ISA = qw(Chart::Base); |
28
|
|
|
|
|
|
|
$Chart::Direction::VERSION = '2.4.10'; |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
#>>>>>>>>>>>>>>>>>>>>>>>>>># |
31
|
|
|
|
|
|
|
# public methods go here # |
32
|
|
|
|
|
|
|
#<<<<<<<<<<<<<<<<<<<<<<<<<<# |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
## @method int set(%opts) |
35
|
|
|
|
|
|
|
# @param[in] %opts Hash of options to the Chart |
36
|
|
|
|
|
|
|
# @return ok or croak |
37
|
|
|
|
|
|
|
# |
38
|
|
|
|
|
|
|
# @brief |
39
|
|
|
|
|
|
|
# Set all options |
40
|
|
|
|
|
|
|
# |
41
|
|
|
|
|
|
|
# @details |
42
|
|
|
|
|
|
|
# main method for customizing the chart, lets users |
43
|
|
|
|
|
|
|
# specify values for different parameters\n |
44
|
|
|
|
|
|
|
# dont check the number of points in the added datasets in a polarplot\n |
45
|
|
|
|
|
|
|
# overwrite Base method |
46
|
|
|
|
|
|
|
# |
47
|
|
|
|
|
|
|
sub set |
48
|
|
|
|
|
|
|
{ |
49
|
|
|
|
|
|
|
my $self = shift; |
50
|
|
|
|
|
|
|
my %opts = @_; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
# basic error checking on the options, just warn 'em |
53
|
|
|
|
|
|
|
unless ( $#_ % 2 ) |
54
|
|
|
|
|
|
|
{ |
55
|
|
|
|
|
|
|
carp "Whoops, some option to be set didn't have a value.\n", "You might want to look at that.\n"; |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
# set the options |
59
|
|
|
|
|
|
|
for ( keys %opts ) |
60
|
|
|
|
|
|
|
{ |
61
|
|
|
|
|
|
|
$self->{$_} = $opts{$_}; |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
# if someone wants to change the grid_lines color, we should set all |
64
|
|
|
|
|
|
|
# the colors of the grid_lines |
65
|
|
|
|
|
|
|
if ( $_ =~ /^colors$/ ) |
66
|
|
|
|
|
|
|
{ |
67
|
|
|
|
|
|
|
my %hash = %{ $opts{$_} }; |
68
|
|
|
|
|
|
|
foreach my $key ( sort keys %hash ) |
69
|
|
|
|
|
|
|
{ |
70
|
|
|
|
|
|
|
if ( $key =~ /^grid_lines$/ ) |
71
|
|
|
|
|
|
|
{ |
72
|
|
|
|
|
|
|
$self->{'colors'}{'y_grid_lines'} = $hash{'grid_lines'}; |
73
|
|
|
|
|
|
|
$self->{'colors'}{'x_grid_lines'} = $hash{'grid_lines'}; |
74
|
|
|
|
|
|
|
$self->{'colors'}{'y2_grid_lines'} = $hash{'grid_lines'}; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
if ( $self->false( $self->{'polar'} ) && ( defined $self->{'croak'} ) ) |
81
|
|
|
|
|
|
|
{ |
82
|
|
|
|
|
|
|
carp "New data set to be added has an incorrect number of points"; |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# now return |
86
|
|
|
|
|
|
|
return 1; |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
## @method int add_dataset(@data) |
90
|
|
|
|
|
|
|
# Add many datasets to the dataref |
91
|
|
|
|
|
|
|
# |
92
|
|
|
|
|
|
|
# Graph API\n |
93
|
|
|
|
|
|
|
# Overwrite Base method |
94
|
|
|
|
|
|
|
# |
95
|
|
|
|
|
|
|
# @param @data Dataset to add |
96
|
|
|
|
|
|
|
# |
97
|
|
|
|
|
|
|
sub add_dataset |
98
|
|
|
|
|
|
|
{ |
99
|
|
|
|
|
|
|
my $self = shift; |
100
|
|
|
|
|
|
|
my @data = @_; |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
# error check the data (carp, don't croak) |
103
|
|
|
|
|
|
|
if ( $self->{'dataref'} && ( $#{ $self->{'dataref'}->[0] } != $#data ) ) |
104
|
|
|
|
|
|
|
{ |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
# carp "New data set to be added has an incorrect number of points"; |
107
|
|
|
|
|
|
|
$self->{'croak'} = 'true'; |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
# copy it into the dataref |
111
|
|
|
|
|
|
|
push @{ $self->{'dataref'} }, [@data]; |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
# now return |
114
|
|
|
|
|
|
|
return 1; |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
#>>>>>>>>>>>>>>>>>>>>>>>>>>># |
118
|
|
|
|
|
|
|
# private methods go here # |
119
|
|
|
|
|
|
|
#<<<<<<<<<<<<<<<<<<<<<<<<<<<# |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
## @fn private int _find_y_scale() |
122
|
|
|
|
|
|
|
# we use the find_y_scale methode to determine the labels of the circles |
123
|
|
|
|
|
|
|
# and the amount of them |
124
|
|
|
|
|
|
|
# @return status |
125
|
|
|
|
|
|
|
# |
126
|
|
|
|
|
|
|
# This function is an overwrite to the same function found in the base class |
127
|
|
|
|
|
|
|
# Chart::Base |
128
|
|
|
|
|
|
|
# |
129
|
|
|
|
|
|
|
sub _find_y_scale |
130
|
|
|
|
|
|
|
{ |
131
|
|
|
|
|
|
|
my $self = shift; |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# Predeclare vars. |
134
|
|
|
|
|
|
|
my ( $d_min, $d_max ); # Dataset min & max. |
135
|
|
|
|
|
|
|
my ( $p_min, $p_max ); # Plot min & max. |
136
|
|
|
|
|
|
|
my ( $tickInterval, $tickCount, $skip ); |
137
|
|
|
|
|
|
|
my @tickLabels; # List of labels for each tick. |
138
|
|
|
|
|
|
|
my $maxtickLabelLen = 0; # The length of the longest tick label. |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
# Find the datatset minimum and maximum. |
141
|
|
|
|
|
|
|
( $d_min, $d_max ) = $self->_find_y_range(); |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# Force the inclusion of zero if the user has requested it. |
144
|
|
|
|
|
|
|
if ( $self->true( $self->{'include_zero'} ) ) |
145
|
|
|
|
|
|
|
{ |
146
|
|
|
|
|
|
|
if ( ( $d_min * $d_max ) > 0 ) # If both are non zero and of the same sign. |
147
|
|
|
|
|
|
|
{ |
148
|
|
|
|
|
|
|
if ( $d_min > 0 ) # If the whole scale is positive. |
149
|
|
|
|
|
|
|
{ |
150
|
|
|
|
|
|
|
$d_min = 0; |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
else # The scale is entirely negative. |
153
|
|
|
|
|
|
|
{ |
154
|
|
|
|
|
|
|
$d_max = 0; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# Allow the dataset range to be overidden by the user. |
160
|
|
|
|
|
|
|
# f_min/max are booleans which indicate that the min & max should not be modified. |
161
|
|
|
|
|
|
|
my $f_min = defined $self->{'min_val'}; |
162
|
|
|
|
|
|
|
$d_min = $self->{'min_val'} if $f_min; |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
my $f_max = defined $self->{'max_val'}; |
165
|
|
|
|
|
|
|
$d_max = $self->{'max_val'} if $f_max; |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
# Assert against the min is larger than the max. |
168
|
|
|
|
|
|
|
if ( $d_min > $d_max ) |
169
|
|
|
|
|
|
|
{ |
170
|
|
|
|
|
|
|
croak "The the specified 'min_val' & 'max_val' values are reversed (min > max: $d_min>$d_max)"; |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# Calculate the width of the dataset. (posibly modified by the user) |
174
|
|
|
|
|
|
|
my $d_width = $d_max - $d_min; |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
# If the width of the range is zero, forcibly widen it |
177
|
|
|
|
|
|
|
# (to avoid division by zero errors elsewhere in the code). |
178
|
|
|
|
|
|
|
if ( 0 == $d_width ) |
179
|
|
|
|
|
|
|
{ |
180
|
|
|
|
|
|
|
$d_min--; |
181
|
|
|
|
|
|
|
$d_max++; |
182
|
|
|
|
|
|
|
$d_width = 2; |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
# Descale the range by converting the dataset width into |
186
|
|
|
|
|
|
|
# a floating point exponent & mantisa pair. |
187
|
|
|
|
|
|
|
my ( $rangeExponent, $rangeMantisa ) = $self->_sepFP($d_width); |
188
|
|
|
|
|
|
|
my $rangeMuliplier = 10**$rangeExponent; |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
# Find what tick |
191
|
|
|
|
|
|
|
# to use & how many ticks to plot, |
192
|
|
|
|
|
|
|
# round the plot min & max to suatable round numbers. |
193
|
|
|
|
|
|
|
( $tickInterval, $tickCount, $p_min, $p_max ) = $self->_calcTickInterval( |
194
|
|
|
|
|
|
|
$d_min / $rangeMuliplier, |
195
|
|
|
|
|
|
|
$d_max / $rangeMuliplier, |
196
|
|
|
|
|
|
|
$f_min, $f_max, |
197
|
|
|
|
|
|
|
$self->{'min_circles'} + 1, |
198
|
|
|
|
|
|
|
$self->{'max_circles'} + 1 |
199
|
|
|
|
|
|
|
); |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
# Restore the tickInterval etc to the correct scale |
202
|
|
|
|
|
|
|
$_ *= $rangeMuliplier foreach ( $tickInterval, $p_min, $p_max ); |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
#get the precision for the labels |
205
|
|
|
|
|
|
|
my $precision = $self->{'precision'}; |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
# Now sort out an array of tick labels. |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
if ( $self->false( $self->{'polar'} ) ) |
210
|
|
|
|
|
|
|
{ |
211
|
|
|
|
|
|
|
for ( my $labelNum = $p_min ; $labelNum <= $p_max ; $labelNum += $tickInterval ) |
212
|
|
|
|
|
|
|
{ |
213
|
|
|
|
|
|
|
my $labelText; |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
if ( defined $self->{f_y_tick} ) |
216
|
|
|
|
|
|
|
{ |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
# Is _default_f_tick function used? |
219
|
|
|
|
|
|
|
if ( $self->{f_y_tick} == \&Chart::Base::_default_f_tick ) |
220
|
|
|
|
|
|
|
{ |
221
|
|
|
|
|
|
|
$labelText = sprintf( "%." . $precision . "f", $labelNum ); |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
else |
224
|
|
|
|
|
|
|
{ |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
# print \&_default_f_tick; |
227
|
|
|
|
|
|
|
$labelText = $self->{f_y_tick}->($labelNum); |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
else |
231
|
|
|
|
|
|
|
{ |
232
|
|
|
|
|
|
|
$labelText = sprintf( "%." . $precision . "f", $labelNum ); |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
push @tickLabels, $labelText; |
235
|
|
|
|
|
|
|
$maxtickLabelLen = length $labelText if $maxtickLabelLen < length $labelText; |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
else |
239
|
|
|
|
|
|
|
{ |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
# polar == true |
242
|
|
|
|
|
|
|
for ( my $labelNum = $p_max ; $labelNum >= $p_min ; $labelNum -= $tickInterval ) |
243
|
|
|
|
|
|
|
{ |
244
|
|
|
|
|
|
|
my $labelText; |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
if ( defined $self->{f_y_tick} ) |
247
|
|
|
|
|
|
|
{ |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
# Is _default_f_tick function used? |
250
|
|
|
|
|
|
|
if ( $self->{f_y_tick} == \&Chart::Base::_default_f_tick ) |
251
|
|
|
|
|
|
|
{ |
252
|
|
|
|
|
|
|
$labelText = sprintf( "%." . $precision . "f", $labelNum ); |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
else |
255
|
|
|
|
|
|
|
{ |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
# print \&_default_f_tick; |
258
|
|
|
|
|
|
|
$labelText = $self->{f_y_tick}->($labelNum); |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
else |
262
|
|
|
|
|
|
|
{ |
263
|
|
|
|
|
|
|
$labelText = sprintf( "%." . $precision . "f", $labelNum ); |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
push @tickLabels, $labelText; |
266
|
|
|
|
|
|
|
$maxtickLabelLen = length $labelText if $maxtickLabelLen < length $labelText; |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
# Store the calculated data. |
271
|
|
|
|
|
|
|
$self->{'min_val'} = $p_min, |
272
|
|
|
|
|
|
|
$self->{'max_val'} = $p_max, |
273
|
|
|
|
|
|
|
$self->{'y_ticks'} = $tickCount, |
274
|
|
|
|
|
|
|
$self->{'y_tick_labels'} = \@tickLabels, |
275
|
|
|
|
|
|
|
$self->{'y_tick_label_length'} = $maxtickLabelLen; |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
# and return. |
278
|
|
|
|
|
|
|
return 1; |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
## @fn private _calcTickInterval($dataset_min, $dataset_max, $flag_fixed_min, $flag_fixed_max, $minTicks, $maxTicks) |
282
|
|
|
|
|
|
|
# @brief |
283
|
|
|
|
|
|
|
# Calculates the ticks for direction in normalised units. |
284
|
|
|
|
|
|
|
# |
285
|
|
|
|
|
|
|
# @details |
286
|
|
|
|
|
|
|
# Calculate the Interval between ticks in y direction |
287
|
|
|
|
|
|
|
# and compare the number of ticks to |
288
|
|
|
|
|
|
|
# the user given values min_y_ticks, max_y_ticks |
289
|
|
|
|
|
|
|
# |
290
|
|
|
|
|
|
|
# @param[in] dataset_min Minimal value in y direction |
291
|
|
|
|
|
|
|
# @param[in] dataset_max Maximal value in y direction |
292
|
|
|
|
|
|
|
# @param[in] flag_fixed_min Indicator whether the dataset_min value is fixed |
293
|
|
|
|
|
|
|
# @param[in] flag_fixed_max Indicator whether the dataset_max value is fixed |
294
|
|
|
|
|
|
|
# @param[in] minTicks Minimal number of ticks wanted |
295
|
|
|
|
|
|
|
# @param[in] maxTicks Maximal number of ticks wanted |
296
|
|
|
|
|
|
|
# @return $tickInterval, $tickCount, $pMin, $pMax |
297
|
|
|
|
|
|
|
# |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
sub _calcTickInterval |
300
|
|
|
|
|
|
|
{ |
301
|
|
|
|
|
|
|
my $self = shift; |
302
|
|
|
|
|
|
|
my ( |
303
|
|
|
|
|
|
|
$min, $max, # The dataset min & max. |
304
|
|
|
|
|
|
|
$minF, $maxF, # Indicates if those min/max are fixed. |
305
|
|
|
|
|
|
|
$minTicks, $maxTicks, # The minimum & maximum number of ticks. |
306
|
|
|
|
|
|
|
) = @_; |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
# Verify the supplied 'min_y_ticks' & 'max_y_ticks' are sensible. |
309
|
|
|
|
|
|
|
if ( $minTicks < 2 ) |
310
|
|
|
|
|
|
|
{ |
311
|
|
|
|
|
|
|
carp "Chart::Direction : Incorrect value for 'min_circles', too small.\n"; |
312
|
|
|
|
|
|
|
$minTicks = 2; |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
if ( $maxTicks < 5 * $minTicks ) |
316
|
|
|
|
|
|
|
{ |
317
|
|
|
|
|
|
|
carp "Chart::Direction : Incorrect value for 'max_circles', too small.\n"; |
318
|
|
|
|
|
|
|
$maxTicks = 5 * $minTicks; |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
my $width = $max - $min; |
322
|
|
|
|
|
|
|
my @divisorList; |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
for ( my $baseMul = 1 ; ; $baseMul *= 10 ) |
325
|
|
|
|
|
|
|
{ |
326
|
|
|
|
|
|
|
TRY: foreach my $tryMul ( 1, 2, 5 ) |
327
|
|
|
|
|
|
|
{ |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
# Calc a fresh, smaller tick interval. |
330
|
|
|
|
|
|
|
my $divisor = $baseMul * $tryMul; |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
# Count the number of ticks. |
333
|
|
|
|
|
|
|
my ( $tickCount, $pMin, $pMax ) = $self->_countTicks( $min, $max, 1 / $divisor ); |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
# Look a the number of ticks. |
336
|
|
|
|
|
|
|
if ( $maxTicks < $tickCount ) |
337
|
|
|
|
|
|
|
{ |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
# If it is too high, Backtrack. |
340
|
|
|
|
|
|
|
$divisor = pop @divisorList; |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
# just for security: |
343
|
|
|
|
|
|
|
if ( !defined($divisor) || $divisor == 0 ) { $divisor = 1; } |
344
|
|
|
|
|
|
|
( $tickCount, $pMin, $pMax ) = $self->_countTicks( $min, $max, 1 / $divisor ); |
345
|
|
|
|
|
|
|
carp "Chart::Direction : Caution: Tick limit of $maxTicks exceeded. Backing of to an interval of " |
346
|
|
|
|
|
|
|
. 1 / $divisor |
347
|
|
|
|
|
|
|
. " which plots $tickCount ticks\n"; |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
return ( 1 / $divisor, $tickCount, $pMin, $pMax ); |
350
|
|
|
|
|
|
|
} |
351
|
|
|
|
|
|
|
elsif ( $minTicks > $tickCount ) |
352
|
|
|
|
|
|
|
{ |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
# If it is too low, try again. |
355
|
|
|
|
|
|
|
next TRY; |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
else |
358
|
|
|
|
|
|
|
{ |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
# Store the divisor for possible later backtracking. |
361
|
|
|
|
|
|
|
push @divisorList, $divisor; |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
# if the min or max is fixed, check they will fit in the interval. |
364
|
|
|
|
|
|
|
next TRY if ( $minF && ( int( $min * $divisor ) != ( $min * $divisor ) ) ); |
365
|
|
|
|
|
|
|
next TRY if ( $maxF && ( int( $max * $divisor ) != ( $max * $divisor ) ) ); |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
# If everything passes the tests, return. |
368
|
|
|
|
|
|
|
return ( 1 / $divisor, $tickCount, $pMin, $pMax ); |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
die "can't happen!"; |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
## @fn private int _draw_y_ticks() |
376
|
|
|
|
|
|
|
# draw the circles and the axes |
377
|
|
|
|
|
|
|
# |
378
|
|
|
|
|
|
|
# Overwrites _draw_y_ticks() of Base class |
379
|
|
|
|
|
|
|
# |
380
|
|
|
|
|
|
|
# @return status |
381
|
|
|
|
|
|
|
sub _draw_y_ticks |
382
|
|
|
|
|
|
|
{ |
383
|
|
|
|
|
|
|
my $self = shift; |
384
|
|
|
|
|
|
|
my $data = $self->{'dataref'}; |
385
|
|
|
|
|
|
|
my $misccolor = $self->_color_role_to_index('misc'); |
386
|
|
|
|
|
|
|
my $textcolor = $self->_color_role_to_index('text'); |
387
|
|
|
|
|
|
|
my $background = $self->_color_role_to_index('background'); |
388
|
|
|
|
|
|
|
my @labels = @{ $self->{'y_tick_labels'} }; |
389
|
|
|
|
|
|
|
my ( $width, $height, $centerX, $centerY, $diameter ); |
390
|
|
|
|
|
|
|
my ( $pi, $font, $fontW, $fontH, $labelX, $labelY, $label_offset ); |
391
|
|
|
|
|
|
|
my ( $dia_delta, $dia, $x, $y, @label_degrees, $arc, $angle_interval ); |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
# set up initial constant values |
394
|
|
|
|
|
|
|
$pi = 3.14159265358979323846, |
395
|
|
|
|
|
|
|
$font = $self->{'legend_font'}, |
396
|
|
|
|
|
|
|
$fontW = $self->{'legend_font'}->width, |
397
|
|
|
|
|
|
|
$fontH = $self->{'legend_font'}->height, |
398
|
|
|
|
|
|
|
$angle_interval = $self->{'angle_interval'}; |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
if ( $self->true( $self->{'grey_background'} ) ) |
401
|
|
|
|
|
|
|
{ |
402
|
|
|
|
|
|
|
$background = $self->_color_role_to_index('grey_background'); |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
# init the imagemap data field if they wanted it |
406
|
|
|
|
|
|
|
if ( $self->true( $self->{'imagemap'} ) ) |
407
|
|
|
|
|
|
|
{ |
408
|
|
|
|
|
|
|
$self->{'imagemap_data'} = []; |
409
|
|
|
|
|
|
|
} |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
# find width and height |
412
|
|
|
|
|
|
|
$width = $self->{'curr_x_max'} - $self->{'curr_x_min'}; |
413
|
|
|
|
|
|
|
$height = $self->{'curr_y_max'} - $self->{'curr_y_min'}; |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
# find center point, from which the pie will be drawn around |
416
|
|
|
|
|
|
|
$centerX = int( $width / 2 + $self->{'curr_x_min'} ); |
417
|
|
|
|
|
|
|
$centerY = int( $height / 2 + $self->{'curr_y_min'} ); |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
# always draw a circle, which means the diameter will be the smaller |
420
|
|
|
|
|
|
|
# of the width and height. let enough space for the labels. |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
## @todo calculate the width of the labels |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
if ( $width < $height ) |
425
|
|
|
|
|
|
|
{ |
426
|
|
|
|
|
|
|
$diameter = $width - 110; |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
else |
429
|
|
|
|
|
|
|
{ |
430
|
|
|
|
|
|
|
$diameter = $height - 80; |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
#the difference between the diameter of two following circles; |
434
|
|
|
|
|
|
|
$dia_delta = ceil( $diameter / ( $self->{'y_ticks'} - 1 ) ); |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
#store the calculated data |
437
|
|
|
|
|
|
|
$self->{'centerX'} = $centerX; |
438
|
|
|
|
|
|
|
$self->{'centerY'} = $centerY; |
439
|
|
|
|
|
|
|
$self->{'diameter'} = $diameter; |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
#draw the axes and its labels |
442
|
|
|
|
|
|
|
# set up an array of labels for the axes |
443
|
|
|
|
|
|
|
if ( $angle_interval == 0 ) |
444
|
|
|
|
|
|
|
{ |
445
|
|
|
|
|
|
|
@label_degrees = (); |
446
|
|
|
|
|
|
|
} |
447
|
|
|
|
|
|
|
elsif ( $angle_interval <= 5 && $angle_interval > 0 ) |
448
|
|
|
|
|
|
|
{ |
449
|
|
|
|
|
|
|
@label_degrees = qw(180 175 170 165 160 155 150 145 140 135 130 125 120 115 |
450
|
|
|
|
|
|
|
110 105 100 95 90 85 80 75 70 65 60 55 50 45 40 35 30 25 20 15 10 5 0 355 350 |
451
|
|
|
|
|
|
|
345 340 335 330 325 320 315 310 305 300 295 290 285 280 275 270 265 260 255 |
452
|
|
|
|
|
|
|
250 245 240 235 230 225 220 215 210 205 200 195 190 185); |
453
|
|
|
|
|
|
|
$angle_interval = 5; |
454
|
|
|
|
|
|
|
} |
455
|
|
|
|
|
|
|
elsif ( $angle_interval <= 10 && $angle_interval > 5 ) |
456
|
|
|
|
|
|
|
{ |
457
|
|
|
|
|
|
|
@label_degrees = qw(180 170 160 150 140 130 120 110 100 90 80 70 60 50 40 |
458
|
|
|
|
|
|
|
30 20 10 0 350 340 330 320 310 300 290 280 270 260 250 240 230 220 210 200 190); |
459
|
|
|
|
|
|
|
$angle_interval = 10; |
460
|
|
|
|
|
|
|
} |
461
|
|
|
|
|
|
|
elsif ( $angle_interval <= 15 && $angle_interval > 10 ) |
462
|
|
|
|
|
|
|
{ |
463
|
|
|
|
|
|
|
@label_degrees = qw(180 165 150 135 120 105 90 75 60 45 30 15 0 345 330 315 300 |
464
|
|
|
|
|
|
|
285 270 255 240 225 210 195); |
465
|
|
|
|
|
|
|
$angle_interval = 15; |
466
|
|
|
|
|
|
|
} |
467
|
|
|
|
|
|
|
elsif ( $angle_interval <= 20 && $angle_interval > 15 ) |
468
|
|
|
|
|
|
|
{ |
469
|
|
|
|
|
|
|
@label_degrees = qw(180 160 140 120 100 80 60 40 20 0 340 320 300 280 260 240 |
470
|
|
|
|
|
|
|
220 200); |
471
|
|
|
|
|
|
|
$angle_interval = 20; |
472
|
|
|
|
|
|
|
} |
473
|
|
|
|
|
|
|
elsif ( $angle_interval <= 30 && $angle_interval > 20 ) |
474
|
|
|
|
|
|
|
{ |
475
|
|
|
|
|
|
|
@label_degrees = qw(180 150 120 90 60 30 0 330 300 270 240 210); |
476
|
|
|
|
|
|
|
$angle_interval = 30; |
477
|
|
|
|
|
|
|
} |
478
|
|
|
|
|
|
|
elsif ( $angle_interval <= 45 && $angle_interval > 30 ) |
479
|
|
|
|
|
|
|
{ |
480
|
|
|
|
|
|
|
@label_degrees = qw(180 135 90 45 0 315 270 225); |
481
|
|
|
|
|
|
|
$angle_interval = 45; |
482
|
|
|
|
|
|
|
} |
483
|
|
|
|
|
|
|
elsif ( $angle_interval <= 90 && $angle_interval > 45 ) |
484
|
|
|
|
|
|
|
{ |
485
|
|
|
|
|
|
|
@label_degrees = qw(180 90 0 270); |
486
|
|
|
|
|
|
|
$angle_interval = 90; |
487
|
|
|
|
|
|
|
} |
488
|
|
|
|
|
|
|
else |
489
|
|
|
|
|
|
|
{ |
490
|
|
|
|
|
|
|
carp "The angle_interval must be between 0 and 90!\nCorrected value: 30"; |
491
|
|
|
|
|
|
|
@label_degrees = qw(180 150 120 90 60 30 0 330 300 270 240 210); |
492
|
|
|
|
|
|
|
$angle_interval = 30; |
493
|
|
|
|
|
|
|
} |
494
|
|
|
|
|
|
|
$arc = 0; |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
foreach (@label_degrees) |
497
|
|
|
|
|
|
|
{ |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
#calculated the coordinates of the end point of the line |
500
|
|
|
|
|
|
|
$x = sin($arc) * ( $diameter / 2 + 10 ) + $centerX; |
501
|
|
|
|
|
|
|
$y = cos($arc) * ( $diameter / 2 + 10 ) + $centerY; |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
#some ugly correcture |
504
|
|
|
|
|
|
|
if ( $_ == '270' ) { $y++; } |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
#draw the line |
507
|
|
|
|
|
|
|
$self->{'gd_obj'}->line( $centerX, $centerY, $x, $y, $misccolor ); |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
#calculate the string point |
510
|
|
|
|
|
|
|
$x = sin($arc) * ( $diameter / 2 + 30 ) + $centerX - 8; |
511
|
|
|
|
|
|
|
$y = cos($arc) * ( $diameter / 2 + 28 ) + $centerY - 6; |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
#draw the labels |
514
|
|
|
|
|
|
|
$self->{'gd_obj'}->string( $font, $x, $y, $_ . '°', $textcolor ); |
515
|
|
|
|
|
|
|
$arc += ( ($angle_interval) / 360 ) * 2 * $pi; |
516
|
|
|
|
|
|
|
} |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
#draw the circles |
519
|
|
|
|
|
|
|
$dia = 0; |
520
|
|
|
|
|
|
|
foreach (@labels) |
521
|
|
|
|
|
|
|
{ |
522
|
|
|
|
|
|
|
$self->{'gd_obj'}->arc( $centerX, $centerY, $dia, $dia, 0, 360, $misccolor ); |
523
|
|
|
|
|
|
|
$dia += $dia_delta; |
524
|
|
|
|
|
|
|
} |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
$self->{'gd_obj'}->filledRectangle( |
527
|
|
|
|
|
|
|
$centerX - length( $labels[0] ) / 2 * $fontW - 2, |
528
|
|
|
|
|
|
|
$centerY + 2, |
529
|
|
|
|
|
|
|
$centerX + 2 + $diameter / 2, |
530
|
|
|
|
|
|
|
$centerY + $fontH + 2, $background |
531
|
|
|
|
|
|
|
); |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
#draw the labels of the circles |
534
|
|
|
|
|
|
|
$dia = 0; |
535
|
|
|
|
|
|
|
foreach (@labels) |
536
|
|
|
|
|
|
|
{ |
537
|
|
|
|
|
|
|
$self->{'gd_obj'}->string( $font, $centerX + $dia / 2 - length($_) / 2 * $fontW, $centerY + 2, $_, $textcolor ); |
538
|
|
|
|
|
|
|
$dia += $dia_delta; |
539
|
|
|
|
|
|
|
} |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
return 1; |
542
|
|
|
|
|
|
|
} |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
## @fn private int _draw_x_ticks() |
545
|
|
|
|
|
|
|
# We don't need x ticks, it's all done in _draw_y_ticks |
546
|
|
|
|
|
|
|
# @return status |
547
|
|
|
|
|
|
|
# |
548
|
|
|
|
|
|
|
# Overwrites the corresponding function in Base |
549
|
|
|
|
|
|
|
# |
550
|
|
|
|
|
|
|
sub _draw_x_ticks |
551
|
|
|
|
|
|
|
{ |
552
|
|
|
|
|
|
|
my $self = shift; |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
return 1; |
555
|
|
|
|
|
|
|
} |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
## @fn private _draw_data |
558
|
|
|
|
|
|
|
# finally get around to plotting the data for direction charts |
559
|
|
|
|
|
|
|
sub _draw_data |
560
|
|
|
|
|
|
|
{ |
561
|
|
|
|
|
|
|
my $self = shift; |
562
|
|
|
|
|
|
|
my $data = $self->{'dataref'}; |
563
|
|
|
|
|
|
|
my $misccolor = $self->_color_role_to_index('misc'); |
564
|
|
|
|
|
|
|
my $textcolor = $self->_color_role_to_index('text'); |
565
|
|
|
|
|
|
|
my $background = $self->_color_role_to_index('background'); |
566
|
|
|
|
|
|
|
my ( $width, $height, $centerX, $centerY, $diameter ); |
567
|
|
|
|
|
|
|
my ( $mod, $map, $i, $j, $brush, $color, $x, $y, $winkel, $first_x, $first_y ); |
568
|
|
|
|
|
|
|
my ( $arrow_x, $arrow_y, $m ); |
569
|
|
|
|
|
|
|
$color = 1; |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
my $pi = 3.14159265358979323846; |
572
|
|
|
|
|
|
|
my $len = 10; |
573
|
|
|
|
|
|
|
my $alpha = 1; |
574
|
|
|
|
|
|
|
my $last_x = undef; |
575
|
|
|
|
|
|
|
my $last_y = undef; |
576
|
|
|
|
|
|
|
my $diff; |
577
|
|
|
|
|
|
|
my $n = 0; |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
if ( $self->true( $self->{'pairs'} ) ) |
580
|
|
|
|
|
|
|
{ |
581
|
|
|
|
|
|
|
my $a = $self->{'num_datasets'} / 2; |
582
|
|
|
|
|
|
|
my $b = ceil($a); |
583
|
|
|
|
|
|
|
my $c = $b - $a; |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
if ( $c == 0 ) |
586
|
|
|
|
|
|
|
{ |
587
|
|
|
|
|
|
|
croak "Wrong number of datasets for 'pairs'"; |
588
|
|
|
|
|
|
|
} |
589
|
|
|
|
|
|
|
} |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
# init the imagemap data field if they wanted it |
592
|
|
|
|
|
|
|
if ( $self->true( $self->{'imagemap'} ) ) |
593
|
|
|
|
|
|
|
{ |
594
|
|
|
|
|
|
|
$self->{'imagemap_data'} = []; |
595
|
|
|
|
|
|
|
} |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
# find width and height |
598
|
|
|
|
|
|
|
$width = $self->{'curr_x_max'} - $self->{'curr_x_min'}; |
599
|
|
|
|
|
|
|
$height = $self->{'curr_y_max'} - $self->{'curr_y_min'}; |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
# get the base values |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
if ( $self->false( $self->{'polar'} ) ) |
604
|
|
|
|
|
|
|
{ |
605
|
|
|
|
|
|
|
$mod = $self->{'min_val'}; |
606
|
|
|
|
|
|
|
} |
607
|
|
|
|
|
|
|
else |
608
|
|
|
|
|
|
|
{ |
609
|
|
|
|
|
|
|
$mod = $self->{'max_val'}; |
610
|
|
|
|
|
|
|
} |
611
|
|
|
|
|
|
|
$centerX = $self->{'centerX'}; |
612
|
|
|
|
|
|
|
$centerY = $self->{'centerY'}; |
613
|
|
|
|
|
|
|
$diameter = $self->{'diameter'}; |
614
|
|
|
|
|
|
|
$diff = $self->{'max_val'} - $self->{'min_val'}; |
615
|
|
|
|
|
|
|
$diff = 1 if $diff < 1; |
616
|
|
|
|
|
|
|
$map = $diameter / 2 / $diff; |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
$brush = $self->_prepare_brush( $color, 'point' ); |
619
|
|
|
|
|
|
|
$self->{'gd_obj'}->setBrush($brush); |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
# draw every line for this dataset |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
if ( $self->false( $self->{'pairs'} ) ) |
624
|
|
|
|
|
|
|
{ |
625
|
|
|
|
|
|
|
for $j ( 1 .. $self->{'num_datasets'} ) |
626
|
|
|
|
|
|
|
{ |
627
|
|
|
|
|
|
|
$color = $self->_color_role_to_index( 'dataset' . ( $j - 1 ) ); |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
for $i ( 0 .. $self->{'num_datapoints'} - 1 ) |
630
|
|
|
|
|
|
|
{ |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
# don't try to draw anything if there's no data |
633
|
|
|
|
|
|
|
if ( defined( $data->[$j][$i] ) |
634
|
|
|
|
|
|
|
&& $data->[$j][$i] <= $self->{'max_val'} |
635
|
|
|
|
|
|
|
&& $data->[$j][$i] >= $self->{'min_val'} ) |
636
|
|
|
|
|
|
|
{ #calculate the point |
637
|
|
|
|
|
|
|
$winkel = ( 180 - ( $data->[0][$i] % 360 ) ) / 360 * 2 * $pi; |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
if ( $self->false( $self->{'polar'} ) ) |
640
|
|
|
|
|
|
|
{ |
641
|
|
|
|
|
|
|
$x = ceil( $centerX + sin($winkel) * ( $data->[$j][$i] - $mod ) * $map ); |
642
|
|
|
|
|
|
|
$y = ceil( $centerY + cos($winkel) * ( $data->[$j][$i] - $mod ) * $map ); |
643
|
|
|
|
|
|
|
} |
644
|
|
|
|
|
|
|
else |
645
|
|
|
|
|
|
|
{ |
646
|
|
|
|
|
|
|
$x = ceil( $centerX + sin($winkel) * ( $mod - $data->[$j][$i] ) * $map ); |
647
|
|
|
|
|
|
|
$y = ceil( $centerY + cos($winkel) * ( $mod - $data->[$j][$i] ) * $map ); |
648
|
|
|
|
|
|
|
} |
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
# set the x and y values back |
651
|
|
|
|
|
|
|
if ( $i == 0 ) |
652
|
|
|
|
|
|
|
{ |
653
|
|
|
|
|
|
|
$first_x = $x; |
654
|
|
|
|
|
|
|
$first_y = $y; |
655
|
|
|
|
|
|
|
$last_x = $x; |
656
|
|
|
|
|
|
|
$last_y = $y; |
657
|
|
|
|
|
|
|
} |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
if ( $self->true( $self->{'point'} ) ) |
660
|
|
|
|
|
|
|
{ |
661
|
|
|
|
|
|
|
$brush = $self->_prepare_brush( $color, 'point' ); |
662
|
|
|
|
|
|
|
$self->{'gd_obj'}->setBrush($brush); |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
#draw the point |
665
|
|
|
|
|
|
|
$self->{'gd_obj'}->line( $x + 1, $y, $x, $y, gdBrushed ); |
666
|
|
|
|
|
|
|
} |
667
|
|
|
|
|
|
|
if ( $self->true( $self->{'line'} ) ) |
668
|
|
|
|
|
|
|
{ |
669
|
|
|
|
|
|
|
$brush = $self->_prepare_brush( $color, 'line' ); |
670
|
|
|
|
|
|
|
$self->{'gd_obj'}->setBrush($brush); |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
#draw the line |
673
|
|
|
|
|
|
|
if ( defined $last_x ) |
674
|
|
|
|
|
|
|
{ |
675
|
|
|
|
|
|
|
$self->{'gd_obj'}->line( $x, $y, $last_x, $last_y, gdBrushed ); |
676
|
|
|
|
|
|
|
} |
677
|
|
|
|
|
|
|
} |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
if ( $self->true( $self->{'arrow'} ) ) |
680
|
|
|
|
|
|
|
{ |
681
|
|
|
|
|
|
|
$brush = $self->_prepare_brush( $color, 'line' ); |
682
|
|
|
|
|
|
|
$self->{'gd_obj'}->setBrush($brush); |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
#draw the arrow |
685
|
|
|
|
|
|
|
if ( $data->[$j][$i] > $self->{'min_val'} ) |
686
|
|
|
|
|
|
|
{ |
687
|
|
|
|
|
|
|
$self->{'gd_obj'}->line( $x, $y, $centerX, $centerY, gdBrushed ); |
688
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
$arrow_x = $x - cos( $winkel - $alpha ) * $len; |
690
|
|
|
|
|
|
|
$arrow_y = $y + sin( $winkel - $alpha ) * $len; |
691
|
|
|
|
|
|
|
$self->{'gd_obj'}->line( $x, $y, $arrow_x, $arrow_y, gdBrushed ); |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
$arrow_x = $x + sin( $pi / 2 - $winkel - $alpha ) * $len; |
694
|
|
|
|
|
|
|
$arrow_y = $y - cos( $pi / 2 - $winkel - $alpha ) * $len; |
695
|
|
|
|
|
|
|
$self->{'gd_obj'}->line( $x, $y, $arrow_x, $arrow_y, gdBrushed ); |
696
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
} |
698
|
|
|
|
|
|
|
} |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
$last_x = $x; |
701
|
|
|
|
|
|
|
$last_y = $y; |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
# store the imagemap data if they asked for it |
704
|
|
|
|
|
|
|
if ( $self->true( $self->{'imagemap'} ) ) |
705
|
|
|
|
|
|
|
{ |
706
|
|
|
|
|
|
|
$self->{'imagemap_data'}->[$j][$i] = [ $x, $y ]; |
707
|
|
|
|
|
|
|
} |
708
|
|
|
|
|
|
|
} |
709
|
|
|
|
|
|
|
else |
710
|
|
|
|
|
|
|
{ |
711
|
|
|
|
|
|
|
if ( $self->true( $self->{'imagemap'} ) ) |
712
|
|
|
|
|
|
|
{ |
713
|
|
|
|
|
|
|
$self->{'imagemap_data'}->[$j][$i] = [ undef(), undef() ]; |
714
|
|
|
|
|
|
|
} |
715
|
|
|
|
|
|
|
} |
716
|
|
|
|
|
|
|
} # end for |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
# draw the last line to the first point |
719
|
|
|
|
|
|
|
if ( $self->true( $self->{'line'} ) ) |
720
|
|
|
|
|
|
|
{ |
721
|
|
|
|
|
|
|
$self->{'gd_obj'}->line( $x, $y, $first_x, $first_y, gdBrushed ); |
722
|
|
|
|
|
|
|
} |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
} # end for $j |
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
if ( $self->true( $self->{'pairs'} ) ) |
728
|
|
|
|
|
|
|
{ |
729
|
|
|
|
|
|
|
for ( $j = 1 ; $j <= $self->{'num_datasets'} ; $j += 2 ) |
730
|
|
|
|
|
|
|
{ |
731
|
|
|
|
|
|
|
if ( $j == 1 ) |
732
|
|
|
|
|
|
|
{ |
733
|
|
|
|
|
|
|
$color = $self->_color_role_to_index( 'dataset' . ( $j - 1 ) ); |
734
|
|
|
|
|
|
|
} |
735
|
|
|
|
|
|
|
else |
736
|
|
|
|
|
|
|
{ |
737
|
|
|
|
|
|
|
$color = $self->_color_role_to_index( 'dataset' . ( $j / 2 - 0.5 ) ); |
738
|
|
|
|
|
|
|
} |
739
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
##### $color = $self->_color_role_to_index('dataset'.(1)); ##################### |
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
for $i ( 0 .. $self->{'num_datapoints'} - 1 ) |
743
|
|
|
|
|
|
|
{ |
744
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
# don't try to draw anything if there's no data |
746
|
|
|
|
|
|
|
if ( defined( $data->[$j][$i] ) |
747
|
|
|
|
|
|
|
&& $data->[$j][$i] <= $self->{'max_val'} |
748
|
|
|
|
|
|
|
&& $data->[$j][$i] >= $self->{'min_val'} ) |
749
|
|
|
|
|
|
|
{ |
750
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
# calculate the point |
752
|
|
|
|
|
|
|
$winkel = ( 180 - ( $data->[$n][$i] % 360 ) ) / 360 * 2 * $pi; |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
if ( $self->false( $self->{'polar'} ) ) |
755
|
|
|
|
|
|
|
{ |
756
|
|
|
|
|
|
|
$x = ceil( $centerX + sin($winkel) * ( $data->[$j][$i] - $mod ) * $map ); |
757
|
|
|
|
|
|
|
$y = ceil( $centerY + cos($winkel) * ( $data->[$j][$i] - $mod ) * $map ); |
758
|
|
|
|
|
|
|
} |
759
|
|
|
|
|
|
|
else |
760
|
|
|
|
|
|
|
{ |
761
|
|
|
|
|
|
|
$x = ceil( $centerX + sin($winkel) * ( $mod - $data->[$j][$i] ) * $map ); |
762
|
|
|
|
|
|
|
$y = ceil( $centerY + cos($winkel) * ( $mod - $data->[$j][$i] ) * $map ); |
763
|
|
|
|
|
|
|
} |
764
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
# set the x and y values back |
766
|
|
|
|
|
|
|
if ( $i == 0 ) |
767
|
|
|
|
|
|
|
{ |
768
|
|
|
|
|
|
|
$first_x = $x; |
769
|
|
|
|
|
|
|
$first_y = $y; |
770
|
|
|
|
|
|
|
$last_x = $x; |
771
|
|
|
|
|
|
|
$last_y = $y; |
772
|
|
|
|
|
|
|
} |
773
|
|
|
|
|
|
|
|
774
|
|
|
|
|
|
|
if ( $self->true( $self->{'point'} ) ) |
775
|
|
|
|
|
|
|
{ |
776
|
|
|
|
|
|
|
$brush = $self->_prepare_brush( $color, 'point' ); |
777
|
|
|
|
|
|
|
$self->{'gd_obj'}->setBrush($brush); |
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
#draw the point |
780
|
|
|
|
|
|
|
$self->{'gd_obj'}->line( $x + 1, $y, $x, $y, gdBrushed ); |
781
|
|
|
|
|
|
|
} |
782
|
|
|
|
|
|
|
if ( $self->true( $self->{'line'} ) ) |
783
|
|
|
|
|
|
|
{ |
784
|
|
|
|
|
|
|
$brush = $self->_prepare_brush( $color, 'line' ); |
785
|
|
|
|
|
|
|
$self->{'gd_obj'}->setBrush($brush); |
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
#draw the line |
788
|
|
|
|
|
|
|
if ( defined $last_x ) |
789
|
|
|
|
|
|
|
{ |
790
|
|
|
|
|
|
|
$self->{'gd_obj'}->line( $x, $y, $last_x, $last_y, gdBrushed ); |
791
|
|
|
|
|
|
|
} |
792
|
|
|
|
|
|
|
else { } |
793
|
|
|
|
|
|
|
} |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
if ( $self->true( $self->{'arrow'} ) ) |
796
|
|
|
|
|
|
|
{ |
797
|
|
|
|
|
|
|
$brush = $self->_prepare_brush( $color, 'line' ); |
798
|
|
|
|
|
|
|
$self->{'gd_obj'}->setBrush($brush); |
799
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
#draw the arrow |
801
|
|
|
|
|
|
|
if ( $data->[$j][$i] > $self->{'min_val'} ) |
802
|
|
|
|
|
|
|
{ |
803
|
|
|
|
|
|
|
$self->{'gd_obj'}->line( $x, $y, $centerX, $centerY, gdBrushed ); |
804
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
$arrow_x = $x - cos( $winkel - $alpha ) * $len; |
806
|
|
|
|
|
|
|
$arrow_y = $y + sin( $winkel - $alpha ) * $len; |
807
|
|
|
|
|
|
|
$self->{'gd_obj'}->line( $x, $y, $arrow_x, $arrow_y, gdBrushed ); |
808
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
$arrow_x = $x + sin( $pi / 2 - $winkel - $alpha ) * $len; |
810
|
|
|
|
|
|
|
$arrow_y = $y - cos( $pi / 2 - $winkel - $alpha ) * $len; |
811
|
|
|
|
|
|
|
$self->{'gd_obj'}->line( $x, $y, $arrow_x, $arrow_y, gdBrushed ); |
812
|
|
|
|
|
|
|
} |
813
|
|
|
|
|
|
|
} |
814
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
$last_x = $x; |
816
|
|
|
|
|
|
|
$last_y = $y; |
817
|
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
# store the imagemap data if they asked for it |
819
|
|
|
|
|
|
|
if ( $self->true( $self->{'imagemap'} ) ) |
820
|
|
|
|
|
|
|
{ |
821
|
|
|
|
|
|
|
$self->{'imagemap_data'}->[$j][$i] = [ $x, $y ]; |
822
|
|
|
|
|
|
|
} |
823
|
|
|
|
|
|
|
} # end if ( defined ... |
824
|
|
|
|
|
|
|
else |
825
|
|
|
|
|
|
|
{ |
826
|
|
|
|
|
|
|
if ( $self->true( $self->{'imagemap'} ) ) |
827
|
|
|
|
|
|
|
{ |
828
|
|
|
|
|
|
|
$self->{'imagemap_data'}->[$j][$i] = [ undef(), undef() ]; |
829
|
|
|
|
|
|
|
} |
830
|
|
|
|
|
|
|
} |
831
|
|
|
|
|
|
|
} #end for $i |
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
# draw the last line to the first point |
834
|
|
|
|
|
|
|
if ( $self->true( $self->{'line'} ) ) |
835
|
|
|
|
|
|
|
{ |
836
|
|
|
|
|
|
|
$self->{'gd_obj'}->line( $x, $y, $first_x, $first_y, gdBrushed ); |
837
|
|
|
|
|
|
|
} |
838
|
|
|
|
|
|
|
$n += 2; |
839
|
|
|
|
|
|
|
} # end for $j |
840
|
|
|
|
|
|
|
} # end if pairs |
841
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
# now outline it |
843
|
|
|
|
|
|
|
$self->{'gd_obj'} |
844
|
|
|
|
|
|
|
->rectangle( $self->{'curr_x_min'}, $self->{'curr_y_min'}, $self->{'curr_x_max'}, $self->{'curr_y_max'}, $misccolor ); |
845
|
|
|
|
|
|
|
|
846
|
|
|
|
|
|
|
return; |
847
|
|
|
|
|
|
|
} |
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
## @fn private int _prepare_brush($color,$type) |
850
|
|
|
|
|
|
|
# set the gdBrush object to trick GD into drawing fat lines |
851
|
|
|
|
|
|
|
# |
852
|
|
|
|
|
|
|
# |
853
|
|
|
|
|
|
|
# @param[in] color Color to be used |
854
|
|
|
|
|
|
|
# @param[in] type Type of line |
855
|
|
|
|
|
|
|
# @return status |
856
|
|
|
|
|
|
|
sub _prepare_brush |
857
|
|
|
|
|
|
|
{ |
858
|
|
|
|
|
|
|
my $self = shift; |
859
|
|
|
|
|
|
|
my $color = shift; |
860
|
|
|
|
|
|
|
my $type = shift; |
861
|
|
|
|
|
|
|
my ( $radius, @rgb, $brush, $white, $newcolor ); |
862
|
|
|
|
|
|
|
|
863
|
|
|
|
|
|
|
@rgb = $self->{'gd_obj'}->rgb($color); |
864
|
|
|
|
|
|
|
|
865
|
|
|
|
|
|
|
# get the appropriate brush size |
866
|
|
|
|
|
|
|
if ( $type eq 'line' ) |
867
|
|
|
|
|
|
|
{ |
868
|
|
|
|
|
|
|
$radius = $self->{'brush_size'} / 2; |
869
|
|
|
|
|
|
|
} |
870
|
|
|
|
|
|
|
elsif ( $type eq 'point' ) |
871
|
|
|
|
|
|
|
{ |
872
|
|
|
|
|
|
|
$radius = $self->{'pt_size'} / 2; |
873
|
|
|
|
|
|
|
} |
874
|
|
|
|
|
|
|
|
875
|
|
|
|
|
|
|
# create the new image |
876
|
|
|
|
|
|
|
$brush = GD::Image->new( $radius * 2, $radius * 2 ); |
877
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
# get the colors, make the background transparent |
879
|
|
|
|
|
|
|
$white = $brush->colorAllocate( 255, 255, 255 ); |
880
|
|
|
|
|
|
|
$newcolor = $brush->colorAllocate(@rgb); |
881
|
|
|
|
|
|
|
$brush->transparent($white); |
882
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
# draw the circle |
884
|
|
|
|
|
|
|
$brush->arc( $radius - 1, $radius - 1, $radius, $radius, 0, 360, $newcolor ); |
885
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
# fill it if we're using lines |
887
|
|
|
|
|
|
|
$brush->fill( $radius - 1, $radius - 1, $newcolor ); |
888
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
# set the new image as the main object's brush |
890
|
|
|
|
|
|
|
return $brush; |
891
|
|
|
|
|
|
|
} |
892
|
|
|
|
|
|
|
|
893
|
|
|
|
|
|
|
## @fn private int _draw_legend() |
894
|
|
|
|
|
|
|
# let them know what all the pretty colors mean |
895
|
|
|
|
|
|
|
# @return status |
896
|
|
|
|
|
|
|
# |
897
|
|
|
|
|
|
|
# Overwrite corresponding function of Base |
898
|
|
|
|
|
|
|
# |
899
|
|
|
|
|
|
|
sub _draw_legend |
900
|
|
|
|
|
|
|
{ |
901
|
|
|
|
|
|
|
my $self = shift; |
902
|
|
|
|
|
|
|
my $length; |
903
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
# check to see if legend type is none.. |
905
|
|
|
|
|
|
|
if ( $self->{'legend'} =~ /^none$/ ) |
906
|
|
|
|
|
|
|
{ |
907
|
|
|
|
|
|
|
return 1; |
908
|
|
|
|
|
|
|
} |
909
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
# check to see if they have as many labels as datasets, |
911
|
|
|
|
|
|
|
# warn them if not |
912
|
|
|
|
|
|
|
if ( ( $#{ $self->{'legend_labels'} } >= 0 ) |
913
|
|
|
|
|
|
|
&& ( ( scalar( @{ $self->{'legend_labels'} } ) ) != $self->{'num_datasets'} ) ) |
914
|
|
|
|
|
|
|
{ |
915
|
|
|
|
|
|
|
carp "The number of legend labels and datasets doesn\'t match"; |
916
|
|
|
|
|
|
|
} |
917
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
# init a field to store the length of the longest legend label |
919
|
|
|
|
|
|
|
unless ( $self->{'max_legend_label'} ) |
920
|
|
|
|
|
|
|
{ |
921
|
|
|
|
|
|
|
$self->{'max_legend_label'} = 0; |
922
|
|
|
|
|
|
|
} |
923
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
# fill in the legend labels, find the longest one |
925
|
|
|
|
|
|
|
|
926
|
|
|
|
|
|
|
if ( $self->false( $self->{'pairs'} ) ) |
927
|
|
|
|
|
|
|
{ |
928
|
|
|
|
|
|
|
for ( 1 .. $self->{'num_datasets'} ) |
929
|
|
|
|
|
|
|
{ |
930
|
|
|
|
|
|
|
unless ( $self->{'legend_labels'}[ $_ - 1 ] ) |
931
|
|
|
|
|
|
|
{ |
932
|
|
|
|
|
|
|
$self->{'legend_labels'}[ $_ - 1 ] = "Dataset $_"; |
933
|
|
|
|
|
|
|
} |
934
|
|
|
|
|
|
|
$length = length( $self->{'legend_labels'}[ $_ - 1 ] ); |
935
|
|
|
|
|
|
|
if ( $length > $self->{'max_legend_label'} ) |
936
|
|
|
|
|
|
|
{ |
937
|
|
|
|
|
|
|
$self->{'max_legend_label'} = $length; |
938
|
|
|
|
|
|
|
} |
939
|
|
|
|
|
|
|
} #end for |
940
|
|
|
|
|
|
|
} |
941
|
|
|
|
|
|
|
|
942
|
|
|
|
|
|
|
if ( $self->true( $self->{'pairs'} ) ) |
943
|
|
|
|
|
|
|
{ |
944
|
|
|
|
|
|
|
|
945
|
|
|
|
|
|
|
for ( 1 .. ceil( $self->{'num_datasets'} / 2 ) ) |
946
|
|
|
|
|
|
|
{ |
947
|
|
|
|
|
|
|
unless ( $self->{'legend_labels'}[ $_ - 1 ] ) |
948
|
|
|
|
|
|
|
{ |
949
|
|
|
|
|
|
|
$self->{'legend_labels'}[ $_ - 1 ] = "Dataset $_"; |
950
|
|
|
|
|
|
|
} |
951
|
|
|
|
|
|
|
$length = length( $self->{'legend_labels'}[ $_ - 1 ] ); |
952
|
|
|
|
|
|
|
if ( $length > $self->{'max_legend_label'} ) |
953
|
|
|
|
|
|
|
{ |
954
|
|
|
|
|
|
|
$self->{'max_legend_label'} = $length; |
955
|
|
|
|
|
|
|
} |
956
|
|
|
|
|
|
|
} |
957
|
|
|
|
|
|
|
} |
958
|
|
|
|
|
|
|
|
959
|
|
|
|
|
|
|
# different legend types |
960
|
|
|
|
|
|
|
if ( $self->{'legend'} eq 'bottom' ) |
961
|
|
|
|
|
|
|
{ |
962
|
|
|
|
|
|
|
$self->_draw_bottom_legend; |
963
|
|
|
|
|
|
|
} |
964
|
|
|
|
|
|
|
elsif ( $self->{'legend'} eq 'right' ) |
965
|
|
|
|
|
|
|
{ |
966
|
|
|
|
|
|
|
$self->_draw_right_legend; |
967
|
|
|
|
|
|
|
} |
968
|
|
|
|
|
|
|
elsif ( $self->{'legend'} eq 'left' ) |
969
|
|
|
|
|
|
|
{ |
970
|
|
|
|
|
|
|
$self->_draw_left_legend; |
971
|
|
|
|
|
|
|
} |
972
|
|
|
|
|
|
|
elsif ( $self->{'legend'} eq 'top' ) |
973
|
|
|
|
|
|
|
{ |
974
|
|
|
|
|
|
|
$self->_draw_top_legend; |
975
|
|
|
|
|
|
|
} |
976
|
|
|
|
|
|
|
else |
977
|
|
|
|
|
|
|
{ |
978
|
|
|
|
|
|
|
carp "I can't put a legend there (at " . $self->{'legend'} . ")\n"; |
979
|
|
|
|
|
|
|
} |
980
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
# and return |
982
|
|
|
|
|
|
|
return 1; |
983
|
|
|
|
|
|
|
} |
984
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
## @fn private array _find_y_range() |
986
|
|
|
|
|
|
|
# Find minimum and maximum value of y data sets. |
987
|
|
|
|
|
|
|
# |
988
|
|
|
|
|
|
|
# @return ( min, max, flag_all_integers ) |
989
|
|
|
|
|
|
|
# |
990
|
|
|
|
|
|
|
# Overwrites corresponding Base function |
991
|
|
|
|
|
|
|
# |
992
|
|
|
|
|
|
|
sub _find_y_range |
993
|
|
|
|
|
|
|
{ |
994
|
|
|
|
|
|
|
my $self = shift; |
995
|
|
|
|
|
|
|
my $data = $self->{'dataref'}; |
996
|
|
|
|
|
|
|
|
997
|
|
|
|
|
|
|
my $max = undef; |
998
|
|
|
|
|
|
|
my $min = undef; |
999
|
|
|
|
|
|
|
my $k = 1; |
1000
|
|
|
|
|
|
|
my $dataset = 1; |
1001
|
|
|
|
|
|
|
my $datum; |
1002
|
|
|
|
|
|
|
|
1003
|
|
|
|
|
|
|
if ( $self->false( $self->{'pairs'} ) ) |
1004
|
|
|
|
|
|
|
{ |
1005
|
|
|
|
|
|
|
for $dataset ( @$data[ 1 .. $#$data ] ) |
1006
|
|
|
|
|
|
|
{ |
1007
|
|
|
|
|
|
|
|
1008
|
|
|
|
|
|
|
# print "dataset @$dataset\n"; |
1009
|
|
|
|
|
|
|
for $datum (@$dataset) |
1010
|
|
|
|
|
|
|
{ |
1011
|
|
|
|
|
|
|
if ( defined $datum ) |
1012
|
|
|
|
|
|
|
{ |
1013
|
|
|
|
|
|
|
|
1014
|
|
|
|
|
|
|
# Prettier, but probably slower: |
1015
|
|
|
|
|
|
|
# $max = $datum unless defined $max && $max >= $datum; |
1016
|
|
|
|
|
|
|
# $min = $datum unless defined $min && $min <= $datum; |
1017
|
|
|
|
|
|
|
if ( defined $max ) |
1018
|
|
|
|
|
|
|
{ |
1019
|
|
|
|
|
|
|
if ( $datum > $max ) { $max = $datum; } |
1020
|
|
|
|
|
|
|
elsif ( $datum < $min ) { $min = $datum; } |
1021
|
|
|
|
|
|
|
} |
1022
|
|
|
|
|
|
|
else |
1023
|
|
|
|
|
|
|
{ |
1024
|
|
|
|
|
|
|
$min = $max = $datum; |
1025
|
|
|
|
|
|
|
} |
1026
|
|
|
|
|
|
|
} #endif defined |
1027
|
|
|
|
|
|
|
} # end for |
1028
|
|
|
|
|
|
|
} |
1029
|
|
|
|
|
|
|
} |
1030
|
|
|
|
|
|
|
|
1031
|
|
|
|
|
|
|
if ( $self->true( $self->{'pairs'} ) ) |
1032
|
|
|
|
|
|
|
{ |
1033
|
|
|
|
|
|
|
|
1034
|
|
|
|
|
|
|
# only every second dataset must be checked |
1035
|
|
|
|
|
|
|
for $dataset ( @$data[$k] ) |
1036
|
|
|
|
|
|
|
{ |
1037
|
|
|
|
|
|
|
for $datum (@$dataset) |
1038
|
|
|
|
|
|
|
{ |
1039
|
|
|
|
|
|
|
if ( defined $datum ) |
1040
|
|
|
|
|
|
|
{ |
1041
|
|
|
|
|
|
|
|
1042
|
|
|
|
|
|
|
# Prettier, but probably slower: |
1043
|
|
|
|
|
|
|
# $max = $datum unless defined $max && $max >= $datum; |
1044
|
|
|
|
|
|
|
# $min = $datum unless defined $min && $min <= $datum; |
1045
|
|
|
|
|
|
|
if ( defined $max ) |
1046
|
|
|
|
|
|
|
{ |
1047
|
|
|
|
|
|
|
if ( $datum > $max ) { $max = $datum; } |
1048
|
|
|
|
|
|
|
elsif ( $datum < $min ) { $min = $datum; } |
1049
|
|
|
|
|
|
|
} |
1050
|
|
|
|
|
|
|
else |
1051
|
|
|
|
|
|
|
{ |
1052
|
|
|
|
|
|
|
$min = $max = $datum; |
1053
|
|
|
|
|
|
|
} |
1054
|
|
|
|
|
|
|
} |
1055
|
|
|
|
|
|
|
} |
1056
|
|
|
|
|
|
|
$k += 2; |
1057
|
|
|
|
|
|
|
} |
1058
|
|
|
|
|
|
|
} |
1059
|
|
|
|
|
|
|
|
1060
|
|
|
|
|
|
|
( $min, $max ); |
1061
|
|
|
|
|
|
|
} |
1062
|
|
|
|
|
|
|
|
1063
|
|
|
|
|
|
|
## be a good module and return 1 |
1064
|
|
|
|
|
|
|
1; |