line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Geo::Ov2; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our @ISA = qw(IO::File); |
4
|
|
|
|
|
|
|
|
5
|
1
|
|
|
1
|
|
29156
|
use warnings; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
39
|
|
6
|
1
|
|
|
1
|
|
5
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
42
|
|
7
|
|
|
|
|
|
|
require IO::File; |
8
|
1
|
|
|
1
|
|
5
|
use Carp; |
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
120
|
|
9
|
1
|
|
|
1
|
|
1006
|
use POSIX; |
|
1
|
|
|
|
|
9943
|
|
|
1
|
|
|
|
|
9
|
|
10
|
1
|
|
|
1
|
|
8159
|
use locale; |
|
1
|
|
|
|
|
326
|
|
|
1
|
|
|
|
|
7
|
|
11
|
1
|
|
|
1
|
|
1153
|
use Locale::TextDomain 'net.suteren.POI.todevice'; |
|
1
|
|
|
|
|
33190
|
|
|
1
|
|
|
|
|
9
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 NAME |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
Geo::Ov2 - Library for reading and writing TomTom Navigator .ov2 POI files. |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
Extends L |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 VERSION |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
Version 0.91 |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=cut |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
our $VERSION = '0.91'; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
our %defaults = ( repart_size=> 10, repartition => 1, deareize => 0 ); |
29
|
|
|
|
|
|
|
our %params; |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
=head1 SYNOPSIS |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
Because this is a child of L, all functions of L are accessibe. No overriding is done. |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
The core of this module is done by two main methods poiread and poiwrite. |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
There are also another supporting functions, such as area_envelope, deareizator, split_area which works with ov2 record 0x01 - area and makes TTN working faster. |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
The third sort of methods are getters/setters, which controls behavior of the module. These are deareize, repartition and repart_size. |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
And at the end thera are poireadall and poiwriteall, which reads and writes array of pois. Poiwriteall do also rearealization, if repartition flag is set and stripes original 0x01 records if deareize flag is set. |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
Perhaps a little code snippet. |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
use Geo::Ov2; |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
my $ov2 = Geo::Ov2->new( "
|
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
while ( my $poi = $ov2->poiread() ) { |
50
|
|
|
|
|
|
|
printf "type: %d; longitude: %f; latitude: %f; description: %s\n", ${$poi}{type}, ${$poi}{longitude}, ${$poi}{latitude}, ${$poi}{description}; |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
my @pois = @{$ov2->poireadall()}; |
54
|
|
|
|
|
|
|
foreach $poi (@pois) { |
55
|
|
|
|
|
|
|
printf "type: %d; longitude: %f; latitude: %f; description: %s\n", ${$poi}{type}, ${$poi}{longitude}, ${$poi}{latitude}, ${$poi}{description}; |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
$ov2->poiwrite( { type => 2, longitude => 4000000, latitude => 1200000, descrption => "my POI" } ); |
59
|
|
|
|
|
|
|
$ov2->poiwriteall( @pois ); |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
@pois = @{$self->deareizator( @pois )}; |
62
|
|
|
|
|
|
|
@pois = @{$self->split_area( 0, @pois )}; |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=head1 EXPORT |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
A list of functions that can be exported. You can delete this section |
67
|
|
|
|
|
|
|
if you don't export anything, such as for a purely object-oriented module. |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
=head1 FUNCTIONS |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=head2 _params |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
This is an internal function, which allows set and get parameters for each instance. This is required because of parrent L uses fle descriptor as $self, so it can not be used for storing other data. |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=cut |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
sub _params { |
78
|
0
|
|
|
0
|
|
|
my $self = shift; |
79
|
0
|
|
|
|
|
|
my $params = shift; |
80
|
0
|
0
|
|
|
|
|
$params{$self} = $params if defined $params; |
81
|
0
|
0
|
|
|
|
|
$params{$self} = {} unless exists $params{$self}; |
82
|
0
|
|
|
|
|
|
return $params{$self}; |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
=head2 deareize |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
This is a getter and setter of deareize flag for specific instance of object. |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=cut |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub deareize { |
92
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
93
|
0
|
|
|
|
|
|
return $self->_param( "deareize", $_[0] ); |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
=head2 repartition |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
This is a getter and setter of repartition flag for specific instance of object. |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=cut |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
sub repartition { |
103
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
104
|
0
|
|
|
|
|
|
return $self->_param( "repartition", $_[0] ); |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=head2 repart_size |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
This is a getter and setter of repart_size value for specific instance of object. |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=cut |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub repart_size { |
114
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
115
|
0
|
|
|
|
|
|
return $self->_param( "repart_size", $_[0] ); |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=head2 _param |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
This is an internal function, which allows set and get parameters for each instance. This is required because of parrent L uses fle descriptor as $self, so it can not be used for storing other data. |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=cut |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
sub _param { |
125
|
0
|
|
|
0
|
|
|
my $self = shift; |
126
|
0
|
|
|
|
|
|
my $key = shift; |
127
|
0
|
0
|
|
|
|
|
croak __"undefined parameter." unless defined $key; |
128
|
0
|
|
|
|
|
|
my $new_value = shift; |
129
|
0
|
|
|
|
|
|
my %params = %{$self->_params}; |
|
0
|
|
|
|
|
|
|
130
|
0
|
0
|
|
|
|
|
if ( defined $new_value ) { |
131
|
0
|
|
|
|
|
|
$params{$key} = $new_value; |
132
|
0
|
|
|
|
|
|
$self->_params( \%params ); |
133
|
|
|
|
|
|
|
} |
134
|
0
|
0
|
|
|
|
|
unless ( defined $params{$key} ) { |
135
|
0
|
|
|
|
|
|
$params{$key} = $defaults{$key}; |
136
|
0
|
|
|
|
|
|
$self->_params( \%params ); |
137
|
|
|
|
|
|
|
} |
138
|
0
|
|
|
|
|
|
return $params{$key}; |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=head2 poiwrite |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
This method writes data referenced by hashref into ov2 file. |
144
|
|
|
|
|
|
|
if "data" atribute is provided, it is written into a file, otherwise method pack data supplied in other attributes, fills "data" attribude and then it is written. |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
=head3 input |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
inpus is a hashref, which has following structure: |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
{ |
151
|
|
|
|
|
|
|
type => 2, |
152
|
|
|
|
|
|
|
longitude => 5000000, |
153
|
|
|
|
|
|
|
latitude => 1100000, |
154
|
|
|
|
|
|
|
description => "some text", |
155
|
|
|
|
|
|
|
data => "packed above data into binary form of ov2" |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
=cut |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
sub poiwrite { |
161
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
162
|
0
|
|
|
|
|
|
my $poi = shift; |
163
|
0
|
|
|
|
|
|
my %poi = %$poi; |
164
|
0
|
|
|
|
|
|
my $data = $poi{data}; |
165
|
0
|
0
|
|
|
|
|
unless ( exists $poi{data} ) { |
166
|
0
|
|
|
|
|
|
my $type = $poi{type}; |
167
|
0
|
|
|
|
|
|
my $longitude = $poi{longitude}; |
168
|
0
|
|
|
|
|
|
my $latitude = $poi{latitude}; |
169
|
0
|
0
|
0
|
|
|
|
if ( $type == 0x01 ) { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
170
|
0
|
|
|
|
|
|
my $longitude2 = $poi{longitude2}; |
171
|
0
|
|
|
|
|
|
my $latitude2 = $poi{latitude2}; |
172
|
0
|
|
|
|
|
|
my $size = $poi{size}; |
173
|
0
|
|
|
|
|
|
$data = pack "CVVVVV", $type, $size, $longitude, $latitude, |
174
|
|
|
|
|
|
|
$longitude2, $latitude2; |
175
|
|
|
|
|
|
|
} elsif ( $type == 0x02 ) { |
176
|
0
|
|
|
|
|
|
my $description = $poi{description}; |
177
|
0
|
|
|
|
|
|
$data = pack "CVVV", $type, 13 + lenght $description, $latitude, |
178
|
|
|
|
|
|
|
$longitude; |
179
|
0
|
|
|
|
|
|
$data = $data . $description; |
180
|
|
|
|
|
|
|
} elsif ( $type == 0x04 ) { |
181
|
0
|
|
|
|
|
|
$data = pack "C", $type; |
182
|
0
|
|
|
|
|
|
$data = $data . substr( pack( "V", $longitude ), 1 ); |
183
|
0
|
|
|
|
|
|
$data = $data . substr( pack( "V", $latitude ), 1 ); |
184
|
|
|
|
|
|
|
} elsif ( $type == 0x05 or $type == 0x15 ) { |
185
|
0
|
|
|
|
|
|
my $description = $poi{description}; |
186
|
0
|
|
|
|
|
|
$data = pack "C", $type; |
187
|
0
|
|
|
|
|
|
$data = $data . substr( pack( "V", $longitude ), 1 ); |
188
|
0
|
|
|
|
|
|
$data = $data . substr( pack( "V", $latitude ), 1 ); |
189
|
0
|
|
|
|
|
|
$data = $data . substr( $description, 0, 2 ); # TODO |
190
|
|
|
|
|
|
|
} elsif ( $type == 0x06 ) { |
191
|
0
|
|
|
|
|
|
my $description = $poi{description}; |
192
|
0
|
|
|
|
|
|
$data = pack "C", $type; |
193
|
0
|
|
|
|
|
|
$data = $data . substr( pack( "V", $longitude ), 1 ); |
194
|
0
|
|
|
|
|
|
$data = $data . substr( pack( "V", $latitude ), 1 ); |
195
|
0
|
|
|
|
|
|
$data = $data . substr( $description, 0, 3 ); # TODO |
196
|
|
|
|
|
|
|
} elsif ( $type == 0x07 |
197
|
|
|
|
|
|
|
or $type == 0x08 |
198
|
|
|
|
|
|
|
or $type == 0x18 |
199
|
|
|
|
|
|
|
or $type == 0x09 |
200
|
|
|
|
|
|
|
or $type == 0x19 |
201
|
|
|
|
|
|
|
or $type == 0x0a |
202
|
|
|
|
|
|
|
or $type == 0x1a |
203
|
|
|
|
|
|
|
or $type == 0x0c ) |
204
|
|
|
|
|
|
|
{ |
205
|
0
|
|
|
|
|
|
my $description = $poi{description}; |
206
|
0
|
|
|
|
|
|
$data = pack "CC", $type, length $description; |
207
|
0
|
|
|
|
|
|
$data = $data . substr( pack( "V", $longitude ), 1 ); |
208
|
0
|
|
|
|
|
|
$data = $data . substr( pack( "V", $latitude ), 1 ); |
209
|
0
|
|
|
|
|
|
$data = $data . $description; |
210
|
|
|
|
|
|
|
} else { |
211
|
0
|
|
|
|
|
|
croak "Unknown type of POI."; |
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
} |
214
|
0
|
|
|
|
|
|
print {$self} $data; |
|
0
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
=head2 poiread |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
This method reads data from ov2 file and returns hashref into POI structure: |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
{ |
223
|
|
|
|
|
|
|
type => 2, |
224
|
|
|
|
|
|
|
longitude => 5000000, |
225
|
|
|
|
|
|
|
latitude => 1100000, |
226
|
|
|
|
|
|
|
description => "some text", |
227
|
|
|
|
|
|
|
data => "packed above data into binary form of ov2" |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=cut |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
sub poiread { |
233
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
234
|
0
|
|
|
|
|
|
my $res = read( $self, my $buff, 1); |
235
|
0
|
0
|
0
|
|
|
|
return undef unless $res and $res == 1; |
236
|
0
|
|
|
|
|
|
my $data = $buff; |
237
|
0
|
|
|
|
|
|
my $type = unpack "C", $buff; |
238
|
0
|
|
|
|
|
|
my %poi; |
239
|
0
|
0
|
0
|
|
|
|
if ( $type == 0x01 ) { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
240
|
0
|
0
|
|
|
|
|
read( $self, $buff, 20 ) == 20 |
241
|
|
|
|
|
|
|
or croak __"Unexpected end of ov2 file."; |
242
|
|
|
|
|
|
|
#next if $repartition; |
243
|
0
|
|
|
|
|
|
$data = $data . $buff; |
244
|
0
|
|
|
|
|
|
my ( $size, $longitude, $latitude, $longitude2, $latitude2 ) = |
245
|
|
|
|
|
|
|
unpack "VVVVV", $buff; |
246
|
0
|
|
|
|
|
|
%poi = ( |
247
|
|
|
|
|
|
|
type => $type, |
248
|
|
|
|
|
|
|
size => $size, |
249
|
|
|
|
|
|
|
longitude => $longitude, |
250
|
|
|
|
|
|
|
latitude => $latitude, |
251
|
|
|
|
|
|
|
longitude2 => $longitude2, |
252
|
|
|
|
|
|
|
latitude2 => $latitude2, |
253
|
|
|
|
|
|
|
data => $data |
254
|
|
|
|
|
|
|
); |
255
|
|
|
|
|
|
|
} elsif ( $type == 0x02 ) { |
256
|
0
|
0
|
|
|
|
|
read( $self, $buff, 4 ) == 4 |
257
|
|
|
|
|
|
|
or croak __"Unexpected end of ov2 file."; |
258
|
0
|
|
|
|
|
|
$data = $data . $buff; |
259
|
0
|
|
|
|
|
|
my $size = unpack "V", $buff; |
260
|
0
|
0
|
|
|
|
|
read( $self, $buff, 8 ) == 8 |
261
|
|
|
|
|
|
|
or croak __"Unexpected end of ov2 file."; |
262
|
0
|
|
|
|
|
|
$data = $data . $buff; |
263
|
0
|
|
|
|
|
|
my ( $longitude, $latitude ) = unpack "VV", $buff; |
264
|
0
|
0
|
|
|
|
|
read( $self, $buff, $size - 13 ) == $size - 13 |
265
|
|
|
|
|
|
|
or croak __"Unexpected end of ov2 file."; |
266
|
0
|
|
|
|
|
|
$data = $data . $buff; |
267
|
0
|
|
|
|
|
|
%poi = ( |
268
|
|
|
|
|
|
|
type => $type, |
269
|
|
|
|
|
|
|
size => $size, |
270
|
|
|
|
|
|
|
longitude => $longitude, |
271
|
|
|
|
|
|
|
latitude => $latitude, |
272
|
|
|
|
|
|
|
data => $data, |
273
|
|
|
|
|
|
|
description => $buff |
274
|
|
|
|
|
|
|
); |
275
|
|
|
|
|
|
|
} elsif ( $type == 0x04 ) { |
276
|
0
|
0
|
|
|
|
|
read( $self, $buff, 3 ) == 3 |
277
|
|
|
|
|
|
|
or croak __"Unexpected end of ov2 file."; |
278
|
0
|
|
|
|
|
|
$data = $data . $buff; |
279
|
0
|
|
|
|
|
|
my $tmp = "00" . $buff; |
280
|
0
|
0
|
|
|
|
|
read( $self, $buff, 3 ) == 3 |
281
|
|
|
|
|
|
|
or croak __"Unexpected end of ov2 file."; |
282
|
0
|
|
|
|
|
|
$data = $data . $buff; |
283
|
0
|
|
|
|
|
|
$tmp = $tmp . "00" . $buff; |
284
|
0
|
|
|
|
|
|
my ( $longitude, $latitude ) = unpack "VV", $tmp; |
285
|
0
|
|
|
|
|
|
%poi = ( |
286
|
|
|
|
|
|
|
type => $type, |
287
|
|
|
|
|
|
|
longitude => $longitude, |
288
|
|
|
|
|
|
|
latitude => $latitude, |
289
|
|
|
|
|
|
|
data => $data |
290
|
|
|
|
|
|
|
); |
291
|
|
|
|
|
|
|
} elsif ( $type == 0x05 or $type == 0x15 ) { |
292
|
0
|
0
|
|
|
|
|
read( $self, $buff, 3 ) == 3 |
293
|
|
|
|
|
|
|
or croak __"Unexpected end of ov2 file."; |
294
|
0
|
|
|
|
|
|
$data = $data . $buff; |
295
|
0
|
|
|
|
|
|
my $tmp = "00" . $buff; |
296
|
0
|
0
|
|
|
|
|
read( $self, $buff, 3 ) == 3 |
297
|
|
|
|
|
|
|
or croak __"Unexpected end of ov2 file."; |
298
|
0
|
|
|
|
|
|
$data = $data . $buff; |
299
|
0
|
|
|
|
|
|
$tmp = $tmp . "00" . $buff; |
300
|
0
|
|
|
|
|
|
my ( $longitude, $latitude ) = unpack "VV", $buff; |
301
|
0
|
0
|
|
|
|
|
read( $self, $buff, 2 ) == 2 |
302
|
|
|
|
|
|
|
or croak __"Unexpected end of ov2 file."; |
303
|
0
|
|
|
|
|
|
$data = $data . $buff; |
304
|
0
|
|
|
|
|
|
%poi = ( |
305
|
|
|
|
|
|
|
type => $type, |
306
|
|
|
|
|
|
|
longitude => $longitude, |
307
|
|
|
|
|
|
|
latitude => $latitude, |
308
|
|
|
|
|
|
|
data => $data, |
309
|
|
|
|
|
|
|
description => $buff |
310
|
|
|
|
|
|
|
); |
311
|
|
|
|
|
|
|
} elsif ( $type == 0x06 ) { |
312
|
0
|
0
|
|
|
|
|
read( $self, $buff, 3 ) == 3 |
313
|
|
|
|
|
|
|
or croak __"Unexpected end of ov2 file."; |
314
|
0
|
|
|
|
|
|
$data = $data . $buff; |
315
|
0
|
|
|
|
|
|
my $tmp = "00" . $buff; |
316
|
0
|
0
|
|
|
|
|
read( $self, $buff, 3 ) == 3 |
317
|
|
|
|
|
|
|
or croak __"Unexpected end of ov2 file."; |
318
|
0
|
|
|
|
|
|
$data = $data . $buff; |
319
|
0
|
|
|
|
|
|
$tmp = $tmp . "00" . $buff; |
320
|
0
|
|
|
|
|
|
my ( $longitude, $latitude ) = unpack "VV", $buff; |
321
|
0
|
0
|
|
|
|
|
read( $self, $buff, 3 ) == 3 |
322
|
|
|
|
|
|
|
or croak __"Unexpected end of ov2 file."; |
323
|
0
|
|
|
|
|
|
$data = $data . $buff; |
324
|
0
|
|
|
|
|
|
%poi = ( |
325
|
|
|
|
|
|
|
type => $type, |
326
|
|
|
|
|
|
|
longitude => $longitude, |
327
|
|
|
|
|
|
|
latitude => $latitude, |
328
|
|
|
|
|
|
|
description => $buff, |
329
|
|
|
|
|
|
|
data => $data |
330
|
|
|
|
|
|
|
); |
331
|
|
|
|
|
|
|
} elsif ( $type == 0x07 |
332
|
|
|
|
|
|
|
or $type == 0x08 |
333
|
|
|
|
|
|
|
or $type == 0x18 |
334
|
|
|
|
|
|
|
or $type == 0x09 |
335
|
|
|
|
|
|
|
or $type == 0x19 |
336
|
|
|
|
|
|
|
or $type == 0x0a |
337
|
|
|
|
|
|
|
or $type == 0x1a |
338
|
|
|
|
|
|
|
or $type == 0x0c ) |
339
|
|
|
|
|
|
|
{ |
340
|
0
|
0
|
|
|
|
|
read( $self, $buff, 1 ) == 1 |
341
|
|
|
|
|
|
|
or croak __"Unexpected end of ov2 file."; |
342
|
0
|
|
|
|
|
|
$data = $data . $buff; |
343
|
0
|
|
|
|
|
|
my $size = unpack "C", $buff; |
344
|
0
|
0
|
|
|
|
|
read( $self, $buff, 3 ) == 3 |
345
|
|
|
|
|
|
|
or croak __"Unexpected end of ov2 file."; |
346
|
0
|
|
|
|
|
|
$data = $data . $buff; |
347
|
0
|
|
|
|
|
|
my $tmp = "00" . $buff; |
348
|
0
|
0
|
|
|
|
|
read( $self, $buff, 3 ) == 3 |
349
|
|
|
|
|
|
|
or croak __"Unexpected end of ov2 file."; |
350
|
0
|
|
|
|
|
|
$data = $data . $buff; |
351
|
0
|
|
|
|
|
|
$tmp = $tmp . "00" . $buff; |
352
|
0
|
|
|
|
|
|
my ( $longitude, $latitude ) = unpack "VV", $buff; |
353
|
0
|
0
|
|
|
|
|
read( $self, $buff, $size ) == $size |
354
|
|
|
|
|
|
|
or croak __"Unexpected end of ov2 file."; |
355
|
0
|
|
|
|
|
|
$data = $data . $buff; |
356
|
0
|
|
|
|
|
|
%poi = ( |
357
|
|
|
|
|
|
|
type => $type, |
358
|
|
|
|
|
|
|
size => $size, |
359
|
|
|
|
|
|
|
longitude => $longitude, |
360
|
|
|
|
|
|
|
latitude => $latitude, |
361
|
|
|
|
|
|
|
description => $buff, |
362
|
|
|
|
|
|
|
data => $data |
363
|
|
|
|
|
|
|
); |
364
|
|
|
|
|
|
|
} else { |
365
|
0
|
|
|
|
|
|
croak __"Unknown type of POI."; |
366
|
|
|
|
|
|
|
} |
367
|
0
|
|
|
|
|
|
return \%poi; |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
=head2 poiwriteall |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
Method gets array of hashrefs into POIs and writes it into ov2 file. |
373
|
|
|
|
|
|
|
When deareize is set, it also strips all 0x01 records (area) befor writting. |
374
|
|
|
|
|
|
|
When repartition is set, it does deareize and then it creates own area structure for POIs in array. Then all it is written to ov2 file. |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
=cut |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
sub poiwriteall { |
379
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
380
|
0
|
|
|
|
|
|
my @pois = @_; |
381
|
|
|
|
|
|
|
#printf STDERR "%d %d\n", $self->repartition, $self->deareize; |
382
|
0
|
0
|
0
|
|
|
|
@pois = @{$self->deareizator( @pois )} if ( $self->repartition or $self->deareize ); |
|
0
|
|
|
|
|
|
|
383
|
0
|
0
|
|
|
|
|
@pois = @{$self->split_area( 0, @pois )} if $self->repartition; |
|
0
|
|
|
|
|
|
|
384
|
0
|
|
|
|
|
|
foreach my $poi (@pois) { |
385
|
0
|
|
|
|
|
|
$self->poiwrite($poi); |
386
|
|
|
|
|
|
|
} |
387
|
|
|
|
|
|
|
} |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
=head2 poireadall |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
This method reads the whole ov2 file and returns array of hashrefs into POI structures. |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
=cut |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
sub poireadall { |
396
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
397
|
0
|
|
|
|
|
|
my @pois; |
398
|
0
|
|
|
|
|
|
while ( my $poi = $self->poiread() ) { |
399
|
0
|
|
|
|
|
|
my %poi = %$poi; |
400
|
0
|
|
|
|
|
|
push @pois, \%poi; |
401
|
|
|
|
|
|
|
} |
402
|
0
|
|
|
|
|
|
return \@pois; |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
=head2 area_envelope |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
This method expects array of hashrefs into POIs and returns structure of 0x01 record, which is area for these POIs. |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
=cut |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
sub area_envelope { |
412
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
413
|
0
|
|
|
|
|
|
my @pois = @_; |
414
|
0
|
|
|
|
|
|
my ( $longitude2, $longitude, $latitude2, $latitude ) = ( undef, undef, undef, undef ); |
415
|
0
|
|
|
|
|
|
my $size = 0; |
416
|
0
|
|
|
|
|
|
my $atleastone = 0; |
417
|
0
|
|
|
|
|
|
foreach my $i (@pois) { |
418
|
0
|
|
|
|
|
|
my %poi = %$i; |
419
|
0
|
|
|
|
|
|
$atleastone = 1; |
420
|
0
|
0
|
|
|
|
|
$longitude2 = $poi{longitude} unless defined $longitude2; |
421
|
0
|
0
|
|
|
|
|
$longitude = $poi{longitude} unless defined $longitude; |
422
|
0
|
0
|
|
|
|
|
$latitude2 = $poi{latitude} unless defined $latitude2; |
423
|
0
|
0
|
|
|
|
|
$latitude = $poi{latitude} unless defined $latitude; |
424
|
0
|
0
|
|
|
|
|
$longitude2 = $poi{longitude} if $poi{longitude} < $longitude2; |
425
|
0
|
0
|
|
|
|
|
$latitude2 = $poi{latitude} if $poi{latitude} < $latitude2; |
426
|
0
|
0
|
|
|
|
|
$longitude = $poi{longitude} if $poi{longitude} > $longitude; |
427
|
0
|
0
|
|
|
|
|
$latitude = $poi{latitude} if $poi{latitude} > $latitude; |
428
|
0
|
|
|
|
|
|
my $type = $poi{type}; |
429
|
0
|
0
|
0
|
|
|
|
if ( $type == 0x01 ) { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
430
|
0
|
|
|
|
|
|
$size += 21; |
431
|
|
|
|
|
|
|
} elsif ( $type == 0x02 ) { |
432
|
0
|
0
|
|
|
|
|
$poi{size} = 13 + length $poi{description} unless $poi{size}; |
433
|
0
|
|
|
|
|
|
$size += $poi{size}; |
434
|
|
|
|
|
|
|
} elsif ( $type == 0x04 ) { |
435
|
0
|
|
|
|
|
|
$size += 7; |
436
|
|
|
|
|
|
|
} elsif ( $type == 0x05 or $type == 0x15 ) { |
437
|
0
|
|
|
|
|
|
$size += 9; |
438
|
|
|
|
|
|
|
} elsif ( $type == 0x06 ) { |
439
|
0
|
|
|
|
|
|
$size += 10; |
440
|
|
|
|
|
|
|
} elsif ( $type == 0x07 |
441
|
|
|
|
|
|
|
or $type == 0x08 |
442
|
|
|
|
|
|
|
or $type == 0x18 |
443
|
|
|
|
|
|
|
or $type == 0x09 |
444
|
|
|
|
|
|
|
or $type == 0x19 |
445
|
|
|
|
|
|
|
or $type == 0x0a |
446
|
|
|
|
|
|
|
or $type == 0x1a |
447
|
|
|
|
|
|
|
or $type == 0x0c ) |
448
|
|
|
|
|
|
|
{ |
449
|
0
|
0
|
|
|
|
|
$poi{size} = length $poi{description} unless $poi{size}; |
450
|
0
|
|
|
|
|
|
$size += $poi{size} + 8; |
451
|
|
|
|
|
|
|
} else { |
452
|
0
|
|
|
|
|
|
croak __"Unknown type of POI."; |
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
} |
455
|
0
|
|
|
|
|
|
$size += 21; |
456
|
0
|
|
|
|
|
|
my $data = ""; |
457
|
0
|
0
|
|
|
|
|
$data = pack( "CVVVVV", 1, $size, $longitude, $latitude, $longitude2, $latitude2 ) if $atleastone; |
458
|
0
|
0
|
|
|
|
|
$size = 21 if $atleastone; |
459
|
0
|
|
|
|
|
|
my %poi = ( type => 1, size => $size, longitude => $longitude, latitude => $latitude, longitude2 => $longitude2, latitude2 => $latitude2, data => $data ); |
460
|
|
|
|
|
|
|
#printf "debug: %d %d %d %d\n", $longitude, $latitude, $longitude2, $latitude2; |
461
|
0
|
|
|
|
|
|
return \%poi; |
462
|
|
|
|
|
|
|
} |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
=head2 deareizator |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
This method expects array of POI hashrefs on input and rturns reference to array which is copy of source array, but without 0x01 records. |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
=cut |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
sub deareizator { |
471
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
472
|
0
|
|
|
|
|
|
my @pois = @_; |
473
|
0
|
|
|
|
|
|
my @poiout; |
474
|
0
|
|
|
|
|
|
foreach my $i ( @pois ) { |
475
|
0
|
0
|
|
|
|
|
if ( ${$i}{type} != 1 ) { |
|
0
|
|
|
|
|
|
|
476
|
0
|
|
|
|
|
|
push @poiout, \%{$i} |
|
0
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
} |
478
|
|
|
|
|
|
|
} |
479
|
0
|
|
|
|
|
|
return \@poiout; |
480
|
|
|
|
|
|
|
} |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
=head2 split_area |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
On input is array of POI hashrefs. This array must be without 0x01 records - use deareizator. |
485
|
|
|
|
|
|
|
Output is reference to array which contains POIs organized into tree of areas. |
486
|
|
|
|
|
|
|
This can significantly improve speed of displaying POIs in TTN. |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
=cut |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
sub split_area { |
491
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
492
|
0
|
|
|
|
|
|
my $orientation = shift; |
493
|
0
|
|
|
|
|
|
my @pois = @_; |
494
|
0
|
|
|
|
|
|
$orientation++; |
495
|
|
|
|
|
|
|
#@pois = @{_sortpois( $orientation, @pois)}; |
496
|
0
|
|
|
|
|
|
my $dimension = "longitude"; |
497
|
0
|
0
|
|
|
|
|
$dimension = "latitude" if $orientation % 2; |
498
|
0
|
|
|
|
|
|
@pois = sort { ${$a}{$dimension} <=> ${$b}{$dimension} } @pois; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
=pod |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
foreach my $i ( @pois ) { |
503
|
|
|
|
|
|
|
printf STDERR "sort: %s: %d\n", $dimension, ${$i}{$dimension}; |
504
|
|
|
|
|
|
|
} |
505
|
|
|
|
|
|
|
printf STDERR "========================\n"; |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
=cut |
508
|
0
|
|
|
|
|
|
my $blocksize = ( ( $#pois + 1 ) / ( $self->repart_size - 1 ) ) + 1; |
509
|
0
|
0
|
0
|
|
|
|
if ( $#pois > $self->repart_size and $orientation < 10 ) { |
510
|
0
|
|
|
|
|
|
my @poiout; |
511
|
0
|
|
|
|
|
|
my $i = 0; |
512
|
0
|
|
|
|
|
|
while ( ( $i + $blocksize - 1 ) <= $#pois ) { |
513
|
0
|
|
|
|
|
|
my $tmp = $i; |
514
|
0
|
|
|
|
|
|
$i += $blocksize; |
515
|
0
|
|
|
|
|
|
my @tmp = @pois[$tmp .. $i - 1 ]; |
516
|
0
|
|
|
|
|
|
my $pois = $self->split_area($orientation, @tmp ); |
517
|
0
|
|
|
|
|
|
push @poiout, @$pois; |
518
|
|
|
|
|
|
|
} |
519
|
0
|
0
|
|
|
|
|
if ( $i < $#pois + 1) { |
520
|
0
|
|
|
|
|
|
my @tmp = @pois[$i .. $#pois]; |
521
|
0
|
|
|
|
|
|
my $pois = $self->split_area($orientation, @tmp ); |
522
|
0
|
|
|
|
|
|
push @poiout, @$pois; |
523
|
|
|
|
|
|
|
} |
524
|
0
|
|
|
|
|
|
@pois = @poiout; |
525
|
|
|
|
|
|
|
} |
526
|
0
|
|
|
|
|
|
my %poi = %{$self->area_envelope( @pois )}; |
|
0
|
|
|
|
|
|
|
527
|
0
|
|
|
|
|
|
unshift @pois, \%poi; |
528
|
0
|
|
|
|
|
|
return \@pois; |
529
|
|
|
|
|
|
|
} |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
=head1 SEE ALSO |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
L, |
534
|
|
|
|
|
|
|
L, |
535
|
|
|
|
|
|
|
L, |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
=head1 AUTHOR |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
Petr Vranik, C<< >> |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
=head1 BUGS |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
Please report any bugs or feature requests to |
544
|
|
|
|
|
|
|
C, or through the web interface at |
545
|
|
|
|
|
|
|
L. |
546
|
|
|
|
|
|
|
I will be notified, and then you'll automatically be notified of progress on |
547
|
|
|
|
|
|
|
your bug as I make changes. |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
=head1 TODO |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
=over 4 |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
=item 1) Implement reading and writing poi.dat |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
It means operating in two modes. In mode of ov2 behavior stays the same as now. In poi.dat mode it will return hash of arrays on read and expect hash of arrays on write. The top level hash will contain categories and in each category there will be array of POIs, as returned nowadays. |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
=item 2) Make Czech translations of README and INSTALL. |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
=item 3) Implement seekability on POI basis. |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
=item 4) Implement other IO::File methods on POI basis. |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
=back |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
=head1 SUPPORT |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
perldoc Geo::Ov2 |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
You can also look for information at: |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
=over 4 |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
=item * AnnoCPAN: Annotated CPAN documentation |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
L |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
=item * CPAN Ratings |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
L |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
=item * RT: CPAN's request tracker |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
L |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
=item * Search CPAN |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
L |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
=back |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
Copyright 2007 Petr Vranik, all rights reserved. |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
600
|
|
|
|
|
|
|
under the same terms as Perl itself. |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
=cut |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
1; # End of Geo::Ov2 |