line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Geo::GDAL::FFI::Geometry; |
2
|
5
|
|
|
5
|
|
66
|
use v5.10; |
|
5
|
|
|
|
|
18
|
|
3
|
5
|
|
|
5
|
|
26
|
use strict; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
103
|
|
4
|
5
|
|
|
5
|
|
25
|
use warnings; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
128
|
|
5
|
5
|
|
|
5
|
|
31
|
use Carp; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
17245
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = 0.0900; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
my %ref; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
sub new { |
12
|
17
|
|
|
17
|
1
|
1093
|
my $class = shift; |
13
|
17
|
|
|
|
|
29
|
my $g = 0; |
14
|
17
|
50
|
|
|
|
43
|
confess "Must give either geometry type or format => data." unless @_; |
15
|
17
|
100
|
|
|
|
40
|
if (@_ == 1) { |
16
|
9
|
|
50
|
|
|
21
|
my $type = shift // ''; |
17
|
9
|
|
|
|
|
27
|
my $tmp = $Geo::GDAL::FFI::geometry_types{$type}; |
18
|
9
|
50
|
|
|
|
20
|
confess "Empty or unknown geometry type: '$type'." unless defined $tmp; |
19
|
9
|
|
|
|
|
33
|
my $m = $type =~ /M$/; |
20
|
9
|
|
100
|
|
|
44
|
my $z = $type =~ /ZM$/ || $type =~ /25D$/; |
21
|
9
|
|
|
|
|
73
|
$g = Geo::GDAL::FFI::OGR_G_CreateGeometry($tmp); |
22
|
9
|
50
|
|
|
|
25
|
confess "OGR_G_CreateGeometry failed." unless $g; # should not happen |
23
|
9
|
100
|
|
|
|
31
|
Geo::GDAL::FFI::OGR_G_SetMeasured($g, 1) if $m; |
24
|
9
|
100
|
|
|
|
22
|
Geo::GDAL::FFI::OGR_G_Set3D($g, 1) if $z; |
25
|
9
|
|
|
|
|
36
|
return bless \$g, $class; |
26
|
|
|
|
|
|
|
} else { |
27
|
8
|
|
|
|
|
24
|
my ($format, $string, $sr) = @_; |
28
|
8
|
|
|
|
|
21
|
my $tmp = $Geo::GDAL::FFI::geometry_formats{$format}; |
29
|
8
|
50
|
|
|
|
24
|
confess "Empty or unknown geometry format: '$format'." unless defined $tmp; |
30
|
8
|
50
|
|
|
|
18
|
$sr = $$sr if $sr; |
31
|
8
|
50
|
|
|
|
20
|
if ($format eq 'WKT') { |
32
|
8
|
|
|
|
|
49
|
my $e = Geo::GDAL::FFI::OGR_G_CreateFromWkt(\$string, $sr, \$g); |
33
|
8
|
50
|
|
|
|
583
|
confess(Geo::GDAL::FFI::error_msg({OGRError => $e})) if $e; |
34
|
|
|
|
|
|
|
} |
35
|
|
|
|
|
|
|
} |
36
|
8
|
|
|
|
|
28
|
return bless \$g, $class; |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
sub DESTROY { |
40
|
56
|
|
|
56
|
|
2988
|
my ($self) = @_; |
41
|
56
|
|
|
|
|
145
|
Geo::GDAL::FFI::_deregister_parent_ref ($$self); |
42
|
56
|
100
|
|
|
|
110
|
if ($ref{$$self}) { |
43
|
36
|
|
|
|
|
58
|
delete $ref{$$self}; |
44
|
36
|
|
|
|
|
60
|
return; |
45
|
|
|
|
|
|
|
} |
46
|
20
|
100
|
|
|
|
50
|
if ($Geo::GDAL::FFI::immutable{$$self}) { |
47
|
|
|
|
|
|
|
#say STDERR "forget $$self $immutable{$$self}"; |
48
|
7
|
|
|
|
|
13
|
$Geo::GDAL::FFI::immutable{$$self}--; |
49
|
7
|
100
|
|
|
|
52
|
delete $Geo::GDAL::FFI::immutable{$$self} if $Geo::GDAL::FFI::immutable{$$self} == 0; |
50
|
|
|
|
|
|
|
} else { |
51
|
|
|
|
|
|
|
#say STDERR "destroy $$self"; |
52
|
13
|
|
|
|
|
106
|
Geo::GDAL::FFI::OGR_G_DestroyGeometry($$self); |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub Clone { |
57
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
58
|
0
|
|
|
|
|
0
|
my $g = Geo::GDAL::FFI::OGR_G_Clone($$self); |
59
|
0
|
|
|
|
|
0
|
return bless \$g, 'Geo::GDAL::FFI::Geometry'; |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub GetType { |
63
|
5
|
|
|
5
|
1
|
27
|
my ($self, $mode) = @_; |
64
|
5
|
|
50
|
|
|
32
|
$mode //= ''; |
65
|
5
|
|
|
|
|
23
|
my $t = Geo::GDAL::FFI::OGR_G_GetGeometryType($$self); |
66
|
5
|
50
|
|
|
|
15
|
Geo::GDAL::FFI::OGR_GT_Flatten($t) if $mode =~ /flatten/i; |
67
|
|
|
|
|
|
|
#say STDERR "type is $t"; |
68
|
5
|
|
|
|
|
33
|
return $Geo::GDAL::FFI::geometry_types_reverse{$t}; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
sub GetPointCount { |
72
|
13
|
|
|
13
|
1
|
23
|
my ($self) = @_; |
73
|
13
|
|
|
|
|
46
|
return Geo::GDAL::FFI::OGR_G_GetPointCount($$self); |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub SetPoint { |
77
|
36
|
|
|
36
|
1
|
382
|
my $self = shift; |
78
|
36
|
50
|
|
|
|
68
|
confess "Can't modify an immutable object." if $Geo::GDAL::FFI::immutable{$$self}; |
79
|
36
|
|
|
|
|
41
|
my $i; |
80
|
36
|
100
|
|
|
|
101
|
if (Geo::GDAL::FFI::OGR_G_GetDimension($$self) == 0) { |
81
|
4
|
|
|
|
|
7
|
$i = 0; |
82
|
|
|
|
|
|
|
} else { |
83
|
32
|
|
|
|
|
39
|
$i = shift; |
84
|
|
|
|
|
|
|
} |
85
|
36
|
|
|
|
|
50
|
my ($x, $y, $z, $m, $is3d, $ism); |
86
|
36
|
50
|
|
|
|
62
|
confess "SetPoint missing coordinate parameters." unless @_; |
87
|
36
|
100
|
|
|
|
63
|
if (ref $_[0]) { |
88
|
31
|
|
|
|
|
33
|
($x, $y, $z, $m) = @{$_[0]}; |
|
31
|
|
|
|
|
44
|
|
89
|
31
|
|
66
|
|
|
65
|
$is3d = $_[1] // Geo::GDAL::FFI::OGR_G_Is3D($$self); |
90
|
31
|
|
66
|
|
|
49
|
$ism = $_[2] // Geo::GDAL::FFI::OGR_G_IsMeasured($$self); |
91
|
|
|
|
|
|
|
} else { |
92
|
5
|
50
|
|
|
|
15
|
confess "SetPoint missing coordinate parameters." unless @_ > 1; |
93
|
5
|
|
|
|
|
14
|
($x, $y, $z, $m) = @_; |
94
|
5
|
|
|
|
|
22
|
$is3d = Geo::GDAL::FFI::OGR_G_Is3D($$self); |
95
|
5
|
|
|
|
|
18
|
$ism = Geo::GDAL::FFI::OGR_G_IsMeasured($$self); |
96
|
|
|
|
|
|
|
} |
97
|
36
|
50
|
66
|
|
|
130
|
if ($is3d && $ism) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
98
|
0
|
|
0
|
|
|
0
|
$z //= 0; |
99
|
0
|
|
0
|
|
|
0
|
$m //= 0; |
100
|
0
|
|
|
|
|
0
|
Geo::GDAL::FFI::OGR_G_SetPointZM($$self, $i, $x, $y, $z, $m); |
101
|
|
|
|
|
|
|
} elsif ($ism) { |
102
|
1
|
|
50
|
|
|
8
|
$m //= 0; |
103
|
1
|
|
|
|
|
11
|
Geo::GDAL::FFI::OGR_G_SetPointM($$self, $i, $x, $y, $m); |
104
|
|
|
|
|
|
|
} elsif ($is3d) { |
105
|
30
|
|
50
|
|
|
42
|
$z //= 0; |
106
|
30
|
|
|
|
|
88
|
Geo::GDAL::FFI::OGR_G_SetPoint($$self, $i, $x, $y, $z); |
107
|
|
|
|
|
|
|
} else { |
108
|
5
|
|
|
|
|
62
|
Geo::GDAL::FFI::OGR_G_SetPoint_2D($$self, $i, $x, $y); |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
sub GetPoint { |
113
|
63
|
|
|
63
|
1
|
90
|
my ($self, $i, $is3d, $ism) = @_; |
114
|
63
|
|
100
|
|
|
96
|
$i //= 0; |
115
|
63
|
|
66
|
|
|
102
|
$is3d //= Geo::GDAL::FFI::OGR_G_Is3D($$self); |
116
|
63
|
|
66
|
|
|
107
|
$ism //= Geo::GDAL::FFI::OGR_G_IsMeasured($$self); |
117
|
63
|
|
|
|
|
80
|
my ($x, $y, $z, $m) = (0, 0, 0, 0); |
118
|
63
|
|
|
|
|
253
|
Geo::GDAL::FFI::OGR_G_GetPointZM($$self, $i, \$x, \$y, \$z, \$m); |
119
|
63
|
|
|
|
|
122
|
my @point = ($x, $y); |
120
|
63
|
100
|
|
|
|
95
|
push @point, $z if $is3d; |
121
|
63
|
50
|
|
|
|
89
|
push @point, $m if $ism; |
122
|
63
|
100
|
|
|
|
112
|
return wantarray ? @point : \@point; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
sub GetPoints { |
126
|
26
|
|
|
26
|
1
|
42
|
my ($self, $is3d, $ism) = @_; |
127
|
26
|
|
66
|
|
|
45
|
$is3d //= Geo::GDAL::FFI::OGR_G_Is3D($$self); |
128
|
26
|
|
66
|
|
|
53
|
$ism //= Geo::GDAL::FFI::OGR_G_IsMeasured($$self); |
129
|
26
|
|
|
|
|
29
|
my $points = []; |
130
|
26
|
|
|
|
|
43
|
my $n = $self->GetGeometryCount; |
131
|
26
|
100
|
|
|
|
51
|
if ($n == 0) { |
132
|
12
|
|
|
|
|
15
|
$n = $self->GetPointCount; |
133
|
12
|
50
|
|
|
|
21
|
return scalar $self->GetPoint(0, $is3d, $ism) if $n == 0; |
134
|
12
|
|
|
|
|
16
|
for my $i (0..$n-1) { |
135
|
60
|
|
|
|
|
94
|
my $p = $self->GetPoint($i, $is3d, $ism); |
136
|
60
|
|
|
|
|
92
|
push @$points, $p; |
137
|
|
|
|
|
|
|
} |
138
|
12
|
|
|
|
|
28
|
return $points; |
139
|
|
|
|
|
|
|
} |
140
|
14
|
|
|
|
|
30
|
for my $i (0..$n-1) { |
141
|
24
|
|
|
|
|
41
|
push @$points, $self->GetGeometry($i)->GetPoints($is3d, $ism); |
142
|
|
|
|
|
|
|
} |
143
|
14
|
|
|
|
|
38
|
return $points; |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
sub SetPoints { |
147
|
13
|
|
|
13
|
1
|
342
|
my ($self, $points, $is3d, $ism) = @_; |
148
|
13
|
50
|
|
|
|
22
|
confess "SetPoints must be called with an arrayref." unless ref $points; |
149
|
13
|
|
66
|
|
|
28
|
$is3d //= Geo::GDAL::FFI::OGR_G_Is3D($$self); |
150
|
13
|
|
66
|
|
|
28
|
$ism //= Geo::GDAL::FFI::OGR_G_IsMeasured($$self); |
151
|
13
|
|
|
|
|
20
|
my $n = $self->GetGeometryCount; |
152
|
13
|
100
|
|
|
|
23
|
if ($n == 0) { |
153
|
6
|
50
|
|
|
|
13
|
unless (ref $points->[0]) { |
154
|
0
|
|
|
|
|
0
|
$self->SetPoint($points, $is3d, $ism); |
155
|
0
|
|
|
|
|
0
|
return; |
156
|
|
|
|
|
|
|
} |
157
|
6
|
|
|
|
|
8
|
$n = @$points; |
158
|
6
|
|
|
|
|
8
|
for my $i (0..$n-1) { |
159
|
30
|
|
|
|
|
46
|
$self->SetPoint($i, $points->[$i], $is3d, $ism); |
160
|
|
|
|
|
|
|
} |
161
|
6
|
|
|
|
|
13
|
return; |
162
|
|
|
|
|
|
|
} |
163
|
7
|
|
|
|
|
14
|
for my $i (0..$n-1) { |
164
|
12
|
|
|
|
|
19
|
$self->GetGeometry($i)->SetPoints($points->[$i], $is3d, $ism); |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
sub GetGeometryCount { |
169
|
39
|
|
|
39
|
1
|
46
|
my ($self) = @_; |
170
|
39
|
|
|
|
|
109
|
return Geo::GDAL::FFI::OGR_G_GetGeometryCount($$self); |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
sub GetGeometry { |
174
|
36
|
|
|
36
|
1
|
46
|
my ($self, $i) = @_; |
175
|
36
|
|
|
|
|
96
|
my $g = Geo::GDAL::FFI::OGR_G_GetGeometryRef($$self, $i); |
176
|
36
|
|
|
|
|
79
|
Geo::GDAL::FFI::_register_parent_ref ($g, $self); |
177
|
36
|
|
|
|
|
49
|
$ref{$g} = 1; |
178
|
36
|
|
|
|
|
94
|
return bless \$g, 'Geo::GDAL::FFI::Geometry'; |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
sub AddGeometry { |
182
|
0
|
|
|
0
|
1
|
0
|
my ($self, $g) = @_; |
183
|
0
|
0
|
|
|
|
0
|
confess "Can't modify an immutable object." if $Geo::GDAL::FFI::immutable{$$self}; |
184
|
0
|
|
|
|
|
0
|
my $e = Geo::GDAL::FFI::OGR_G_OGR_G_AddGeometry($$self, $$g); |
185
|
0
|
0
|
|
|
|
0
|
return unless $e; |
186
|
0
|
|
|
|
|
0
|
confess(Geo::GDAL::FFI::error_msg()); |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
sub RemoveGeometry { |
190
|
0
|
|
|
0
|
1
|
0
|
my ($self, $i) = @_; |
191
|
0
|
0
|
|
|
|
0
|
confess "Can't modify an immutable object." if $Geo::GDAL::FFI::immutable{$$self}; |
192
|
0
|
|
|
|
|
0
|
my $e = Geo::GDAL::FFI::OGR_G_RemoveGeometry($$self, $i, 1); |
193
|
0
|
0
|
|
|
|
0
|
return unless $e; |
194
|
0
|
|
|
|
|
0
|
confess(Geo::GDAL::FFI::error_msg()); |
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
sub ExportToWKT { |
198
|
10
|
|
|
10
|
1
|
322
|
my ($self, $variant) = @_; |
199
|
10
|
|
50
|
|
|
48
|
$variant //= 'ISO'; |
200
|
10
|
|
|
|
|
20
|
my $wkt = ''; |
201
|
10
|
50
|
|
|
|
53
|
if ($variant =~ /(?i)iso/) { |
202
|
10
|
|
|
|
|
58
|
Geo::GDAL::FFI::OGR_G_ExportToIsoWkt($$self, \$wkt); |
203
|
|
|
|
|
|
|
} else { |
204
|
0
|
|
|
|
|
0
|
Geo::GDAL::FFI::OGR_G_ExportToWkt($$self, \$wkt); |
205
|
|
|
|
|
|
|
} |
206
|
10
|
|
|
|
|
790
|
return $wkt; |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
*AsText = *ExportToWKT; |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
sub ExportToGML { |
211
|
0
|
|
|
0
|
1
|
0
|
my ($self, %options) = @_; |
212
|
0
|
|
|
|
|
0
|
my $o = 0; |
213
|
0
|
|
|
|
|
0
|
for my $key (keys %options) { |
214
|
0
|
|
|
|
|
0
|
$o = Geo::GDAL::FFI::CSLAddString($o, "$key=$options{$key}"); |
215
|
|
|
|
|
|
|
} |
216
|
0
|
|
|
|
|
0
|
my $p; |
217
|
0
|
0
|
|
|
|
0
|
if ($o) { |
218
|
0
|
|
|
|
|
0
|
$p = Geo::GDAL::FFI::OGR_G_ExportToGMLEx($$self, $o); |
219
|
0
|
|
|
|
|
0
|
Geo::GDAL::FFI::CSLDestroy($o); |
220
|
|
|
|
|
|
|
} else { |
221
|
0
|
|
|
|
|
0
|
$p = Geo::GDAL::FFI::OGR_G_ExportToGML($$self); |
222
|
|
|
|
|
|
|
} |
223
|
0
|
|
|
|
|
0
|
my $ffi = FFI::Platypus->new; |
224
|
0
|
|
|
|
|
0
|
my $gml = $ffi->cast(opaque => 'string', $p); |
225
|
0
|
|
|
|
|
0
|
Geo::GDAL::FFI::VSIFree($p); |
226
|
0
|
0
|
|
|
|
0
|
confess Geo::GDAL::FFI::error_msg() unless $gml; |
227
|
0
|
|
|
|
|
0
|
return $gml; |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
sub ExportToKML { |
231
|
0
|
|
|
0
|
0
|
0
|
my ($self) = @_; |
232
|
0
|
|
|
|
|
0
|
my $p = Geo::GDAL::FFI::OGR_G_ExportToKML($$self); |
233
|
0
|
|
|
|
|
0
|
my $ffi = FFI::Platypus->new; |
234
|
0
|
|
|
|
|
0
|
my $kml = $ffi->cast(opaque => 'string', $p); |
235
|
0
|
|
|
|
|
0
|
Geo::GDAL::FFI::VSIFree($p); |
236
|
0
|
0
|
|
|
|
0
|
confess Geo::GDAL::FFI::error_msg() unless $kml; |
237
|
0
|
|
|
|
|
0
|
return $kml; |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
sub ExportToJSON { |
241
|
0
|
|
|
0
|
1
|
0
|
my ($self, %options) = @_; |
242
|
0
|
|
|
|
|
0
|
my $o = 0; |
243
|
0
|
|
|
|
|
0
|
for my $key (keys %options) { |
244
|
0
|
|
|
|
|
0
|
$o = Geo::GDAL::FFI::CSLAddString($o, "$key=$options{$key}"); |
245
|
|
|
|
|
|
|
} |
246
|
0
|
|
|
|
|
0
|
my $p; |
247
|
0
|
0
|
|
|
|
0
|
if ($o) { |
248
|
0
|
|
|
|
|
0
|
$p = Geo::GDAL::FFI::OGR_G_ExportToJsonEx($$self, $o); |
249
|
0
|
|
|
|
|
0
|
Geo::GDAL::FFI::CSLDestroy($o); |
250
|
|
|
|
|
|
|
} else { |
251
|
0
|
|
|
|
|
0
|
$p = Geo::GDAL::FFI::OGR_G_ExportToJson($$self); |
252
|
|
|
|
|
|
|
} |
253
|
0
|
|
|
|
|
0
|
my $ffi = FFI::Platypus->new; |
254
|
0
|
|
|
|
|
0
|
my $json = $ffi->cast(opaque => 'string', $p); |
255
|
0
|
|
|
|
|
0
|
Geo::GDAL::FFI::VSIFree($p); |
256
|
0
|
0
|
|
|
|
0
|
confess Geo::GDAL::FFI::error_msg() unless $json; |
257
|
0
|
|
|
|
|
0
|
return $json; |
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
sub Intersects { |
261
|
0
|
|
|
0
|
1
|
0
|
my ($self, $geom) = @_; |
262
|
0
|
|
|
|
|
0
|
return Geo::GDAL::FFI::OGR_G_Intersects($$self, $$geom); |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
sub Equals { |
266
|
0
|
|
|
0
|
1
|
0
|
my ($self, $geom) = @_; |
267
|
0
|
|
|
|
|
0
|
return Geo::GDAL::FFI::OGR_G_Equals($$self, $$geom); |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
sub Disjoint { |
271
|
0
|
|
|
0
|
1
|
0
|
my ($self, $geom) = @_; |
272
|
0
|
|
|
|
|
0
|
return Geo::GDAL::FFI::OGR_G_Disjoint($$self, $$geom); |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
sub Touches { |
276
|
0
|
|
|
0
|
1
|
0
|
my ($self, $geom) = @_; |
277
|
0
|
|
|
|
|
0
|
return Geo::GDAL::FFI::OGR_G_Touches($$self, $$geom); |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
sub Crosses { |
281
|
0
|
|
|
0
|
1
|
0
|
my ($self, $geom) = @_; |
282
|
0
|
|
|
|
|
0
|
return Geo::GDAL::FFI::OGR_G_Crosses($$self, $$geom); |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
sub Within { |
286
|
0
|
|
|
0
|
1
|
0
|
my ($self, $geom) = @_; |
287
|
0
|
|
|
|
|
0
|
return Geo::GDAL::FFI::OGR_G_Within($$self, $$geom); |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
sub Contains { |
291
|
0
|
|
|
0
|
1
|
0
|
my ($self, $geom) = @_; |
292
|
0
|
|
|
|
|
0
|
return Geo::GDAL::FFI::OGR_G_Contains($$self, $$geom); |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
sub Overlaps { |
296
|
0
|
|
|
0
|
1
|
0
|
my ($self, $geom) = @_; |
297
|
0
|
|
|
|
|
0
|
return Geo::GDAL::FFI::OGR_G_Overlaps($$self, $$geom); |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
sub Boundary { |
301
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
302
|
0
|
|
|
|
|
0
|
return bless \Geo::GDAL::FFI::OGR_G_Boundary($$self), 'Geo::GDAL::FFI::Geometry'; |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
sub ConvexHull { |
306
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
307
|
0
|
|
|
|
|
0
|
return bless \Geo::GDAL::FFI::OGR_G_ConvexHull($$self), 'Geo::GDAL::FFI::Geometry'; |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
sub Buffer { |
311
|
0
|
|
|
0
|
1
|
0
|
my ($self, $dist, $quad_segs) = @_; |
312
|
0
|
|
|
|
|
0
|
return bless \Geo::GDAL::FFI::OGR_G_Buffer($$self, $dist, $quad_segs), 'Geo::GDAL::FFI::Geometry'; |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
sub Intersection { |
316
|
0
|
|
|
0
|
1
|
0
|
my ($self, $geom) = @_; |
317
|
0
|
0
|
|
|
|
0
|
confess "Undefined geometry." unless $geom; |
318
|
0
|
|
|
|
|
0
|
$self = Geo::GDAL::FFI::OGR_G_Intersection($$self, $$geom); |
319
|
0
|
0
|
|
|
|
0
|
confess Geo::GDAL::FFI::error_msg() unless $self; |
320
|
0
|
|
|
|
|
0
|
return bless \$self, 'Geo::GDAL::FFI::Geometry'; |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
sub Union { |
324
|
0
|
|
|
0
|
1
|
0
|
my ($self, $geom) = @_; |
325
|
0
|
0
|
|
|
|
0
|
confess "Undefined geometry." unless $geom; |
326
|
0
|
|
|
|
|
0
|
$self = Geo::GDAL::FFI::OGR_G_Union($$self, $$geom); |
327
|
0
|
0
|
|
|
|
0
|
confess Geo::GDAL::FFI::error_msg() unless $self; |
328
|
0
|
|
|
|
|
0
|
return bless \$self, 'Geo::GDAL::FFI::Geometry'; |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
sub Difference { |
332
|
0
|
|
|
0
|
1
|
0
|
my ($self, $geom) = @_; |
333
|
0
|
0
|
|
|
|
0
|
confess "Undefined geometry." unless $geom; |
334
|
0
|
|
|
|
|
0
|
$self = Geo::GDAL::FFI::OGR_G_Difference($$self, $$geom); |
335
|
0
|
0
|
|
|
|
0
|
confess Geo::GDAL::FFI::error_msg() unless $self; |
336
|
0
|
|
|
|
|
0
|
return bless \$self, 'Geo::GDAL::FFI::Geometry'; |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
sub SymDifference { |
340
|
0
|
|
|
0
|
1
|
0
|
my ($self, $geom) = @_; |
341
|
0
|
0
|
|
|
|
0
|
confess "Undefined geometry." unless $geom; |
342
|
0
|
|
|
|
|
0
|
$self = Geo::GDAL::FFI::OGR_G_SymDifference($$self, $$geom); |
343
|
0
|
0
|
|
|
|
0
|
confess Geo::GDAL::FFI::error_msg() unless $self; |
344
|
0
|
|
|
|
|
0
|
return bless \$self, 'Geo::GDAL::FFI::Geometry'; |
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
sub Distance { |
348
|
0
|
|
|
0
|
1
|
0
|
my ($self, $geom) = @_; |
349
|
0
|
0
|
|
|
|
0
|
confess "Undefined geometry." unless $geom; |
350
|
0
|
|
|
|
|
0
|
return Geo::GDAL::FFI::OGR_G_Distance($$self, $$geom); |
351
|
|
|
|
|
|
|
} |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
sub Distance3D { |
354
|
0
|
|
|
0
|
1
|
0
|
my ($self, $geom) = @_; |
355
|
0
|
0
|
|
|
|
0
|
confess "Undefined geometry." unless $geom; |
356
|
0
|
|
|
|
|
0
|
return Geo::GDAL::FFI::OGR_G_Distance3D($$self, $$geom); |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
sub Length { |
360
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
361
|
0
|
|
|
|
|
0
|
return Geo::GDAL::FFI::OGR_G_Length($$self); |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
sub Area { |
365
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
366
|
0
|
|
|
|
|
0
|
return Geo::GDAL::FFI::OGR_G_Area($$self); |
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
sub Centroid { |
370
|
1
|
|
|
1
|
1
|
7
|
my ($self) = @_; |
371
|
1
|
|
|
|
|
4
|
my $centroid = Geo::GDAL::FFI::Geometry->new('Point'); |
372
|
1
|
|
|
|
|
26
|
Geo::GDAL::FFI::OGR_G_Centroid($$self, $$centroid); |
373
|
1
|
|
|
|
|
6
|
my $msg = Geo::GDAL::FFI::error_msg(); |
374
|
1
|
50
|
|
|
|
2
|
confess($msg) if $msg; |
375
|
1
|
|
|
|
|
3
|
return $centroid; |
376
|
|
|
|
|
|
|
} |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
sub Empty { |
379
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
380
|
0
|
|
|
|
|
0
|
Geo::GDAL::FFI::OGR_G_Empty($$self); |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub IsEmpty { |
384
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
385
|
0
|
|
|
|
|
0
|
return Geo::GDAL::FFI::OGR_G_IsEmpty($$self); |
386
|
|
|
|
|
|
|
} |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
sub IsValid { |
389
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
390
|
0
|
|
|
|
|
0
|
return Geo::GDAL::FFI::OGR_G_IsValid($$self); |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
sub IsSimple { |
394
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
395
|
0
|
|
|
|
|
0
|
return Geo::GDAL::FFI::OGR_G_IsSimple($$self); |
396
|
|
|
|
|
|
|
} |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
sub IsRing { |
399
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
400
|
0
|
|
|
|
|
0
|
return Geo::GDAL::FFI::OGR_G_IsRing($$self); |
401
|
|
|
|
|
|
|
} |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
sub GetEnvelope { |
404
|
1
|
|
|
1
|
1
|
8
|
my ($self) = @_; |
405
|
1
|
|
|
|
|
3
|
my $envelope = [0,0,0,0]; |
406
|
1
|
|
|
|
|
20
|
Geo::GDAL::FFI::OGR_G_GetEnvelope ($$self, $envelope); |
407
|
1
|
|
|
|
|
3
|
return $envelope; |
408
|
|
|
|
|
|
|
} |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
sub GetEnvelope3D { |
411
|
1
|
|
|
1
|
1
|
566
|
my ($self) = @_; |
412
|
1
|
|
|
|
|
3
|
my $envelope = [0,0,0,0,0,0]; |
413
|
1
|
|
|
|
|
9
|
Geo::GDAL::FFI::OGR_G_GetEnvelope3D ($$self, $envelope); |
414
|
1
|
|
|
|
|
3
|
return $envelope; |
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
1; |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
=pod |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
=encoding UTF-8 |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
=head1 NAME |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
Geo::GDAL::FFI::Geometry - A GDAL geometry |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
=head1 SYNOPSIS |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
=head1 DESCRIPTION |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
=head1 METHODS |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
=head2 new |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
my $geom = Geo::GDAL::FFI::Geometry->new($geometry_type); |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
$type must be one of Geo::GDAL::FFI::GeometryTypes(). |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
my $geom = Geo::GDAL::FFI::Geometry->new($format, $arg, $sr); |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
$format must be one of Geo::GDAL::FFI::GeometryFormats(), e.g., 'WKT'. |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
$sr should be a SpatialRef object if given. |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
=head2 Clone |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
my $geom2 = $geom1->Clone; |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
Clones this geometry and returns the clone. |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
=head2 GetType |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
my $type = $geom->GetType($mode); |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
Returns the type of this geometry. If $mode (optional) is 'flatten', |
457
|
|
|
|
|
|
|
returns the type without Z, M, or ZM postfix. |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
=head2 GetPointCount |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
Returns the point count of this geometry. |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
=head2 SetPoint |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
$point->SetPoint($x, $y, $z, $m); |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
Set the coordinates of a point geometry. The usage of $z and $m in the |
468
|
|
|
|
|
|
|
method depend on the actual 3D or measured status of the point. |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
$point->SetPoint([$x, $y, $z, $m]); |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
Set the coordinates of a point geometry. The usage of $z and $m in the |
473
|
|
|
|
|
|
|
method depend on the actual 3D or measured status of the geometry. |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
$geom->SetPoint($i, $x, $y, $z, $m); |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
Set the coordinates of the ith (zero based index) point in a curve |
478
|
|
|
|
|
|
|
geometry. The usage of $z and $m in the method depend on the actual 3D |
479
|
|
|
|
|
|
|
or measured status of the geometry. |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
Note that setting the nth point of a curve creates all points 0..n-2 |
482
|
|
|
|
|
|
|
unless they exist. |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
$geom->SetPoint($i, $coords); |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
Set the coordinates of the ith (zero based index) point in this |
487
|
|
|
|
|
|
|
curve. $coords must be a reference to an array of the coordinates. The |
488
|
|
|
|
|
|
|
usage of $z and $m in the method depend on the 3D or measured status |
489
|
|
|
|
|
|
|
of the geometry. |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
Note that setting the nth point of a curve may create all points |
492
|
|
|
|
|
|
|
0..n-2. |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
=head2 GetPoint |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
my $coords = $geom->GetPoint($i); |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
Get the coordinates of the ith (zero based index) point in this |
499
|
|
|
|
|
|
|
curve. This method can also be used to set the coordinates of a point |
500
|
|
|
|
|
|
|
geometry and then the $i must be zero if it is given. |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
Returns the coordinates either as a list or a reference to an |
503
|
|
|
|
|
|
|
anonymous array depending on the context. The coordinates contain $z |
504
|
|
|
|
|
|
|
and $m depending on the 3D or measured status of the geometry. |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
=head2 GetPoints |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
my $points = $geom->GetPoints; |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
Returns the coordinates of the vertices of this geometry in an obvious |
511
|
|
|
|
|
|
|
array based data structure. Note that different geometry types have |
512
|
|
|
|
|
|
|
similar data structures. |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
=head2 SetPoints |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
$geom->SetPoints($points); |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
Sets the coordinates of the vertices of this geometry from an obvious |
519
|
|
|
|
|
|
|
array based data structure. Note that different geometry types may |
520
|
|
|
|
|
|
|
have similar data structures. If the geometry contains subgeometries |
521
|
|
|
|
|
|
|
(like polygon contains rings for example), the data structure is |
522
|
|
|
|
|
|
|
assumed to adhere to this structure. Uses SetPoint and may thus add |
523
|
|
|
|
|
|
|
points to curves. |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
=head2 GetGeometryCount |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
my $num_geometries = $geom->GetGeometryCount; |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
=head2 GetGeometry |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
my $outer_ring = $polygon->GetGeometry(0); |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
Returns the ith subgeometry (zero based index) in this geometry. The |
534
|
|
|
|
|
|
|
returned geometry object is only a wrapper to the underlying C++ |
535
|
|
|
|
|
|
|
reference and thus changing that geometry will change the parent. |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
=head2 AddGeometry |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
$polygon->AddGeometry($ring); |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
=head2 RemoveGeometry |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
$geom->RemoveGeometry($i); |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
=head2 ExportToWKT($variant) |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
my $wkt = $geom->ExportToWKT($variant); |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
Returns the geometry as WKT. $variant is optional (default is 'ISO'). |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
=head2 AsText |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
Alias to ExportToWKT. |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
=head2 ExportToGML($options) |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
my $gml = $geom->ExportToGML(%options); |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
Returns the geometry as GML string. %options may contain options as |
560
|
|
|
|
|
|
|
described in GDAL documentation. |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
=head2 ExportToJSON($options) |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
my $json = $geom->ExportToJSON(%options); |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
Returns the geometry as JSON string. %options may contain options as |
567
|
|
|
|
|
|
|
described in GDAL documentation. |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
=head2 Intersects |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
=head2 Equals |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
=head2 Disjoint |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
=head2 Touches |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
=head2 Crosses |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
=head2 Within |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
=head2 Contains |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
=head2 Overlaps |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
=head2 Boundary |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
=head2 ConvexHull |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
=head2 Buffer |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
=head2 Intersection |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
=head2 Union |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
=head2 Difference |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
=head2 SymDifference |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
=head2 Distance |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
=head2 Distance3D |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
=head2 Length |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
=head2 Area |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
=head2 Centroid |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
=head2 Empty |
610
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
=head2 IsEmpty |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
=head2 IsValid |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
=head2 IsSimple |
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
=head2 IsRing |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
=head2 GetEnvelope |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
Returns a four element array reference containing |
622
|
|
|
|
|
|
|
[Xmin, Xmax, Ymin, Ymax]. |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
=head2 GetEnvelope3D |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
Returns a six element array reference containing |
627
|
|
|
|
|
|
|
[Xmin, Xmax, Ymin, Ymax, Zmin, Zmax]. |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
=head1 LICENSE |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
This software is released under the Artistic License. See |
633
|
|
|
|
|
|
|
L. |
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
=head1 AUTHOR |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
Ari Jolma - Ari.Jolma at gmail.com |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
=head1 SEE ALSO |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
L |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
L, L, L |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
=cut |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
__END__; |