File Coverage

blib/lib/Geo/Shapelib.pm
Criterion Covered Total %
statement 311 468 66.4
branch 125 216 57.8
condition 25 65 38.4
subroutine 25 28 89.2
pod 10 19 52.6
total 496 796 62.3


line stmt bran cond sub pod time code
1             package Geo::Shapelib;
2              
3 1     1   740 use strict;
  1         2  
  1         29  
4 1     1   5 use Carp;
  1         2  
  1         86  
5 1     1   771 use Tree::R;
  1         19280  
  1         54  
6 1     1   9 use vars qw($VERSION @ISA @EXPORT %EXPORT_TAGS @EXPORT_OK $AUTOLOAD);
  1         2  
  1         93  
7 1     1   6 use vars qw(%ShapeTypes %PartTypes);
  1         2  
  1         47  
8              
9             require Exporter;
10             require DynaLoader;
11 1     1   5 use AutoLoader 'AUTOLOAD';
  1         2  
  1         11  
12              
13             @ISA = qw(Exporter DynaLoader);
14              
15             $VERSION = '0.20';
16              
17             bootstrap Geo::Shapelib $VERSION;
18              
19             # Preloaded methods go here.
20              
21             # Autoload methods go after =cut, and are processed by the autosplit program.
22              
23             # Page 4 of the ESRI Shapefile Technical Description, July 1998
24             %ShapeTypes = (
25             1 => 'Point',
26             3 => 'PolyLine',
27             5 => 'Polygon',
28             8 => 'Multipoint',
29             11 => 'PointZ',
30             13 => 'PolyLineZ',
31             15 => 'PolygonZ',
32             18 => 'MultipointZ',
33             21 => 'PointM',
34             23 => 'PolyLineM',
35             25 => 'PolygonM',
36             28 => 'MultipointM',
37             31 => 'Multipatch',
38             );
39              
40             # Page 21 of the ESRI Shapefile Technical Description, July 1998
41             %PartTypes = (
42             0 => 'TriStrip',
43             1 => 'TriFan',
44             2 => 'OuterRing',
45             3 => 'InnerRing',
46             4 => 'FirstRing',
47             5 => 'Ring',
48             );
49              
50             # Create the SUBROUTINES FOR ShapeTypes and PartTypes
51             # We could prefix these with SHPT_ and SHPP_ respectively
52             {
53             my %typeval = (map(uc,reverse(%ShapeTypes)),map(uc,reverse(%PartTypes)));
54              
55             for my $datum (keys %typeval) {
56 1     1   142 no strict "refs"; # to register new methods in package
  1         2  
  1         6047  
57 2     2   495 *$datum = sub { $typeval{$datum}; }
58             }
59             }
60              
61             # Add Extended Exports
62             %EXPORT_TAGS = ('constants' => [ map(uc,values(%ShapeTypes)),
63             map(uc,values(%PartTypes))
64             ],
65             'types' =>[ qw(%ShapeTypes %PartTypes) ] );
66             $EXPORT_TAGS{all}=[ @{ $EXPORT_TAGS{constants} },
67             @{ $EXPORT_TAGS{types} } ];
68              
69             @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
70              
71             @EXPORT = qw();
72              
73              
74             =pod
75              
76             =head1 NAME
77              
78             Geo::Shapelib - Perl extension for reading and writing shapefiles as defined by ESRI(r)
79              
80             =head1 SYNOPSIS
81              
82             use Geo::Shapelib qw/:all/;
83              
84             or
85              
86             use Geo::Shapelib qw/:all/;
87              
88             my $shapefile = new Geo::Shapelib {
89             Name => 'stations',
90             Shapetype => POINT,
91             FieldNames => ['Name','Code','Founded'];
92             FieldTypes => ['String:50','String:10','Integer:8'];
93             };
94              
95             while () {
96             chomp;
97             my($station,$code,$founded,$x,$y) = split /\|/;
98             push @{$shapefile->{Shapes}},{ Vertices => [[$x,$y,0,0]] };
99             push @{$shapefile->{ShapeRecords}}, [$station,$code,$founded];
100             }
101              
102             $shapefile->save();
103              
104              
105             =head1 DESCRIPTION
106              
107             This is a library for reading, creating, and writing shapefiles as
108             defined by ESRI(r) using Perl. The Perl code uses Frank Warmerdam's
109             Shapefile C Library (http://shapelib.maptools.org/). The library
110             is included in this distribution.
111              
112             Currently no methods exist for populating an empty Shape. You need
113             to do it in your own code. This is how:
114              
115             First you include the module into your code. If you want to define the
116             shape type using its name, import all:
117              
118             use Geo::Shapelib qw/:all/;
119              
120             Create the shapefile object and specify its name and type:
121              
122             $shapefile = new Geo::Shapelib {
123             Name => ,
124             Shapetype => ,
125             FieldNames => ,
126             FieldTypes =>
127             }
128              
129             The name (filename, may include path) of the shapefile, the extension
130             is not used (it is stripped in the save method).
131              
132             The shape type is an integer. This module defines shape type names as
133             constants (see below).
134              
135             The field name list is an array reference of the names of the data
136             items assigned to each shape.
137              
138             The field type list is an array reference of the types of the data
139             items. Field type is either 'Integer', 'Double', or 'String'.
140              
141             The types may have optional 'width' and 'decimals' fields defined,
142             like this:
143              
144             'Integer[:width]' defaults: width = 10
145             'Double[:width[:decimals]]' defaults: width = 10, decimals = 4
146             'String[:width]' defaults: width = 255
147              
148             There are some other attributes which can be defined in the
149             constructor (see below), they are rarely needed. The shape object will
150             need or get a couple of other attributes as well. They should be
151             treated as private:
152              
153             $shapefile->{NShapes} is the number of shapes in your
154             object. Shapefile is a collection of shapes. This is usually
155             automatically deduced from the Shapes array when needed.
156              
157             $shapefile->{MinBounds} is set by shapelib C functions.
158              
159             $shapefile->{MaxBounds} is set by shapelib C functions.
160              
161             Create the shapes and respective shape records and put them into the
162             shape:
163              
164             for many times {
165             make $s, a new shape as a reference to a hash
166             push @{$shapefile->{Shapes}}, $s;
167             make $r, a shape record as a reference to an array
168             push @{$shapefile->{ShapeRecords}}, $r;
169             }
170              
171             how to create $s? It is a (reference to an) hash.
172              
173             set:
174              
175             $s->{Vertices} this is a reference to an array of arrays of four
176             values, one for each vertex: x, y, z, and m of the vertex. There
177             should be at least one vertex in $s. Point has only one vertex.
178              
179             $s->{Parts}:
180              
181             $s->{Parts} is not needed in simple cases. $s->{Parts} is a
182             reference to an array (a) of arrays (b). There is one (b) array
183             for each part. In a (b) array the first value is an index to the
184             Vertices array denoting the first vertex of that part. The second
185             value is the type of the part (NOTE: not the type of the
186             shape). The type is 5 (Ring) unless the shape is of type
187             Multipatch. The third value is set as the type of the part as a
188             string when reading from a file but the save method requires only
189             the first two values.
190              
191             The index of the last vertex of any part is implicitly the index
192             of the next part minus one or the index of the last vertex.
193              
194             forget these:
195              
196             $s->{ShapeId} may be left undefined. The save method sets it to
197             the index in the Shapes array. Instead create and use an id field
198             in the record.
199              
200             $s->{NParts} and $s->{NVertices} may be set but that is usually
201             not necessary since they are calculated in the save method. You
202             only need to set these if you want to save less parts or vertices
203             than there actually are in the Parts or Vertices arrays.
204              
205             $s->{SHPType} is the type of the shape and it is automatically set
206             to $shape->{Shapetype} unless defined (which you should not do)
207              
208             The shape record is simply an array reference, for example:
209              
210             $r = [item1,item2,item3,...];
211              
212             That's all. Then save it and start your shapefile viewer to look at
213             the result.
214              
215             =head1 EXPORT
216              
217             None by default. The following export tags are defined.
218              
219             =over 8
220              
221             =item :constants
222              
223             This exports constant functions for the individual types of shapefile
224             Types and shapefile part types. They all return scalar (integer)
225             values. The shapetype functions: POINT, ARC, POLYGON, MULTIPOINT,
226             POINTZ, ARCZ, POLYGONZ, MULTIPOINTZ, POINTM, ARCM, POLYGONM,
227             MULTIPOINTM, MULTIPATCH are defined. The shapefile part
228             types: TRISTRIP, TRIFAN, OUTERRING, INNERRING, FIRSTRING, RING are
229             defined.
230              
231             =item :types
232              
233             Exports two hashs: %ShapeTypes, %PartTypes which map the shapelib type
234             integers to string values.
235              
236             =item :all
237              
238             All possible exports are included.
239              
240              
241             =back
242              
243             =head1 CONSTRUCTORS
244              
245             This one reads in an existing shapefile:
246              
247             $shapefile = new Geo::Shapelib "myshapefile", {};
248              
249             This one creates a new, blank Perl shapefile object:
250              
251             $shapefile = new Geo::Shapelib {};
252              
253             {} is optional in both cases, an example (note the curly braces):
254              
255             $shapefile = new Geo::Shapelib {
256             Name => $shapefile,
257             Shapetype => POINT,
258             FieldNames => ['Name','Code','Founded'],
259             FieldTypes => ['String:50','String:10','Integer:8']
260             };
261              
262             $shapefile = new Geo::Shapelib "myshapefile" {
263             Rtree => 1
264             };
265              
266             =item Options:
267              
268             Like:
269              
270             A shapefile from which to copy ShapeType, FieldNames, and FieldTypes.
271              
272             Name:
273              
274             Default is "shapefile". The filename (if given) becomes the name
275             for the shapefile unless overridden by this.
276              
277             Shapetype:
278              
279             Default "POINT". The type of the shapes. (All non-null shapes in a
280             shapefile are required to be of the same shape type.)
281              
282             FieldNames:
283              
284             Default is [].
285              
286             FieldTypes:
287              
288             Default is [].
289              
290             ForceStrings:
291              
292             Default is 0. If 1, sets all FieldTypes to string, may be useful
293             if values are very large ints
294              
295             Rtree:
296              
297             Default is 0. If 1, creates an R-tree of the shapes into an
298             element Rtree. (Requires LoadAll.)
299              
300              
301             When a shapefile is read from files they end up in a bit different
302             kind of data structure than what is expected by the save method for
303             example and what is described above. These flags enable the
304             conversion, they are not normally needed.
305              
306             CombineVertices:
307              
308             Default is 1. CombineVertices is experimental. The default
309             behavior is to put all vertices into the Vertices array and part
310             indexes into the Parts array. If CombineVertices is set to 0 there
311             is no Vertices array and all data goes into the Parts. Currently
312             setting CombineVertices to 0 breaks saving of shapefiles.
313              
314             UnhashFields:
315              
316             Default is 1. Makes $self's attributes FieldNames, FieldTypes refs
317             to lists, and ShapeRecords a list of lists.
318              
319              
320             The default is to load all data into Perl variables in the
321             constructor. With these options the data can be left into the files
322             to be loaded on-demand.
323              
324             Load:
325              
326             Default is 1. If 0, has the same effect as LoadRecords=>0 and
327             LoadAll=>0.
328              
329             LoadRecords:
330              
331             Default is 1. Reads shape records into $self->{ShapeRecords}
332             automatically in the constructor using the
333             get_record($shape_index) method
334              
335             LoadAll:
336              
337             Default is 1. Reads shapes (the geometry data) into
338             $self->{Shapes} automatically in the constructor using the
339             get_shape($shape_index) method
340              
341              
342             =cut
343              
344             sub new {
345 11     11 0 4755 my $package = shift;
346 11         17 my $filename;
347 11         23 my $options = shift;
348 11 100       35 unless (ref $options) {
349 8         13 $filename = $options;
350 8         14 $options = shift;
351             }
352 11 50 66     72 croak "usage: new Geo::Shapelib , {};" if (defined $options and not ref $options);
353            
354 11         27 my $self = {};
355 11   33     70 bless $self => (ref($package) or $package);
356            
357 11 100       49 $self->{Name} = $filename if $filename;
358            
359 11         124 my %defaults = ( Like => 0,
360             Name => 'shapefile',
361             Shapetype => 'POINT',
362             FieldNames => [],
363             FieldTypes => [],
364             CombineVertices => 1,
365             UnhashFields => 1,
366             Load => 1,
367             LoadRecords => 1,
368             LoadAll => 1,
369             ForceStrings => 0,
370             Rtree => 0 );
371            
372 11         60 for (keys %defaults) {
373 132 100       280 next if defined $self->{$_};
374 125         226 $self->{$_} = $defaults{$_};
375             }
376            
377 11 100 66     66 if (defined $options and ref $options) {
378 9         30 for (keys %$options) {
379 14 50       44 croak "unknown constructor option for Geo::Shapelib: $_" unless defined $defaults{$_}
380             }
381 9         32 for (keys %defaults) {
382 108 100       255 next unless defined $options->{$_};
383 14         29 $self->{$_} = $options->{$_};
384             }
385 9 100       104 if ($self->{Like}) {
386 1         3 for ('Shapetype','FieldNames','FieldTypes') {
387 3         8 $self->{$_} = $options->{Like}->{$_};
388             }
389             }
390             }
391            
392 11 100       40 return $self unless $filename;
393            
394             # print "\n\n";
395             # for (keys %$self) {
396             # print "$_ $self->{$_}\n";
397             # }
398            
399             # Read the specified file
400            
401             # Get 'NShapes', 'FieldTypes' and 'ShapeRecords' from the dbf
402 7         371 my $dbf_handle = DBFOpen($self->{Name}, 'rb');
403 7 50       23 unless ($dbf_handle) {
404 0         0 croak("DBFOpen $self->{Name} failed");
405 0         0 return undef;
406             }
407 7         32 $self->{NShapes} = DBFGetRecordCount($dbf_handle);
408 7         22 $self->{FieldNames} = '';
409 7         110 $self->{FieldTypes} = ReadDataModel($dbf_handle, $self->{ForceStrings});
410              
411 7 100 100     40 if ($self->{Load} and $self->{LoadRecords}) {
412 3         13533 $self->{ShapeRecords} = ReadData($dbf_handle, $self->{ForceStrings});
413             }
414              
415 7         199 DBFClose($dbf_handle);
416             #return undef unless $dbf; # Here, not above, so the dbf always gets closed.
417            
418             # Get 'Shapetype', 'MinBounds', and 'MaxBounds'
419 7         1625 $self->{SHPHandle} = SHPOpen($self->{Name}, 'rb');
420 7 50       25 unless ($self->{SHPHandle}) {
421 0         0 carp("SHPOpen $self->{Name} failed!");
422 0         0 return undef;
423             }
424 7         69 my $info = SHPGetInfo($self->{SHPHandle}); # DESTROY closes SHPHandle
425 7 50       21 unless ($info) {
426 0         0 carp("SHPGetInfo failed!");
427 0         0 return undef;
428             }
429 7         57 @$self{keys %$info} = values %$info;
430 7         37 $self->{ShapetypeString} = $ShapeTypes{ $self->{Shapetype} };
431            
432 7 100       22 if ($self->{UnhashFields}) {
433 5         40 ($self->{FieldNames}, $self->{FieldTypes}) = data_model($self);
434 5 100 100     52 if ($self->{Load} and $self->{LoadRecords}) {
435 2         6 for my $i (0..$self->{NShapes}-1) {
436 10         25 $self->{ShapeRecords}->[$i] = get_record_arrayref($self, $i, undef, 1);
437             }
438             }
439             }
440            
441 7 100 66     40 if ($self->{Load} and $self->{LoadAll}) {
442 5         23 for (my $i = 0; $i < $self->{NShapes}; $i++) {
443 8575         14128 my $shape = get_shape($self, $i, 1);
444 8575         9118 push @{$self->{Shapes}}, $shape;
  8575         25996  
445             }
446             }
447            
448 7 100       28 $self->Rtree() if $self->{Rtree};
449            
450 7         157 return $self;
451             }
452              
453             =pod
454              
455             =head1 METHODS
456              
457             =head2 data_model
458              
459             Returns data model converted into two arrays.
460              
461             If in a constructor a filename is given, then the data model is read
462             from the dbf file and stored as a hashref in the attribute FieldTypes.
463             This converts the hashref into two arrays: FieldNames and respective
464             FieldTypes. These arrayrefs are stored in attributes of those names if
465             UnhashFields is TRUE.
466              
467             =cut
468              
469             sub data_model {
470 7     7 1 14 my $self = shift;
471 7         9 my @FieldNames;
472             my @FieldTypes;
473 7         14 while (my($name,$type) = each %{$self->{FieldTypes}}) {
  32         121  
474 25         40 push @FieldNames,$name;
475 25         52 push @FieldTypes,$type;
476             }
477 7         33 return (\@FieldNames,\@FieldTypes);
478             }
479              
480             =pod
481              
482             =head2 get_shape(shape_index, from_file)
483              
484             Returns a shape nr. shape_index+1 (first index is 0). The shape is
485             read from a file even if array Shapes exists if from_file is TRUE.
486              
487             Option CombineVertices is in operation here.
488              
489             Use this method to get a shape unless you know what you are doing.
490              
491             =cut
492              
493             sub get_shape {
494 22879     22879 1 41969 my ($self, $i, $from_file) = @_;
495 22879 100 100     87865 if (!$from_file and $self->{Shapes}) {
496              
497 8594         25925 return $self->{Shapes}->[$i];
498              
499             } else {
500              
501 14285 50       213633 my $shape = SHPReadObject($self->{SHPHandle}, $i, $self->{CombineVertices}?1:0) or return undef;
    50          
502              
503             # $shape->{ShapeRecords} = $self->{ShapeRecords}[$i];
504              
505 14285 50       38634 if($self->{CombineVertices}) {
506 14285         15029 for my $part (@{$shape->{Parts}}) {
  14285         29689  
507 2         12 $part->[2] = $PartTypes{ $part->[1] };
508             }
509             }
510 14285         28633 return $shape;
511              
512             }
513             }
514              
515             =pod
516              
517             =head2 get_record(shape_index, from_file)
518              
519             Returns the record which belongs to shape nr. shape_index+1 (first
520             index is 0). The record is read from a file even if array ShapeRecords
521             exists if from_file is TRUE.
522              
523             =cut
524              
525             sub get_record {
526 14306     14306 1 34335 my ($self, $i, $from_file) = @_;
527 14306 100 100     57521 if (!$from_file and $self->{ShapeRecords}) {
528              
529 2875         6262 return $self->{ShapeRecords}->[$i];
530              
531             } else {
532              
533 11431         542796 my $dbf_handle = DBFOpen($self->{Name}, 'rb');
534 11431 50       28616 unless ($dbf_handle) {
535 0         0 croak("DBFOpen $self->{Name} failed");
536 0         0 return undef;
537             }
538 11431         159457 my $rec = ReadRecord($dbf_handle, $self->{ForceStrings}, $i);
539 11431         280253 DBFClose($dbf_handle);
540 11431         52153 return $rec;
541              
542             }
543             }
544              
545             =pod
546              
547             =head2 get_record_arrayref(shape_index, FieldNames, from_file)
548              
549             Returns the record which belongs to shape nr. shape_index+1 (first
550             index is 0) as an arrayref. The parameter FieldNames may be undef but
551             if defined, it is used as the array according to which the record
552             array is sorted. This in case the ShapeRecords contains hashrefs. The
553             record is read from the file even if array ShapeRecords exists if
554             from_file is TRUE.
555              
556             Use this method to get a record of a shape unless you know what you
557             are doing.
558              
559             =cut
560              
561             sub get_record_arrayref {
562 19     19 1 32 my ($self, $i, $FieldNames, $from_file) = @_;
563 19         30 my $rec = get_record($self, $i, $from_file);
564 19 100       54 if (ref $rec eq 'HASH') {
565 10         12 my @rec;
566 10 50       33 $FieldNames = $self->{FieldNames} unless defined $FieldNames;
567 10         19 for (@$FieldNames) {
568 29         64 push @rec,$rec->{$_};
569             }
570 10         54 return \@rec;
571             }
572 9         13 return $rec;
573             }
574              
575             =pod
576              
577             =head2 get_record_hashref(shape_index, from_file)
578              
579             Returns the record which belongs to shape nr. shape_index+1 (first
580             index is 0) as a hashref. The record is read from the file even if
581             array ShapeRecords exists if from_file is TRUE. If records are in the
582             array ShapeRecords as a list of lists, then FieldNames _must_ contain
583             the names of the fields.
584              
585             Use this method to get a record of a shape unless you know what you
586             are doing.
587              
588             =cut
589              
590             sub get_record_hashref {
591 2     2 1 438 my ($self, $i, $from_file) = @_;
592 2         7 my $rec = get_record($self, $i, $from_file);
593 2 100       9 if (ref $rec eq 'ARRAY') {
594 1         1 my %rec;
595 1         2 for my $i (0..$#{$self->{FieldNames}}) {
  1         4  
596 3         8 $rec{$self->{FieldNames}->[$i]} = $rec->[$i];
597             }
598 1         5 return \%rec;
599             }
600 1         4 return $rec;
601             }
602              
603             =pod
604              
605             =head2 lengths(shape)
606              
607             Returns the lengths of the parts of the shape. This is lengths of the
608             parts of polyline or the length of the boundary of polygon. 2D and 3D
609             data is taken into account.
610              
611             =cut
612              
613             sub lengths {
614 1     1 1 7 my ($self, $shape) = @_;
615 1         2 my @l;
616 1 50       3 if ($shape->{NParts}) {
617            
618 0         0 my $pindex = 0;
619 0         0 my $pmax = $shape->{NParts};
620 0         0 while($pindex < $pmax) {
621            
622 0         0 my $l = 0;
623 0         0 my $prev = 0;
624              
625 0         0 my $part = $shape->{Parts}[$pindex];
626            
627 0 0       0 if($self->{CombineVertices}) {
628 0         0 my $vindex = $part->[0];
629 0         0 my $vmax = $shape->{Parts}[$pindex+1][0];
630 0 0       0 $vmax = $shape->{NVertices} unless defined $vmax;
631 0         0 while($vindex < $vmax) {
632              
633 0         0 my $vertex = $shape->{Vertices}[$vindex];
634 0 0       0 if ($prev) {
635 0         0 my $c2 = 0;
636 0 0       0 if ($self->{Shapetype} < 10) { # x,y
637 0         0 for (0..1) {
638 0         0 $c2 += ($vertex->[$_] - $prev->[$_])**2;
639             }
640             } else {
641 0         0 for (0..2) {
642 0         0 $c2 += ($vertex->[$_] - $prev->[$_])**2;
643             }
644             }
645 0         0 $l += sqrt($c2);
646             }
647 0         0 $prev = $vertex;
648              
649 0         0 $vindex++;
650             }
651             } else {
652 0         0 for my $vertex (@{$part->{Vertices}}) {
  0         0  
653              
654 0 0       0 if ($prev) {
655 0         0 my $c2 = 0;
656 0 0       0 if ($self->{Shapetype} < 10) { # x,y
657 0         0 for (0..1) {
658 0         0 $c2 += ($vertex->[$_] - $prev->[$_])**2;
659             }
660             } else {
661 0         0 for (0..2) {
662 0         0 $c2 += ($vertex->[$_] - $prev->[$_])**2;
663             }
664             }
665 0         0 $l += sqrt($c2);
666             }
667 0         0 $prev = $vertex;
668              
669             }
670             }
671            
672 0         0 push @l,$l;
673 0         0 $pindex++;
674             }
675            
676             } else {
677            
678 1         3 my $l = 0;
679 1         2 my $prev = 0;
680 1         2 for my $vertex (@{$shape->{Vertices}}) {
  1         4  
681            
682 2 100       5 if ($prev) {
683 1         2 my $c2 = 0;
684 1 50       5 if ($self->{Shapetype} < 10) { # x,y
685 1         3 for (0..1) {
686 2         7 $c2 += ($vertex->[$_] - $prev->[$_])**2;
687             }
688             } else {
689 0         0 for (0..2) {
690 0         0 $c2 += ($vertex->[$_] - $prev->[$_])**2;
691             }
692             }
693 1         4 $l += sqrt($c2);
694             }
695 2         6 $prev = $vertex;
696             }
697 1         3 push @l,$l;
698            
699             }
700            
701 1         5 return @l;
702             }
703              
704             =pod
705              
706             =head2 Rtree and editing the shapefile
707              
708             Building a R-tree for the shapes:
709              
710             $shapefile->Rtree();
711              
712             This is automatically done if Rtree-option is set when a shapefile is
713             loaded from files.
714              
715             You can then use methods like (there are not yet any wrappers for
716             these).
717              
718             my @shapes;
719             $shapefile->{Rtree}->query_point(@xy,\@shapes); # or
720             $shapefile->{Rtree}->query_completely_within_rect(@rect,\@shapes); # or
721             $shapefile->{Rtree}->query_partly_within_rect(@rect,\@shapes);
722              
723             To get a list of shapes (indexes to the shape array), which you can
724             feed for example to the select_vertices function.
725              
726             for my $shape (@shapes) {
727             my $vertices = $shapefile->select_vertices($shape,@rect);
728             my $n = @$vertices;
729             print "you selected $n vertices from shape $shape\n";
730             }
731              
732             The shapefile object remembers the selected vertices and calling the
733             function
734              
735             $shapefile->move_selected_vertices($dx,$dy);
736              
737             moves the vertices. The bboxes of the affected shapes, and the R-tree,
738             if one exists, are updated automatically. To clear all selections from
739             all shapes, call:
740              
741             $selected->clear_selections();
742              
743             =cut
744              
745             sub Rtree {
746 1     1 1 3 my $self = shift @_;
747 1 50       4 unless (defined $self->{NShapes}) {
748 0 0 0     0 croak "no shapes" unless $self->{Shapes} and ref $self->{Shapes} eq 'ARRAY' and @{$self->{Shapes}};
  0   0     0  
749 0         0 $self->{NShapes} = @{$self->{Shapes}};
  0         0  
750             }
751 1         13 $self->{Rtree} = new Tree::R @_;
752 1         22 for my $sindex (0..$self->{NShapes}-1) {
753 9         1063 my $shape = get_shape($self, $sindex);
754 9         11 my @rect;
755 9         13 @rect[0..1] = @{$shape->{MinBounds}}[0..1];
  9         21  
756 9         12 @rect[2..3] = @{$shape->{MaxBounds}}[0..1];
  9         20  
757              
758 9         30 $self->{Rtree}->insert($sindex,@rect);
759             }
760             }
761              
762             sub clear_selections {
763 0     0 0 0 my($self) = @_;
764 0         0 for my $shape (@{$self->{Shapes}}) {
  0         0  
765 0         0 $shape->{SelectedVertices} = [];
766             }
767             }
768              
769             sub select_vertices {
770 0     0 0 0 my($self,$shape,$minx,$miny,$maxx,$maxy) = @_;
771 0 0       0 unless (defined $shape) {
772 0         0 for my $sindex (0..$self->{NShapes}-1) {
773 0         0 $self->select_vertices($sindex);
774             }
775 0         0 return;
776             }
777 0         0 $shape = $self->{Shapes}->[$shape];
778 0         0 my @vertices;
779 0 0       0 unless (defined $maxy) {
780 0         0 @vertices = (0..$shape->{NVertices}-1);
781 0         0 $shape->{SelectedVertices} = \@vertices;
782 0         0 return \@vertices;
783             }
784 0         0 my $v = $shape->{Vertices};
785 0         0 my $i;
786 0         0 for ($i = 0; $i < $shape->{NVertices}; $i++) {
787             next unless
788 0 0 0     0 $v->[$i]->[0] >= $minx and
      0        
      0        
789             $v->[$i]->[0] <= $maxx and
790             $v->[$i]->[1] >= $miny and
791             $v->[$i]->[1] <= $maxy;
792 0         0 push @vertices,$i;
793             }
794 0         0 $shape->{SelectedVertices} = \@vertices;
795 0         0 return \@vertices;
796             }
797              
798             sub move_selected_vertices {
799 0     0 0 0 my($self,$dx,$dy) = @_;
800 0 0       0 return unless $self->{NShapes};
801              
802 0         0 my $count = 0;
803 0         0 for my $sindex (0..$self->{NShapes}-1) {
804 0         0 my $shape = $self->{Shapes}->[$sindex];
805 0 0 0     0 next unless $shape->{SelectedVertices} and @{$shape->{SelectedVertices}};
  0         0  
806              
807 0         0 my $v = $shape->{Vertices};
808 0         0 for my $vindex (@{$shape->{SelectedVertices}}) {
  0         0  
809 0         0 $v->[$vindex]->[0] += $dx;
810 0         0 $v->[$vindex]->[1] += $dy;
811             }
812              
813 0         0 my @rect;
814 0         0 for my $vertex (@{$shape->{Vertices}}) {
  0         0  
815 0 0       0 $rect[0] = defined($rect[0]) ? min($vertex->[0],$rect[0]) : $vertex->[0];
816 0 0       0 $rect[1] = defined($rect[1]) ? min($vertex->[1],$rect[1]) : $vertex->[1];
817 0 0       0 $rect[2] = defined($rect[2]) ? max($vertex->[0],$rect[2]) : $vertex->[0];
818 0 0       0 $rect[3] = defined($rect[3]) ? max($vertex->[1],$rect[3]) : $vertex->[1];
819             }
820              
821 0         0 @{$shape->{MinBounds}}[0..1] = @rect[0..1];
  0         0  
822 0         0 @{$shape->{MaxBounds}}[0..1] = @rect[2..3];
  0         0  
823 0         0 $count++;
824             }
825              
826 0 0       0 if ($self->{Rtree}) {
827 0 0       0 if ($count < 10) {
828 0         0 for my $sindex (0..$self->{NShapes}-1) {
829 0         0 my $shape = $self->{Shapes}->[$sindex];
830 0 0 0     0 next unless $shape->{SelectedVertices} and @{$shape->{SelectedVertices}};
  0         0  
831            
832             # update Rtree...
833            
834             #delete $sindex from it
835 0         0 print STDERR "remove $sindex\n";
836 0         0 $self->{Rtree}->remove($sindex);
837             }
838 0         0 for my $sindex (0..$self->{NShapes}-1) {
839 0         0 my $shape = $self->{Shapes}->[$sindex];
840 0 0 0     0 next unless $shape->{SelectedVertices} and @{$shape->{SelectedVertices}};
  0         0  
841            
842 0         0 my @rect = (@{$shape->{MinBounds}}[0..1],@{$shape->{MaxBounds}}[0..1]);
  0         0  
  0         0  
843            
844             # update Rtree...
845            
846             # add $sindex to it
847 0         0 print STDERR "add $sindex\n";
848 0         0 $self->{Rtree}->insert($sindex,@rect);
849             }
850             } else {
851 0         0 $self->Rtree;
852             }
853             }
854              
855 0         0 $self->{MinBounds}->[0] = $self->{Shapes}->[0]->{MinBounds}->[0];
856 0         0 $self->{MinBounds}->[1] = $self->{Shapes}->[0]->{MinBounds}->[1];
857 0         0 $self->{MaxBounds}->[0] = $self->{Shapes}->[0]->{MaxBounds}->[0];
858 0         0 $self->{MaxBounds}->[1] = $self->{Shapes}->[0]->{MaxBounds}->[1];
859 0         0 for my $sindex (1..$self->{NShapes}-1) {
860 0         0 my $shape = $self->{Shapes}->[$sindex];
861 0         0 $self->{MinBounds}->[0] = min($self->{MinBounds}->[0],$shape->{MinBounds}->[0]);
862 0         0 $self->{MinBounds}->[1] = min($self->{MinBounds}->[1],$shape->{MinBounds}->[1]);
863 0         0 $self->{MaxBounds}->[0] = max($self->{MaxBounds}->[0],$shape->{MaxBounds}->[0]);
864 0         0 $self->{MaxBounds}->[1] = max($self->{MaxBounds}->[1],$shape->{MaxBounds}->[1]);
865             }
866             }
867              
868             sub min {
869 18 100   18 0 42 $_[0] > $_[1] ? $_[1] : $_[0];
870             }
871              
872             sub max {
873 18 100   18 0 41 $_[0] > $_[1] ? $_[0] : $_[1];
874             }
875              
876             =pod
877              
878             =head2 Setting the bounds of the shapefile
879              
880             $shapefile->set_bounds;
881              
882             Sets the MinBounds and MaxBounds of all shapes and of the shapefile.
883              
884             =cut
885              
886             sub set_bounds {
887 1     1 0 55 my($self) = @_;
888              
889 1 50       2 return unless @{$self->{Shapes}};
  1         7  
890              
891 1         4 my $first = 1;
892              
893 1         2 for my $shape (@{$self->{Shapes}}) {
  1         5  
894              
895 1         4 my @rect;
896 1         3 for my $vertex (@{$shape->{Vertices}}) {
  1         3  
897 10 100       30 $rect[0] = defined($rect[0]) ? min($vertex->[0],$rect[0]) : $vertex->[0];
898 10 100       28 $rect[1] = defined($rect[1]) ? min($vertex->[1],$rect[1]) : $vertex->[1];
899 10 100       30 $rect[2] = defined($rect[2]) ? max($vertex->[0],$rect[2]) : $vertex->[0];
900 10 100       253 $rect[3] = defined($rect[3]) ? max($vertex->[1],$rect[3]) : $vertex->[1];
901             }
902              
903 1         4 @{$shape->{MinBounds}}[0..1] = @rect[0..1];
  1         5  
904 1         4 @{$shape->{MaxBounds}}[0..1] = @rect[2..3];
  1         7  
905              
906 1 50       5 if ($first) {
907 1         4 $self->{MinBounds}->[0] = $shape->{MinBounds}->[0];
908 1         3 $self->{MinBounds}->[1] = $shape->{MinBounds}->[1];
909 1         7 $self->{MaxBounds}->[0] = $shape->{MaxBounds}->[0];
910 1         3 $self->{MaxBounds}->[1] = $shape->{MaxBounds}->[1];
911 1         5 $first = 0;
912             } else {
913 0         0 $self->{MinBounds}->[0] = min($self->{MinBounds}->[0],$shape->{MinBounds}->[0]);
914 0         0 $self->{MinBounds}->[1] = min($self->{MinBounds}->[1],$shape->{MinBounds}->[1]);
915 0         0 $self->{MaxBounds}->[0] = max($self->{MaxBounds}->[0],$shape->{MaxBounds}->[0]);
916 0         0 $self->{MaxBounds}->[1] = max($self->{MaxBounds}->[1],$shape->{MaxBounds}->[1]);
917             }
918              
919             }
920              
921             }
922              
923             =pod
924              
925             =head2 Saving the shapefile
926              
927             $shapefile->save($filename);
928              
929             The argument $shapefile is optional, the internal attribute
930             $shapefile->{Name} is used if $filename is not specified. If $filename
931             is specified it also becomes the new name.
932              
933             $filename may contain an extension, it is removed and .shp etc. are used instead.
934              
935             If you are not sure that the bounds of the shapefile are ok, then call
936             $shapefile->set_bounds; before saving.
937              
938             =cut
939              
940             sub save {
941 6     6 0 582 my($self,$filename) = @_;
942              
943 6 100       32 unless (defined $self->{NShapes}) {
944 1 50 33     15 croak "no shapes" unless $self->{Shapes} and ref $self->{Shapes} eq 'ARRAY' and @{$self->{Shapes}};
  1   33     5  
945 1         2 $self->{NShapes} = @{$self->{Shapes}};
  1         5  
946             }
947              
948 6         30 $self->create($filename);
949              
950 6         21 for my $i (0..$self->{NShapes}-1) {
951 11430         21963 my $s = get_shape($self, $i);
952 11430         33125 my $rec = get_record($self, $i);
953 11430         30202 $self->add($s, $rec);
954             }
955              
956 6         29 $self->close();
957             }
958              
959             =pod
960              
961             =head2 create, add, close
962              
963             $shapefile->create($filename);
964              
965             many times:
966             $shapefile->add($shape, $record);
967              
968             $shapefile->close();
969              
970             These methods make it easy to create large shapefiles. $filename is
971             optional. These methods create some temporary variables (prefix: _) in
972             internal data and thus calling of close method is required.
973              
974             =cut
975              
976             sub create {
977 7     7 1 15 my ($self, $filename) = @_;
978              
979 7 100       25 $filename = $self->{Name} unless defined $filename;
980 7         28 $filename =~ s/\.\w+$//;
981 7         23 $self->{_filename} = $filename;
982              
983 7         3628 $self->{_SHPhandle} = SHPCreate($filename.'.shp', $self->{Shapetype});
984 7 50       29 croak "SHPCreate failed" unless $self->{_SHPhandle};
985              
986 7         1387 $self->{_DBFhandle} = DBFCreate($filename.'.dbf');
987 7 50       27 croak "DBFCreate failed" unless $self->{_DBFhandle};
988            
989 7         24 $self->{_fn} = $self->{FieldNames};
990 7         18 my $ft = $self->{FieldTypes};
991 7 100       24 unless ($self->{_fn}) {
992 2         11 ($self->{_fn}, $ft) = data_model($self);
993             }
994 7         13 for my $f (0..$#{$self->{_fn}}) {
  7         45  
995 25         33 my $type = 0;
996 25         27 my $width;
997 25         25 my $decimals = 0;
998 25         148 my ($ftype, $fwidth, $fdeci) = split(/[:;,]/, $ft->[$f]);
999             SWITCH: {
1000 25 100       35 if ($ftype eq 'String') {
  25         66  
1001 3         5 $type = 1;
1002 3 100       8 $width = defined($fwidth)?$fwidth:255;
1003 3         5 last SWITCH;
1004             }
1005 22 100       60 if ($ftype eq 'Integer') {
1006 7         9 $type = 2;
1007 7 100       24 $width = defined($fwidth)?$fwidth:10;
1008 7         13 last SWITCH;
1009             }
1010 15 50       41 if ($ftype eq 'Double') {
1011 15         21 $type = 3;
1012 15 50       42 $width = defined($fwidth)?$fwidth:10;
1013 15 50       28 $decimals = defined($fdeci)?$fdeci:4;
1014 15         30 last SWITCH;
1015             }
1016             }
1017 25         65 $self->{_ftypes}->[$f] = $type;
1018 25 50       54 next unless $type;
1019 25         154 my $ret = _DBFAddField($self->{_DBFhandle}, $self->{_fn}->[$f], $type, $width, $decimals);
1020 25 50       73 croak "DBFAddField failed for field $self->{_fn}->[$f] of type $ft->[$f]" if $ret == -1;
1021             }
1022            
1023 7         27 $self->{_SHP_id} = 0;
1024             }
1025              
1026             sub add {
1027 14285     14285 1 29789 my ($self, $shape, $record) = @_;
1028              
1029 14285 100       48218 if (defined($shape->{SHPType})) {
1030 14276 50 33     74130 if ($shape->{SHPType} != 0 and $shape->{SHPType} != $self->{Shapetype}) {
1031 0         0 croak "non-null shapes with differing shape types";
1032             }
1033             } else {
1034 9         21 $shape->{SHPType} = $self->{Shapetype};
1035             }
1036 14285 100       41263 my $nParts = exists $shape->{Parts} ? @{$shape->{Parts}} : 0;
  14276         26870  
1037 14285 100       32779 if (defined $shape->{NParts}) {
1038 14276 50       26736 if ($shape->{NParts} > $nParts) {
1039 0         0 croak "NParts is larger than the actual number of Parts";
1040             } else {
1041 14276         19204 $nParts = $shape->{NParts};
1042             }
1043             }
1044 14285 50       28467 my $nVertices = exists $shape->{Vertices} ? @{$shape->{Vertices}} : 0;
  14285         28407  
1045 14285 100       30406 if (defined $shape->{NVertices}) {
1046 14276 50       26778 if ($shape->{NVertices} > $nVertices) {
1047 0         0 croak "NVertices is larger than the actual number of Vertices";
1048             } else {
1049 14276         18878 $nVertices = $shape->{NVertices};
1050             }
1051             }
1052 14285 100       29148 my $id = defined $shape->{ShapeId} ? $shape->{ShapeId} : $self->{_SHP_id};
1053              
1054 14285         86288 my $s = _SHPCreateObject($shape->{SHPType}, $id, $nParts, $shape->{Parts}, $nVertices, $shape->{Vertices});
1055 14285 50       34339 croak "SHPCreateObject failed" unless $s;
1056 14285         295614 SHPWriteObject($self->{_SHPhandle}, -1, $s);
1057 14285         44136 SHPDestroyObject($s);
1058              
1059 14285         24842 my $r = $record;
1060 14285 100       36557 if (ref $r eq 'HASH') {
1061 14275         16779 my @rec;
1062 14275         14549 for (@{$self->{_fn}}) {
  14275         35177  
1063 57100         115125 push @rec,$r->{$_};
1064             }
1065 14275         30411 $r = \@rec;
1066             }
1067              
1068 14285         16717 for my $f (0..$#{$self->{_fn}}) {
  14285         41011  
1069 57129 50       125146 next unless $self->{_ftypes}->[$f];
1070 57129         58035 my $ret;
1071             SWITCH: {
1072 57129 100       59492 if ($self->{_ftypes}->[$f] == 1) {
  57129         123589  
1073 19 50       196 $ret = DBFWriteStringAttribute($self->{_DBFhandle}, $self->{_SHP_id}, $f, $r->[$f]) if exists $r->[$f];
1074 19         22 last SWITCH;
1075             }
1076 57110 100       115698 if ($self->{_ftypes}->[$f] == 2) {
1077 14285 50       79199 $ret = DBFWriteIntegerAttribute($self->{_DBFhandle}, $self->{_SHP_id}, $f, $r->[$f]) if exists $r->[$f];
1078 14285         17612 last SWITCH;
1079             }
1080 42825 50       84401 if ($self->{_ftypes}->[$f] == 3) {
1081 42825 50       487021 $ret = DBFWriteDoubleAttribute($self->{_DBFhandle}, $self->{_SHP_id}, $f, $r->[$f]) if exists $r->[$f];
1082 42825         65132 last SWITCH;
1083             }
1084             }
1085 57129 50       146622 croak "DBFWriteAttribute(field = $self->{_fn}->[$f], ftype = $self->{_ftypes}[$f], value = $r->[$f]) failed" unless $ret;
1086             }
1087            
1088 14285         67397 $self->{_SHP_id}++;
1089             }
1090              
1091             sub close {
1092 7     7 1 25 my ($self) = @_;
1093 7         2024 SHPClose($self->{_SHPhandle});
1094 7         402 DBFClose($self->{_DBFhandle});
1095 7         29 $self->{Name} = $self->{_filename};
1096 7         32 delete $self->{_SHPhandle};
1097 7         19 delete $self->{_DBFhandle};
1098 7         21 delete $self->{_fn};
1099 7         20 delete $self->{_ftypes};
1100 7         14 delete $self->{_SHP_id};
1101 7         34 delete $self->{_filename};
1102             }
1103              
1104             =pod
1105              
1106             =head2 Dump
1107              
1108             $shapefile->dump($to);
1109              
1110             $to can be undef (then dump uses STDOUT), filename, or reference to a
1111             filehandle (e.g., \*DUMP).
1112              
1113             This method just dumps all data. If you have yourself created the
1114             shapefile then the reported bounds may be incorrect.
1115              
1116             =cut
1117              
1118             sub dump {
1119 1     1 0 250 my ($self,$file) = @_;
1120              
1121 1 50       5 unless (defined $self->{NShapes}) {
1122 1 50 33     19 croak "no shapes" unless $self->{Shapes} and ref $self->{Shapes} eq 'ARRAY' and @{$self->{Shapes}};
  1   33     5  
1123 1         2 $self->{NShapes} = @{$self->{Shapes}};
  1         3  
1124             }
1125            
1126 1         3 my $old_select;
1127 1 50       3 if (defined $file) {
1128 1 50       3 if (not ref $file) {
1129             # $file is a name that we'll convert to a file handle
1130             # ref. Passing open a scalar makes it close when the
1131             # scaler is destroyed.
1132 1         3 my $fh;
1133 1 50       120 unless (open $fh, ">$file") {
1134 0         0 carp("$file: $!"),
1135             return undef;
1136             }
1137 1         2 $file = $fh;
1138             }
1139 1 50       5 return undef unless ref($file) eq 'GLOB';
1140 1         4 $old_select = select($file);
1141             }
1142            
1143 1   50     26 printf "Name: %s\n", ($self->{Name} or '(none)');
1144 1         6 print "Shape type: $self->{Shapetype} ($ShapeTypes{$self->{Shapetype}})\n";
1145 1 50       4 printf "Min bounds: %11f %11f %11f %11f\n", @{$self->{MinBounds}} if $self->{MinBounds};
  0         0  
1146 1 50       4 printf "Max bounds: %11f %11f %11f %11f\n", @{$self->{MaxBounds}} if $self->{MaxBounds};
  0         0  
1147 1         2 my $fn = $self->{FieldNames};
1148 1         2 my $ft = $self->{FieldTypes};
1149 1 50       4 unless ($fn) {
1150 0         0 ($fn, $ft) = data_model($self);
1151             }
1152 1         3 print "Field names: ", join(', ', @$fn), "\n";
1153 1         9 print "Field types: ", join(', ', @$ft), "\n";
1154              
1155 1         3 print "Number of shapes: $self->{NShapes}\n";
1156            
1157 1         12 my $sindex = 0;
1158 1         4 while($sindex < $self->{NShapes}) {
1159 9         16 my $shape = get_shape($self, $sindex);
1160 9         16 my $rec = get_record_arrayref($self, $sindex, $fn);
1161            
1162 9         30 print "Begin shape ",$sindex+1," of $self->{NShapes}\n";
1163 9         17 print "\tShape id: $shape->{ShapeId}\n";
1164 9         20 print "\tShape type: $shape->{SHPType} ($ShapeTypes{$shape->{SHPType}})\n";
1165 9 50       20 printf "\tMin bounds: %11f %11f %11f %11f\n", @{$shape->{MinBounds}} if $shape->{MinBounds};
  0         0  
1166 9 50       17 printf "\tMax bounds: %11f %11f %11f %11f\n", @{$shape->{MaxBounds}} if $shape->{MaxBounds};
  0         0  
1167            
1168 9         19 print "\tShape record: ", join(', ', @$rec), "\n";
1169            
1170 9 50       16 if ($shape->{NParts}) {
1171            
1172 0         0 my $pindex = 0;
1173 0         0 my $pmax = $shape->{NParts};
1174 0         0 while($pindex < $pmax) {
1175 0         0 my $part = $shape->{Parts}[$pindex];
1176 0         0 print "\tBegin part ",$pindex+1," of $pmax\n";
1177            
1178 0 0       0 if($self->{CombineVertices}) {
1179 0         0 print "\t\tPartType: $part->[1] ($part->[2])\n";
1180 0         0 my $vindex = $part->[0];
1181 0         0 my $vmax = $shape->{Parts}[$pindex+1][0];
1182 0 0       0 $vmax = $shape->{NVertices} unless defined $vmax;
1183 0         0 while($vindex < $vmax) {
1184 0         0 printf "\t\tVertex: %11f %11f %11f %11f\n", @{$shape->{Vertices}[$vindex]};
  0         0  
1185 0         0 $vindex++;
1186             }
1187             } else {
1188 0         0 print "\t\tPart id: $part->{PartId}\n";
1189 0         0 print "\t\tPart type: $part->{PartType} ($PartTypes{$part->{PartType}})\n";
1190 0         0 for my $vertex (@{$part->{Vertices}}) {
  0         0  
1191 0         0 printf "\t\tVertex: %11f %11f %11f %11f\n", @$vertex;
1192             }
1193             }
1194            
1195 0         0 print "\tEnd part ",$pindex+1," of $pmax\n";
1196 0         0 $pindex++;
1197             }
1198            
1199             } else {
1200            
1201 9         9 for my $vertex (@{$shape->{Vertices}}) {
  9         17  
1202 9         123 printf "\t\tVertex: %11f %11f %11f %11f\n", @$vertex;
1203             }
1204            
1205             }
1206            
1207 9         29 print "End shape ",$sindex+1," of $self->{NShapes}\n";
1208 9         26 $sindex++;
1209             }
1210            
1211 1 50       6 select $old_select if defined $old_select;
1212 1         60 return 1;
1213             }
1214              
1215             sub DESTROY {
1216 11     11   67 my $self = shift;
1217 11 100       15986 SHPClose($self->{SHPHandle}) if defined $self->{SHPHandle};
1218             }
1219              
1220             1;
1221             __END__