File Coverage

blib/lib/Geo/ReadGRIB/PlaceIterator.pm
Criterion Covered Total %
statement 92 100 92.0
branch 17 26 65.3
condition 2 3 66.6
subroutine 13 15 86.6
pod 8 8 100.0
total 132 152 86.8


line stmt bran cond sub pod time code
1             #
2             #===============================================================================
3             #
4             # FILE: PlaceIterator.pm
5             #
6             # DESCRIPTION: A Geo::ReadGRIB::PlaceIterator object contains a collection of
7             # Geo::ReadGRIB data for a regular area and has methods to return
8             # Geo::ReadGRIB::Place in sorted sequence of locations
9             #
10             # FILES: ---
11             # BUGS: ---
12             # NOTES: ---
13             # AUTHOR: Frank Lyon Cox (Dr),
14             # COMPANY: Practial Wizardry
15             # VERSION: 1.0
16             # CREATED: 2/2/2009 12:15:57 PM Pacific Standard Time
17             # REVISION: ---
18             #===============================================================================
19              
20             package Geo::ReadGRIB::PlaceIterator;
21              
22 12     12   71 use strict;
  12         25  
  12         451  
23 12     12   73 use warnings;
  12         113  
  12         527  
24 12     12   7258 use Geo::ReadGRIB::Place;
  12         31  
  12         15201  
25              
26             our $VERSION = 1.0;
27              
28             #--------------------------------------------------------------------------
29             # new( )
30             #--------------------------------------------------------------------------
31             sub new {
32 14     14 1 179 my $class = shift;
33              
34 14         40 my $self = {};
35 14         76 bless $self, $class;
36 14         95 $self->_init;
37 14         198 return $self;
38             }
39              
40              
41             #--------------------------------------------------------------------------
42             # _init( )
43             #--------------------------------------------------------------------------
44             sub _init {
45 14     14   32 my $self = shift;
46              
47 14         253 $self->{shifted_west_by} = 0;
48 14         129 $self->isSorted( undef );
49 14         34 $self->{place_index} = 0;
50 14         51 $self->{place_sorted} = [];
51 14         65 $self->{x_y} = [];
52 14         44 $self->{count_of_places} = 0;
53 14         38 return;
54             }
55              
56             #--------------------------------------------------------------------------
57             # first( )
58             #--------------------------------------------------------------------------
59             sub first {
60 6     6 1 15 my $self = shift;
61 6 100       18 $self->_indexData() if not $self->isSorted;
62 6         133 $self->_setIndex( 0 );
63 6         14 return;
64             }
65              
66              
67             #--------------------------------------------------------------------------
68             # next( )
69             #--------------------------------------------------------------------------
70             sub next {
71 609     609 1 2153 my $self = shift;
72 609 50       1030 $self->_indexData() if not $self->isSorted;
73 609 50       1112 if ( $self->_setIndex == $self->{count_of_places} ) {
74 0         0 return;
75             }
76 609         1164 return $self->_setIndex('+');
77             }
78              
79             #--------------------------------------------------------------------------
80             # current( )
81             #
82             # returns a Geo::ReadGRIB::Place object
83             #--------------------------------------------------------------------------
84             sub current {
85 605     605 1 171376 my $self = shift;
86              
87 605 100       1005 $self->_indexData() if not $self->isSorted;
88              
89 605         1073 my $index = $self->_setIndex;
90              
91 605         1746 my $p = Geo::ReadGRIB::Place->new;
92              
93 605         1985 $p->thisTime( $self->{place_sorted}->[ $index ]->[0] );
94 605         1663 $p->lat( $self->{place_sorted}->[ $index ]->[1] );
95 605         1662 $p->long( $self->{place_sorted}->[ $index ]->[2] );
96              
97 605 100       1299 if ( not defined $p->thisTime ) {
98 1         5 return;
99             }
100              
101 604         733 for my $type ( keys %{ $self->{data}->{$p->thisTime}->{$p->lat}->{$p->long} } ) {
  604         1448  
102 604         1661 $p->types( $type );
103 604         1660 $p->data( $type, $self->{data}->{$p->thisTime}->{$p->lat}->{$p->long}->{$type} );
104             }
105              
106 604         1786 return $p;
107             }
108              
109              
110             #--------------------------------------------------------------------------
111             # numLong( )
112             #--------------------------------------------------------------------------
113             sub numLong {
114 0     0 1 0 my $self = shift;
115 0 0       0 $self->_indexData() if not $self->isSorted;
116 0         0 return $self->{x_y}->[0];
117             }
118              
119             #--------------------------------------------------------------------------
120             # numLat( )
121             #--------------------------------------------------------------------------
122             sub numLat {
123 0     0 1 0 my $self = shift;
124 0 0       0 $self->_indexData() if not $self->isSorted;
125 0         0 return $self->{x_y}->[1];
126             }
127              
128             #--------------------------------------------------------------------------
129             # _setIndex( )
130             #--------------------------------------------------------------------------
131             sub _setIndex {
132 1829     1829   2072 my $self = shift;
133 1829         2258 my $index = shift;
134              
135 1829 100       3579 if ( defined $index ) {
136 615 100       1067 if ( $index eq '+' ) {
137 609         1068 $self->{place_index} = $self->{place_index} + 1;
138             }
139             else {
140 6         20 $self->{place_index} = $index;
141             }
142             }
143              
144 1829 50       4242 if ( $self->{place_index} > $self->{count_of_places} ) {
145 0         0 return;
146             }
147              
148 1829         4088 return $self->{place_index};
149             }
150              
151             #--------------------------------------------------------------------------
152             # isSorted( )
153             #--------------------------------------------------------------------------
154             sub isSorted {
155 1240     1240 1 1394 my $self = shift;
156 1240         1383 my $bool = shift;
157 1240 100       2147 if ( $bool ) {
158 4         17 $self->{is_sorted} = 1;
159             }
160 1240         3262 return $self->{is_sorted};
161             }
162              
163             #--------------------------------------------------------------------------
164             # _indexData( )
165             #
166             # Inspect the data section and prepare a sorted list of
167             # [time, lat, long]
168             #
169             # -- we also count the number of lats and longs
170             #
171             # Object data is updated
172             #--------------------------------------------------------------------------
173             sub _indexData {
174 4     4   11 my $self = shift;
175              
176             # Inspect the data section and prepare a sorted list of
177             # [time, lat, long] and an array of times
178             # -- we also count the number of lats and longs
179              
180 4         12 my ( @tm, $these, $dataType );
181              
182 4         10 my ( $thisTime ) = keys %{ $self->{data} };
  4         18  
183              
184 4         7 my ( $laC, $loC );
185 4         12 while ( my ( $time, $laf ) = each %{ $self->{data} } ) {
  8         45  
186 4         10 $laC = 0;
187 4         27 while ( my ( $la, $lof ) = each %$laf ) {
188 609         1723 while ( my ( $lo, $dtf ) = each %$lof ) {
189 621         578 $loC++;
190 621         1504 push @$these, [ $time, $la, $lo ];
191 621         10933 ($dataType) = each %$dtf;
192             }
193             }
194             }
195              
196 4         21 $self->{x_y} = [ $loC / scalar keys %{ $self->{data}->{$thisTime} },
  4         27  
197 4         12 scalar keys %{ $self->{data}->{$thisTime} } ];
198              
199 4         34 $self->{place_sorted} = $self->_sortThese($these);
200 4         16 $self->{count_of_places} = $loC;
201 4         21 $self->isSorted( 1 );
202 4         35 $self->first;
203              
204 4         27 return;
205             }
206              
207             #--------------------------------------------------------------------------
208             # _sortThese( )
209             #--------------------------------------------------------------------------
210             sub _sortThese {
211 4     4   13 my $self = shift;
212 4         16 my $coArray = shift;
213              
214             # sort by lat and then by long
215 4223 50 66     17618 my @psort = sort {
216 4         86 $a->[0] <=> $b->[0] || $b->[1] <=> $a->[1] || $a->[2] <=> $b->[2]
217             } @$coArray;
218              
219 4         32 return \@psort;
220             }
221              
222             #--------------------------------------------------------------------------
223             # addData( time, la, lo, type, data )
224             #
225             # Add a unit of data to internal structure
226             #--------------------------------------------------------------------------
227             sub addData {
228 1091     1091 1 1729 my $self = shift;
229 1091         1391 my $time = shift;
230 1091         1351 my $la = shift;
231 1091         1192 my $lo = shift;
232 1091         2371 my $type = shift;
233 1091         1677 my $data = shift;
234              
235 1091 50       11126 $self->{data}->{$time}->{$la}->{$lo}->{$type} = $data if defined $data;
236 1091         1791 $self->{is_sorted} = undef;
237              
238 1091         7167 return $self->{data};
239             }
240              
241              
242              
243             1;
244              
245              
246              
247             #---------------------------------------------------------------------------
248             # Module Documentation
249             #---------------------------------------------------------------------------
250              
251             =head1 NAME
252              
253             Geo::ReadGRIB::PlaceIterator - Provides methods to iterate through GRIB data
254             in geographic order and to return Geo::ReadGRIB::Place objects for each location.
255              
256             =head1 VERSION
257              
258             This documentation refers to Geo::ReadGRIB::PlaceIterator version 1.0
259              
260             =head1 SYNOPSIS
261              
262             use Geo::ReadGRIB;
263              
264             $w = new Geo::ReadGRIB "grib-file";
265             $w->getFullCatalog;
266              
267             print $w->show,"\n";
268            
269             $plit = $w->extractLaLo(data_type, lat1, long1, lat2, long2, time);
270             die $w->getError if $w->getError;
271              
272             # $plit is a Geo::ReadGRIB::PlaceIterator
273              
274             for $y ( 0 .. $plit->numLat -1 ) {
275             for $x ( 0 .. $plit->numLong -1 ) {
276            
277             my $place = $plit->current;
278            
279             # $place is a Geo::ReadGRIB::Place object
280              
281             $time = $place->thisTime;
282             $latitude = $place->lat;
283             $longitude = $place->long;
284             $data_types = $place->types; # an array ref of type names
285             $data = $place->data(data_type);
286              
287             # process data for $x, $y
288              
289             $plit->next;
290             }
291             }
292              
293              
294             =head1 DESCRIPTION
295              
296             A PlaceIterator objects let you iterate through places.
297              
298             Objects of this class are returned by the extractLaLo() or extract() method of a
299             Geo::ReadGRIB object. It contains data for one or more data types at one or more
300             times for the area extracted. The locations are sorted first by time
301             then latitude and then by longitude. Methods are provided for sequential access
302             to this data.
303              
304             The first() method sets the iterator index to the most northwest (lat, long)
305             pair. The current() method returns a Place object for the current location.
306             The next() method advances the current location one place in rows from west to
307             east and north to south starting in the northwest corner and ending in the
308             southeast. After the last item in the southeast corner of the extracted region,
309             another call to next() returns B.
310              
311             The convenience methods numLat() and numLong() return the number of latitude and
312             longitude points respectively. This is handy to, for example, provide the x, y
313             dimensions for a GD::Image new() method.
314              
315             =head1 METHODS
316              
317             =over 4
318              
319             =item $object->new;
320              
321             =item $object->first;
322              
323             =item $object->next;
324              
325             =item $place = $object->current;
326              
327             =item $y = $object->numLat;
328              
329             =item $y = $object->numLong;
330              
331             =item $y = $object->addData;
332              
333             =item $y = $object->isSorted;
334              
335             =back
336              
337             =head1 BUGS AND LIMITATIONS
338              
339             There are no known bugs in this module. Please report problems through
340              
341             http://rt.cpan.org
342              
343             or contact Frank Cox, Patches are welcome.
344              
345             =head1 AUTHOR
346              
347             Frank Cox, Efrank.l.cox@gmail.comE
348              
349              
350             =head1 LICENCE AND COPYRIGHT
351              
352             2009 by Frank Cox
353              
354             This library is free software; you can redistribute it and/or modify
355             it under the same terms as Perl itself, either Perl version 5.8.4 or,
356             at your option, any later version of Perl 5 you may have available.
357              
358              
359             =cut
360