File Coverage

blib/lib/Geo/GNUPlot.pm
Criterion Covered Total %
statement 12 483 2.4
branch 0 182 0.0
condition 0 63 0.0
subroutine 4 21 19.0
pod 4 4 100.0
total 20 753 2.6


line stmt bran cond sub pod time code
1             package Geo::GNUPlot;
2              
3 1     1   51109 use strict;
  1         2  
  1         40  
4 1     1   6 use Carp;
  1         2  
  1         89  
5 1     1   6 use IO::File;
  1         7  
  1         247  
6 1     1   6 use vars qw($VERSION $DEBUG);
  1         2  
  1         9899  
7              
8             $VERSION = '0.01';
9             #$DEBUG = 0;
10              
11             #-------------------------------------------------------
12             #New method for Geo::GNUPlot
13             #Notice that it has a mandatory configuration file argument.
14             sub new {
15 0     0 1   my $self=shift;
16 0           my $option_HR=shift;
17              
18 0           my ($grid_HR, $msg, $grid_file, $map_file, $gnuplot)=undef;
19              
20 0           $grid_file=$option_HR->{'grid_file'};
21 0           $map_file=$option_HR->{'map_file'};
22 0           $gnuplot=$option_HR->{'gnuplot'};
23            
24 0 0         unless (defined $grid_file){
25 0           $msg="new method called without the mandatory grid_file option key!";
26 0           carp $msg,"\n";
27 0           return (undef,$msg);
28             }#unless
29              
30 0 0         unless (defined $map_file){
31 0           $msg="new method called without the mandatory map_file option key!";
32 0           carp $msg,"\n";
33 0           return (undef,$msg);
34             }#unless
35            
36 0 0         unless (defined $gnuplot){
37 0           $msg="new method called without the mandatory gnuplot option key!";
38 0           carp $msg,"\n";
39 0           return (undef,$msg);
40             }#unless
41              
42 0           $self={};
43 0           bless($self,'Geo::GNUPlot');
44              
45 0           ($grid_HR,$msg)=$self->_read_grid($grid_file);
46 0 0         return (undef,$msg) unless (defined $grid_HR);
47              
48 0           $self->{'grid_HR'}=$grid_HR;
49 0           $self->{'map_file'}=$map_file;
50 0           $self->{'gnuplot'}=$gnuplot;
51              
52 0           return ($self,undef);
53             }#new
54             #------------------------------------------------------
55             #If $track_AR has 2 elements in the first point in the track it is assumed
56             #the incomming position data is in x,y form.
57             #Otherwise it is assumed the incomming position data is in
58             #($long, $long_dir, $lat, $lat_dir) form.
59             sub plot_track {
60 0     0 1   my $self=shift;
61 0           my $track_AR=shift;
62 0           my $output_file=shift;
63 0           my $option_HR=shift;
64              
65 0           my ($success, $error, $xy_data_AR, $radius, $temp_dir, $ppm_file)=undef;
66 0           my ($data_file, $config_file, $msg, $x_range_AR, $y_range_AR)=undef;
67 0           my ($x_pad, $y_pad, $x_scale, $y_scale, $term, $title)=undef;
68              
69             #Determine x_pad, y_pad, x_scale, y_scale, and term
70 0 0         if (defined $option_HR->{'x_pad'}){
71 0           $x_pad=$option_HR->{'x_pad'};
72             }
73             else {
74 0           $x_pad=0;
75             }#if/else
76            
77 0 0         if (defined $option_HR->{'y_pad'}){
78 0           $y_pad=$option_HR->{'y_pad'};
79             }
80             else {
81 0           $y_pad=0;
82             }#if/else
83              
84 0 0         if (defined $option_HR->{'x_scale'}){
85 0           $x_scale=$option_HR->{'x_scale'};
86             }
87             else {
88 0           $x_scale=1;
89             }#if/else
90              
91 0 0         if (defined $option_HR->{'y_scale'}){
92 0           $y_scale=$option_HR->{'y_scale'};
93             }
94             else {
95 0           $y_scale=1;
96             }#if/else
97              
98 0 0         if (defined $option_HR->{'title'}){
99 0           $title=$option_HR->{'title'};
100             }
101             else {
102 0           $title='Storm Tracking Map';
103             }#if/else
104            
105 0 0         if (defined $option_HR->{'term'}){
106 0           $term=$option_HR->{'term'};
107             }
108             else {
109 0           $term='gif';
110             }#if/else
111              
112             #Determine names for $data_file and $config_file.
113 0 0         if (defined $option_HR->{'temp_dir'}){
114 0           $temp_dir=$option_HR->{'temp_dir'};
115             }
116             else {
117 0           $temp_dir='/tmp/';
118             }
119              
120 0           $temp_dir =~ s!/*!/!;
121 0           $data_file=$temp_dir."datafile_$$";
122 0           $config_file=$temp_dir."configfile_$$";
123              
124             #Figure out what kind of track was passed.
125             #If necessary convert ($long, $long_dir, $lat, $lat_dir) form to xy form.
126 0 0         if (scalar(@{${$track_AR}[0]}) == 2){
  0            
  0            
127 0           $xy_data_AR=$track_AR;
128             }
129             else {
130             #Get the track in x,y form as well as check the syntax of the position arrays.
131 0           ($xy_data_AR,$error)=$self->_generate_xy_data($track_AR);
132              
133             #Abort if _generage_xy_data had a problem.
134 0 0         return (0,$error) unless (defined $xy_data_AR);
135             }#if/else
136              
137             #Write out the data file for gnuplot to plot.
138 0           ($success, $error)=$self->_write_plot_data_file($xy_data_AR,$data_file);
139 0 0         return (0,$error) unless ($success);
140              
141              
142 0           ($x_range_AR,$y_range_AR,$error)=$self->_get_range({
143             x_pad => $x_pad,
144             y_pad => $y_pad,
145             x_scale => $x_scale,
146             y_scale => $y_scale,
147 0           center_point => ${$xy_data_AR}[0],
148             });
149              
150 0 0 0       return (0, $error) unless ( (defined $x_range_AR) and (defined $y_range_AR) );
151              
152             #Write out the config file for gnuplot.
153 0           ($success, $error)=$self->_write_plot_config_file({
154             'config_file'=>$config_file,
155             'data_file'=>$data_file,
156             'output'=>$output_file,
157             'xrange' => $x_range_AR,
158             'yrange' => $y_range_AR,
159             'term' => $term,
160             'title' => $title,
161             });
162 0 0         return (0,$error) unless ($success);
163              
164             #Call gnuplot on the config file.
165 0           ($success, $error)=$self->_call_gnuplot($config_file);
166 0 0         return (0,$error) unless ($success);
167              
168             #Erase temporary files
169 0           ($success, $error)=$self->_wack_files($data_file, $config_file);
170 0 0         return (0,$error) unless ($success);
171              
172 0           return (1,undef);
173              
174             }#plot_track
175             #-------------------------------------------------------
176             sub plot_radius_function {
177 0     0 1   my $self=shift;
178 0           my $output_file=shift;
179 0           my $output_file2=shift;
180 0           my $option_HR=shift;
181              
182 0           my ($term, $temp_dir)=undef;
183 0           my ($data_file, $data_file2, $config_file, $config_file2, $config_file3, $map_file)=undef;
184 0           my ($gnuplot_script, $gnuplot_script2, $gnuplot_script3)=undef;
185 0           my ($success, $error)=undef;
186              
187 0 0         if (defined $option_HR->{'term'}){
188 0           $term=$option_HR->{'term'};
189             }
190             else {
191 0           $term='gif';
192             }#if/else
193              
194             #Determine names for $data_file and $config_file.
195 0 0         if (defined $option_HR->{'temp_dir'}){
196 0           $temp_dir=$option_HR->{'temp_dir'};
197             }
198             else {
199 0           $temp_dir='/tmp/';
200             }
201              
202 0           $temp_dir =~ s!/*!/!;
203              
204 0           $data_file=$temp_dir."datafile_$$";
205 0           $data_file2=$temp_dir."datafile2_$$";
206              
207 0           $config_file=$temp_dir."configfile_$$";
208 0           $config_file2=$temp_dir."configfile2_$$";
209 0           $config_file3=$temp_dir."configfile3_$$";
210              
211 0           $map_file=$self->{'map_file'};
212              
213             #######
214             #Generate 3d radius data
215 0           ($success, $error)=$self->_generate_radius_data_file($data_file);
216              
217             ########
218             #Create a 2d contour file from the 3d data
219              
220 0           $gnuplot_script="set nosurface\nset contour\nset cntrparam levels 15\nset term table\nset output \'$data_file2\'\nsplot \'$data_file\'\n";
221              
222 0           ($success,$error)=$self->_make_file($config_file,$gnuplot_script);
223 0 0         return (0,$error) unless ($success);
224              
225             #Call gnuplot on the config file.
226 0           ($success, $error)=$self->_call_gnuplot($config_file);
227 0 0         return (0,$error) unless ($success);
228              
229              
230             ########
231             #Plot the contour ontop of the world map
232 0           $gnuplot_script2 = "set nokey\nset border\nset xtics\nset ytics\nset term $term\n";
233 0           $gnuplot_script2 .= "set output \'$output_file\'\nplot \'$data_file2\' with lines, \'$map_file\' with lines\n";
234              
235 0           ($success,$error)=$self->_make_file($config_file2,$gnuplot_script2);
236 0 0         return (0,$error) unless ($success);
237              
238             #Call gnuplot on the config file.
239 0           ($success, $error)=$self->_call_gnuplot($config_file2);
240 0 0         return (0,$error) unless ($success);
241              
242             #######
243             #Plot the 3d contour plot
244 0           $gnuplot_script3 = "set key\nset hidden\nset border\nset xtics\nset ytics\nset term $term\n";
245 0           $gnuplot_script3 .= "set contour base\nset cntrparam levels 15\nset autoscale\n";
246 0           $gnuplot_script3 .= "set output \'$output_file2\'\nsplot \'$data_file\' with lines\n";
247              
248 0           ($success,$error)=$self->_make_file($config_file3,$gnuplot_script3);
249 0 0         return (0,$error) unless ($success);
250              
251             #Call gnuplot on the config file.
252 0           ($success, $error)=$self->_call_gnuplot($config_file3);
253 0 0         return (0,$error) unless ($success);
254              
255              
256             ########
257             #Erase temporary files
258 0           ($success, $error)=$self->_wack_files($data_file, $data_file2, $config_file, $config_file2, $config_file3);
259 0 0         return (0,$error) unless ($success);
260              
261             #######
262             #All done
263 0           return (1,undef);
264              
265             }#plot_radius_function
266             #-------------------------------------------------------
267             sub _make_file {
268 0     0     my $self=shift;
269 0           my $filename=shift;
270 0           my $string=shift;
271              
272 0           my ($io, $msg)=undef;
273              
274 0           $io=IO::File->new();
275 0 0         unless ($io->open(">$filename")){
276 0           $msg = "Had trouble writting to $filename!";
277 0           carp $msg,"\n";
278 0           return (0, $msg);
279             }#unless
280 0           $io->print($string);
281 0           $io->close();
282              
283 0           return (1,undef);
284              
285             }#_make_file
286             #-------------------------------------------------------
287             sub _wack_files {
288 0     0     my $self=shift;
289 0           my @files=@_;
290              
291 0           my ($msg, $file)=undef;
292              
293 0 0         unless ($DEBUG) {
294 0           foreach $file (@files){
295 0 0         unless(unlink $file){
296 0           $msg="The $file file could not be erased!";
297 0           carp $msg,"\n";
298 0           return (0,$msg);
299             }#unless
300             }#foreach
301             }#unless
302              
303 0           return (1, undef);
304             }#_wack_files
305             #-------------------------------------------------------
306             sub _generate_radius_data_file {
307 0     0     my $self=shift;
308 0           my $data_file=shift;
309              
310 0           my ($io, $x, $y, $radius, $error, $msg)=undef;
311              
312 0 0         $io=IO::File->new() or croak "Couldn't create new io object!";
313 0 0         unless ($io->open(">$data_file")){
314 0           $msg="Couldn't open $data_file for writing!";
315 0           carp $msg, "\n";
316 0           return (0, $msg);
317             }#unless
318              
319 0           for ($x=-180; $x<=180; $x+=3){
320 0           for ($y=-90; $y<=90; $y+=3){
321 0           ($radius, $error)=$self->radius_function([$x, $y]);
322 0 0         return (0, $error) unless (defined $radius);
323 0           $io->print("$x\t$y\t$radius\n");
324             }#for
325 0           $io->print("\n");
326             }#for
327              
328 0           $io->close();
329              
330 0           return (1,undef);
331             }#_generate_radius_data_file
332             #-------------------------------------------------------
333             #($x_range_AR,$y_range_AR,$error)=$self->_get_range({
334             # x_pad => 1,
335             # y_pad => 1,
336             # x_scale => 2.5,
337             # y_scale => 2.5,
338             # center_pont => ${$xy_data_AR}[0]), # or [2,5]
339             # });
340             sub _get_range {
341 0     0     my $self=shift;
342 0           my $option_HR=shift;
343              
344 0           my ($radius, $error, $x_pad, $y_pad, $x_scale, $y_scale, $center_point)=undef;
345 0           my ($x_low, $x_high, $y_low, $y_high, $x_center, $y_center, $msg)=undef;
346              
347 0           $x_pad=$option_HR->{'x_pad'};
348 0           $y_pad=$option_HR->{'y_pad'};
349 0           $x_scale=$option_HR->{'x_scale'};
350 0           $y_scale=$option_HR->{'y_scale'};
351 0           $center_point=$option_HR->{'center_point'};
352 0           $x_center=${$center_point}[0];
  0            
353 0           $y_center=${$center_point}[1];
  0            
354              
355 0 0 0       unless ((defined $x_pad) and (defined $y_pad) and
      0        
      0        
      0        
356             (defined $x_scale) and (defined $y_scale) and
357             (defined $center_point)){
358 0           $msg="_get_range requires valid x_pad, y_pad, x_scale, y_scale, and ";
359 0           $msg .= "center_point keys in its mandatory hash reference argument. ";
360 0           $msg .= "At least one of these was ill defined!";
361 0           carp $msg, "\n";
362 0           return (undef, undef, $msg);
363             }#unless
364              
365             #Determine the plot radius.
366 0           ($radius, $error)=$self->radius_function($center_point);
367              
368 0 0         unless (defined $radius){
369 0           return (undef, undef, $error);
370             }
371              
372 0           $y_low=$y_center-$radius*$y_scale-$y_pad;
373 0 0         if ($y_low < -90){
374 0           $y_low= -90;
375             }#if
376              
377 0           $y_high=$y_center+$radius*$y_scale+$y_pad;
378              
379 0 0         if ($y_high > 90){
380 0           $y_high=90;
381             }#if
382              
383 0           $x_low=$x_center-$radius*$x_scale-$x_pad;
384 0 0         if ($x_low < -180){
385 0           $x_low=180;
386             }#if
387              
388 0           $x_high=$x_center+$radius*$x_scale+$x_pad;
389 0 0         if ($x_high > 180){
390 0           $x_high=180;
391             }#if
392              
393              
394 0           return ([$x_low, $x_high],[$y_low, $y_high], undef);
395              
396             }#_get_range
397             #-------------------------------------------------------
398             sub _call_gnuplot {
399 0     0     my $self=shift;
400 0           my $config_file=shift;
401              
402 0           my ($gnuplot, $msg, $exit_status, $error)=undef;
403              
404 0           $gnuplot=$self->{'gnuplot'};
405              
406 0 0         unless (-e $gnuplot){
407 0           $msg="Gnuplot executable could not be found at $gnuplot!";
408 0           $msg.=" Examine new method of Geo::GNUPlot!";
409 0           carp $msg,"\n";
410 0           return (0,$msg);
411             }#unless
412              
413 0           $exit_status=system("$gnuplot $config_file");
414 0           $error=$!;
415 0           $exit_status=$exit_status/256;
416 0 0         unless ($exit_status == 0){
417 0           $msg="Execution of gnuplot failed. Exit status was $exit_status. Error was $error";
418 0           carp $msg,"\n";
419 0           return (0,$msg);
420             }#unless
421              
422 0           return (1,undef);
423             }#_call_gnuplot
424             #-------------------------------------------------------
425             sub _write_plot_config_file {
426 0     0     my $self=shift;
427 0           my $option_HR=shift;
428              
429 0           my ($io, $msg)=undef;
430              
431 0           $io=IO::File->new();
432 0 0         unless ($io->open($option_HR->{'config_file'},'w')){
433 0           $msg="Couldn't open ".$option_HR->{'configfile'}." for writting!";
434 0           carp $msg,"\n";
435 0           return (0,$msg);
436             }#unless
437              
438             #Key option
439 0 0         if (!defined $option_HR->{'key'}){
    0          
440 0           $io->print("set nokey\n");
441             }
442             elsif ($option_HR->{'key'}){
443 0           $io->print("set key\n");
444             }
445             else {
446 0           $io->print("set nokey\n");
447             }#if/elsif/else
448              
449             #Border option
450 0 0         if (!defined $option_HR->{'border'}){
    0          
451 0           $io->print("set border\n");
452             }
453             elsif ($option_HR->{'border'}){
454 0           $io->print("set border\n");
455             }
456             else {
457 0           $io->print("set noborder\n");
458             }#if/elsif/else
459              
460             #Yzeroaxis option
461 0 0         if (!defined $option_HR->{'yzeroaxis'}){
    0          
462 0           $io->print("set yzeroaxis\n");
463             }
464             elsif ($option_HR->{'yzeroaxis'}){
465 0           $io->print("set yzeroaxis\n");
466             }
467             else {
468 0           $io->print("set noyzeroaxis\n");
469             }#if/elsif/else
470              
471             #Xzeroaxis option
472 0 0         if (!defined $option_HR->{'xzeroaxis'}){
    0          
473 0           $io->print("set noxzeroaxis\n");
474             }
475             elsif ($option_HR->{'xzeroaxis'}){
476 0           $io->print("set xzeroaxis\n");
477             }
478             else {
479 0           $io->print("set noxzeroaxis\n");
480             }#if/elsif/else
481              
482             #X and Y range
483 0 0 0       if((defined $option_HR->{'xrange'}) and (defined $option_HR->{'yrange'})){
484 0           $io->print("set xrange \[",${$option_HR->{'xrange'}}[0],":",${$option_HR->{'xrange'}}[1],"\]\n");
  0            
  0            
485 0           $io->print("set yrange \[",${$option_HR->{'yrange'}}[0],":",${$option_HR->{'yrange'}}[1],"\]\n");
  0            
  0            
486             }
487             else {
488 0           $io->print("set autoscale\n");
489             }#if/else
490              
491             #Xtics option
492 0 0         if (!defined $option_HR->{'xtics'}){
    0          
493 0           $io->print("set xtics\n");
494             }
495             elsif ($option_HR->{'xtics'}){
496 0           $io->print("set xtics\n");
497             }
498             else {
499 0           $io->print("set noxtics\n");
500             }#if/elsif/else
501              
502             #Ytics option
503 0 0         if (!defined $option_HR->{'ytics'}){
    0          
504 0           $io->print("set ytics\n");
505             }
506             elsif ($option_HR->{'ytics'}){
507 0           $io->print("set ytics\n");
508             }
509             else {
510 0           $io->print("set noytics\n");
511             }#if/elsif/else
512              
513 0 0         if ($option_HR->{'title'}){
514 0           $io->print("set title \'".$option_HR->{'title'}."\'\n");
515             }#if
516              
517 0 0         if (!defined $option_HR->{'output'}){
    0          
518 0           $msg="output option to _write_plot_config_file must be set!";
519 0           carp $msg,"\n";
520 0           return (0,$msg);
521             }
522             elsif ($option_HR->{'output'}){
523 0           $io->print("set output \'".$option_HR->{'output'}."\'\n");
524             }#if/elsif
525              
526             #set term
527 0 0         if (defined $option_HR->{'term'}){
528 0           $io->print("set term ",$option_HR->{'term'},"\n");
529             }
530             else {
531 0           $io->print("set term gif\n");
532             }#if/else
533              
534             #Check to make sure datafile exists.
535 0 0 0       unless ( (defined $option_HR->{'data_file'}) and (-e $option_HR->{'data_file'}) ){
536 0           $msg="data_file option to _write_plot_config_file is not set or the file doesn't exist!";
537 0           carp $msg,"\n";
538 0           return (0,$msg);
539             }#unless
540              
541 0           $io->print("plot \'",$self->{'map_file'},"\' with lines 1 2\, \'",
542             $option_HR->{'data_file'},"\' using 1:2 with lines 3 4\n");
543              
544 0           $io->close();
545              
546 0           return (1,undef);
547             }#_write_plot_config_file
548             #-------------------------------------------------------
549             sub _generate_xy_data {
550 0     0     my $self=shift;
551 0           my $track_AR=shift;
552              
553 0           my ($position_AR, $xy_AR, $error)=undef;
554 0           my @xy_data=();
555            
556 0           foreach $position_AR (@{$track_AR}){
  0            
557 0           ($xy_AR, $error)=$self->_position_to_xy($position_AR);
558 0 0         return (undef, $error) unless (defined $xy_AR);
559 0           push (@xy_data,$xy_AR);
560             }#foreach
561              
562 0           return (\@xy_data,undef);
563             }#_generate_xy_data
564             #-------------------------------------------------------
565             sub _write_plot_data_file {
566 0     0     my $self=shift;
567 0           my $xy_data_AR=shift;
568 0           my $filename=shift;
569              
570 0           my ($io, $msg, $xy_AR)=undef;
571              
572 0           $io=IO::File->new();
573 0 0         unless ( $io->open(">$filename") ) {
574 0           $msg="Couldn't open $filename for writting in _write_plot_data_file!";
575 0           carp $msg,"\n";
576 0           return (0,$msg);
577             }#unless
578 0           foreach $xy_AR (@{$xy_data_AR}){
  0            
579 0           $io->print(join("\t",@{$xy_AR}),"\n");
  0            
580             }#foreach
581 0           $io->close();
582              
583 0           return (1,undef);
584             }#_write_plot_data_file
585             #-------------------------------------------------------
586             sub _read_grid {
587 0     0     my $self=shift;
588 0           my $config_file=shift;
589              
590 0           my ($io, $msg, $anon_HR, $y_index, $in_line, $xtics, $ytics, $radius_grid)=undef;
591 0           my ($matches, $i)=undef;
592 0           my @xtics=();
593 0           my @ytics=();
594 0           my @x_array=();
595 0           my $grid_HR={};
596              
597 0           $io=IO::File->new();
598 0 0         unless($io->open("<$config_file")){
599 0           $msg="Couldn't open $config_file!";
600 0           carp $msg,"\n";
601 0           return (undef, $msg);
602             }#unless;
603              
604 0           $y_index=-1;
605              
606 0           while (defined($in_line=$io->getline)){
607 0           chomp $in_line;
608              
609             #Watch for comment lines
610 0 0 0       next if (($in_line =~ m!^\s*#!) or ($in_line =~ m!^\s*$!));
611              
612 0 0         unless ($xtics){
613 0           $matches=($in_line=~ m!^xtics\:(.*)!i);
614 0 0         if ($matches){
615 0           @xtics=split(',',$1);
616 0           $xtics=scalar(@xtics);
617             #get rid of any spaces around the numbers.
618 0           map {s!([\d\.]*)!$1!} @xtics;
  0            
619 0 0         if ($self->_is_assending(@xtics)){
620 0           next;
621             }
622             else {
623 0           $msg="xtics are not in numerically assending order ";
624 0           $msg.="or has undefined values!";
625 0           carp $msg,"\n";
626 0           return (undef,$msg);
627             }#if/else
628             }
629             else {
630 0           next;
631             }#if/else
632             }#unless
633              
634 0 0         unless ($ytics){
635 0           $matches=($in_line=~ m!^ytics\:(.*)!i);
636 0 0         if ($matches){
637 0           @ytics=split(',',$1);
638 0           $ytics=scalar(@ytics);
639             #get rid of any spaces around the numbers.
640 0           map {s!([\d\.]*)!$1!} @ytics;
  0            
641 0 0         if ($self->_is_descending(@ytics)){
642 0           next;
643             }
644             else {
645 0           $msg="ytics are not in numerically descending order ";
646 0           $msg.="or has undefined values!";
647 0           carp $msg,"\n";
648 0           return (undef,$msg);
649             }#if/else
650             }
651             else {
652 0           next;
653             }#if/else
654             }#unless
655              
656 0 0         unless ($radius_grid){
657 0           $matches=($in_line=~ m!^radius_grid\:!i);
658 0 0         $radius_grid=1 if ($matches);
659 0           next;
660             }#unless
661              
662 0           @x_array=split("\t",$in_line);
663 0 0         unless (scalar(@x_array) == $xtics){
664 0           $msg="Badly formed radius_grid! Too many columns!";
665 0           carp $msg,"\n";
666 0           return (undef,$msg);
667             }#unless
668              
669             #get rid of any spaces around the numbers.
670 0           map {s!([\d\.]*)!$1!} @x_array;
  0            
671              
672              
673             #Increment y_index
674 0           $y_index++;
675              
676             #Make sure there are not too many rows.
677 0 0         if ($y_index >= $ytics){
678 0           $msg="Badly formed radius_grid! Too many rows!";
679 0           carp $msg, "\n";
680 0           return (undef,$msg);
681             }#if
682              
683 0           $anon_HR={};
684 0           for ($i=0; $i<$xtics; $i++){
685 0           $anon_HR->{${xtics}[$i]}=$x_array[$i];
686             }#for
687              
688 0           $grid_HR->{${ytics}[$y_index]}=$anon_HR;
689              
690             }#while
691              
692 0           return ($grid_HR,undef);
693              
694             }#_read_grid
695             #-------------------------------------------------------
696             #Returns 1 only if all elements of the input array
697             #are numerically decreasing and defined.
698             #Returns 0 otherwise.
699             sub _is_descending {
700 0     0     my $self=shift;
701 0           my @array=@_;
702              
703 0           my ($last_elem, $elem)=undef;
704              
705 0           foreach $elem (@array){
706 0 0         return 0 if (!defined $elem);
707 0 0         if (defined $last_elem){
708 0 0         if ($elem < $last_elem){
709 0           $last_elem=$elem;
710 0           next;
711             }
712             else {
713 0           return 0;
714             }#if/else
715             }
716             else{
717 0           $last_elem=$elem;
718             }#if/else
719             }#foreach
720 0           return 1;
721             }#_is_descending
722             #-------------------------------------------------------
723             #Returns 1 only if all elements of the input array
724             #are numerically increasing and defined.
725             #Returns 0 otherwise.
726             sub _is_assending {
727 0     0     my $self=shift;
728 0           my @array=@_;
729              
730 0           my ($last_elem, $elem)=undef;
731              
732 0           foreach $elem (@array){
733 0 0         return 0 if (!defined $elem);
734 0 0         if (defined $last_elem){
735 0 0         if ($elem > $last_elem){
736 0           $last_elem=$elem;
737 0           next;
738             }
739             else {
740 0           return 0;
741             }#if/else
742             }
743             else{
744 0           $last_elem=$elem;
745             }#if/else
746             }#foreach
747 0           return 1;
748             }#_is_assending
749             #-------------------------------------------------------
750             #If $position_AR has 2 elements it is assumed the incomming position is in x,y form.
751             #Otherwise it is assumed the incomming position is in ($long, $long_dir, $lat, $lat_dir) form.
752             sub radius_function {
753 0     0 1   my $self=shift;
754 0           my $position_AR=shift;
755            
756 0           my ($xkey1, $xkey2, $ykey1, $ykey2, $xy_AR, $x, $y, $msg)=undef;
757 0           my ($grid_HR, $x_delta_from_xkey1, $delta_xkey, $y_delta_from_ykey1, $delta_ykey)=undef;
758 0           my ($f1, $f2, $f3, $f4, $t, $u, $f_interpolated)=undef;
759              
760 0 0         if (scalar(@{$position_AR}) == 2){
  0            
761 0           $xy_AR=$position_AR;
762             }
763             else {
764             #Get the postion in x,y form as well as check the syntax of the referenced position array.
765 0           ($xy_AR,$msg)=$self->_position_to_xy($position_AR);
766              
767             #Abort if _position_to_xy had a problem.
768 0 0         return (undef,$msg) unless (defined $xy_AR);
769             }#if/else
770              
771             #Determine high and low key values for both the y and the x axis.
772 0           $x=${$xy_AR}[0];
  0            
773 0           $y=${$xy_AR}[1];
  0            
774            
775 0           ($xkey1,$xkey2,$ykey1,$ykey2)=$self->_find_grid_square($x,$y);
776              
777             #Using equation 3.6.3, 3.6.4, and 3.6.5 on page 117 of
778             #Numerical Recipes in Fortran 77 (Second Edition)
779             #ISBN 0-521-43064-X
780              
781 0           $grid_HR=$self->{'grid_HR'};
782              
783             #Using f instead of y in eq. 3.6.3
784              
785 0           $f1=$grid_HR->{$ykey1}->{$xkey1};
786 0           $f2=$grid_HR->{$ykey1}->{$xkey2};
787 0           $f3=$grid_HR->{$ykey2}->{$xkey2};
788 0           $f4=$grid_HR->{$ykey2}->{$xkey1};
789              
790 0 0         if ($xkey1 > $x){
791 0           $x_delta_from_xkey1=(180-$xkey1)+$x;
792 0           $delta_xkey=(180-$xkey1)+$xkey2;
793             }
794             else {
795 0           $x_delta_from_xkey1=$x-$xkey1;
796 0           $delta_xkey=$xkey2-$xkey1;
797             }#if/else
798              
799 0           $t=$x_delta_from_xkey1/$delta_xkey;
800              
801 0 0         if ($ykey1 == $ykey2){
802             #deal with infinity problem by just interpolating x values.
803 0           $f_interpolated=$x_delta_from_xkey1*($f1-$f2)/$delta_xkey + $f1;
804 0           return ($f_interpolated,undef);
805             }
806             else {
807 0           $y_delta_from_ykey1=$y-$ykey1;
808 0           $delta_ykey=$ykey2-$ykey1;
809             }#if/else
810              
811 0           $u=$y_delta_from_ykey1/$delta_ykey;
812              
813 0           $f_interpolated=(1-$t)*(1-$u)*$f1+$t*(1-$u)*$f2+$t*$u*$f3+(1-$t)*$u*$f4;
814              
815 0           return ($f_interpolated,undef);
816              
817             }#radius_function
818             #-------------------------------------------------------------------------------
819             sub _position_to_xy {
820 0     0     my $self=shift;
821 0           my $position_AR=shift;
822              
823 0           my ($lat, $lat_dir, $long, $long_dir, $msg, $x, $y)=undef;
824              
825             #Check the argument for problems.
826 0           ($lat,$lat_dir,$long,$long_dir)=@{$position_AR};
  0            
827 0 0 0       unless (
      0        
      0        
      0        
      0        
      0        
      0        
828             ($lat =~ m!^\d+(\.\d*)?$!) and
829             ($long =~ m!^\d+(\.\d*)?$!) and
830             ($lat_dir =~ m!^[NS]$!) and
831             ($long_dir =~ m!^[WE]$!) and
832             (($lat <= 90) and ($lat >= 0)) and
833             (($long <= 180) and ($long >= 0))
834             ){
835 0           $msg="Bad arguments passed to radius_function!";
836 0           carp $msg,"\n";
837 0           return (undef,$msg);
838             }#unless
839            
840             #Translate longitude and latitude into x,y values.
841 0 0         if ($lat_dir eq 'N'){
842 0           $y=$lat;
843             }
844             else {
845 0           $y=-$lat;
846             }#if/else
847            
848 0 0         if ($long_dir eq 'E'){
849 0           $x=$long;
850             }
851             else {
852 0           $x=-$long;
853             }#if/else
854              
855 0           return ([$x,$y],undef);
856              
857             }#_position_to_xy
858             #-------------------------------------------------------------------------------
859             sub _find_grid_square {
860 0     0     my $self=shift;
861 0           my $x=shift;
862 0           my $y=shift;
863            
864 0           my ($xval, $yval, $xkey1, $xkey2, $ykey1, $ykey2)=undef;
865 0           my ($xtics, $ytics, $i, $grid_HR)=undef;
866 0           my @ykeys=();
867 0           my @sorted_ykeys=();
868 0           my @xkeys=();
869 0           my @sorted_xkeys=();
870            
871 0           $grid_HR=$self->{'grid_HR'};
872              
873 0           @ykeys=keys %{$grid_HR};
  0            
874 0           @sorted_ykeys = sort {$a<=>$b} @ykeys;
  0            
875              
876 0           $ytics=scalar(@sorted_ykeys);
877              
878 0           for ($i=0; $i <= $ytics; $i++){
879 0           $yval=$sorted_ykeys[$i];
880 0 0 0       if (
    0 0        
      0        
881             ( ($i == $ytics-1) and ($yval <= $y) ) or
882             ( ($i == 0) and ($yval > $y) )
883             ){
884 0           $ykey1=$sorted_ykeys[$i];
885 0           $ykey2=$sorted_ykeys[$i];
886 0           last;
887             }
888             elsif ($yval <= $y){
889 0           $ykey1=$yval;
890 0           next;
891             }
892             else {
893 0           $ykey2=$yval;
894 0           last;
895             }#if/elsif/else
896             }#for
897              
898 0           @xkeys=keys %{$grid_HR->{$ykey1}};
  0            
899 0           @sorted_xkeys = sort {$a<=>$b} @xkeys;
  0            
900              
901              
902 0           $xtics=scalar(@sorted_xkeys);
903              
904 0           for ($i=0; $i <= $xtics; $i++){
905 0           $xval=$sorted_xkeys[$i];
906 0 0 0       if (
    0 0        
      0        
907             ( ($i == $xtics-1) and ($xval <= $x) ) or
908             ( ($i == 0) and ($xval > $x) )
909             ){
910 0           $xkey1=$sorted_xkeys[$xtics-1];
911 0           $xkey2=$sorted_xkeys[0];
912 0           last;
913             }
914             elsif ($xval <= $x){
915 0           $xkey1=$xval;
916 0           next;
917             }
918             else {
919 0           $xkey2=$xval;
920 0           last;
921             }#if/elsif/else
922             }#for
923              
924 0           return ($xkey1,$xkey2,$ykey1,$ykey2);
925              
926             }#_find_grid_square
927             #-------------------------------------------------------
928             1;
929              
930             __END__