File Coverage

lib/Geo/WKT.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             # Copyrights 2008-2015 by [Mark Overmeer].
2             # For other contributors see ChangeLog.
3             # See the manual pages for details on the licensing terms.
4             # Pod stripped from pm file by OODoc 2.01.
5 7     7   103409 use strict;
  7         14  
  7         247  
6 7     7   28 use warnings;
  7         8  
  7         243  
7              
8             package Geo::WKT;
9 7     7   46 use vars '$VERSION';
  7         9  
  7         440  
10             $VERSION = '0.95';
11              
12 7     7   33 use base 'Exporter';
  7         11  
  7         749  
13              
14 7     7   5919 use Geo::Shape ();
  0            
  0            
15             use Carp;
16              
17             our @EXPORT = qw(
18             parse_wkt
19             parse_wkt_point
20             parse_wkt_polygon
21             parse_wkt_geomcol
22             parse_wkt_linestring
23             wkt_point
24             wkt_multipoint
25             wkt_linestring
26             wkt_polygon
27             wkt_linestring
28             wkt_multilinestring
29             wkt_multipolygon
30             wkt_optimal
31             wkt_geomcollection
32             );
33              
34             sub wkt_optimal($);
35              
36              
37             sub parse_wkt_point($;$)
38             { ($_[0] =~ m/^point\(\s*(\S+)\s+(\S+)\)$/i)
39             ? Geo::Point->xy($1+0, $2+0, $_[1])
40             : undef;
41             }
42              
43              
44             sub parse_wkt_polygon($;$)
45             { my ($string, $proj) = @_;
46              
47             $string && $string =~ m/^polygon\(\((.+)\)\)$/i
48             or return undef;
49              
50             my @poly;
51             foreach my $poly (split m/\)\s*\,\s*\(/, $1)
52             { my @points = map +[split " ", $_, 2], split /\s*\,\s*/, $poly;
53             push @poly, \@points;
54             }
55              
56             Geo::Surface->new(@poly, proj => $proj);
57             }
58              
59              
60             sub parse_wkt_geomcol($;$)
61             { my ($string, $proj) = @_;
62              
63             return undef if $string !~
64             s/^(multiline|multipoint|multipolygon|geometrycollection)\(//i;
65              
66             my @comp;
67             while($string =~ m/\D/)
68             { $string =~ s/^([^(]*\([^)]*\))//
69             or last;
70              
71             my $take = $1;
72             while(1)
73             { my @open = $take =~ m/\(/g;
74             my @close = $take =~ m/\)/g;
75             last if @open==@close;
76             $take .= $1 if $string =~ s/^([^\)]*\))//;
77             }
78             push @comp, parse_wkt($take, $proj);
79             $string =~ s/^\s*\,\s*//;
80             }
81              
82             Geo::Space->new(@comp, proj => $proj);
83             }
84              
85              
86             sub parse_wkt_linestring($;$)
87             { my ($string, $proj) = @_;
88              
89             $string && $string =~ m/^linestring\((.+)\)$/i
90             or return undef;
91              
92             my @points = map +[split " ", $_, 2], split /\s*\,\s*/, $1;
93             @points > 1 or return;
94              
95             Geo::Line->new(proj => $proj, points => \@points, filled => 0);
96             }
97              
98              
99             sub parse_wkt($;$) # dirty code to avoid copying the sometimes huge string
100             {
101             $_[0] =~ m/^point\(/i ? &parse_wkt_point
102             : $_[0] =~ m/^polygon\(/i ? &parse_wkt_polygon
103             : $_[0] =~ m/^linestring\(/i ? &parse_wkt_linestring
104             : &parse_wkt_geomcol;
105             }
106              
107              
108             sub _list_of_points(@)
109             { my @points
110             = @_ > 1 ? @_
111             : ref $_[0] eq 'ARRAY' ? @{$_[0]}
112             : $_[0]->isa('Math::Polygon') ? $_[0]->points
113             : $_[0];
114              
115             my @s = map
116             { (ref $_ ne 'ARRAY' && $_->isa('Geo::Point'))
117             ? $_->x.' '.$_->y
118             : $_->[0].' '.$_->[1]
119             } @points;
120              
121             local $" = ',';
122             "(@s)";
123             }
124              
125             sub wkt_point($;$)
126             { my ($x, $y)
127             = @_==2 ? @_
128             : ref $_[0] eq 'ARRAY' ? @{$_[0]}
129             : shift->xy;
130              
131             defined $x && defined $y ? "POINT($x $y)" : ();
132             }
133              
134              
135             sub wkt_linestring(@) { 'LINESTRING' . _list_of_points(@_) }
136              
137              
138             sub wkt_polygon(@)
139             { my @polys
140             = !defined $_[0] ? return ()
141             : ref $_[0] eq 'ARRAY' ? (ref $_[0][0] ? @_ : [@_])
142             : $_[0]->isa('Geo::Line') ? @_
143             : $_[0]->isa('Geo::Surface') ? ($_[0]->outer, $_[0]->inner)
144             : [@_];
145              
146             'POLYGON(' .join(',' , map _list_of_points($_), @polys). ')';
147             }
148              
149              
150             sub wkt_multipoint(@) { 'MULTIPOINT(' .join(',', map wkt_point($_), @_). ')'}
151              
152              
153             sub wkt_multilinestring(@)
154             { return () unless @_;
155             'MULTILINESTRING(' .join(',' , map wkt_linestring($_), @_). ')';
156             }
157              
158              
159             sub wkt_multipolygon(@)
160             { return () unless @_;
161              
162             my @polys = map wkt_polygon($_), @_;
163             s/^POLYGON// for @polys;
164              
165             'MULTIPOLYGON(' .join(',' , @polys). ')';
166             }
167              
168              
169              
170             sub wkt_optimal($)
171             { my $geom = shift;
172             return wkt_point(undef) unless defined $geom;
173              
174             return wkt_point($geom)
175             if $geom->isa('Geo::Point');
176              
177             return ( $geom->isRing && $geom->isFilled
178             ? wkt_polygon($geom)
179             : wkt_linestring($geom))
180             if $geom->isa('Geo::Line');
181              
182             return wkt_multipolygon($geom)
183             if $geom->isa('Geo::Surface');
184              
185             $geom->isa('Geo::Space')
186             or croak "ERROR: Cannot translate object $geom into SQL";
187              
188             $geom->nrComponents==1 ? wkt_optimal($geom->component(0))
189             : $geom->onlyPoints ? wkt_multipoint($geom->points)
190             : wkt_geomcollection($geom);
191             }
192              
193              
194             sub wkt_geomcollection(@)
195             { @_ = $_[0]->components
196             if @_==1
197             && ref $_[0] ne 'ARRAY'
198             && $_[0]->isa('Geo::Space');
199              
200             'GEOMETRYCOLLECTION(' .join(',', map wkt_optimal($_), @_). ')';
201             }
202              
203             1;