line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# Encoding and name #_{ |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=encoding utf8 |
4
|
|
|
|
|
|
|
=head1 NAME |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
Geo::OSM::Render::Renderer::SVG - Specialization of base class L for rendering SVG. |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
=cut |
9
|
|
|
|
|
|
|
package Geo::OSM::Render::Renderer::SVG; |
10
|
|
|
|
|
|
|
#_} |
11
|
|
|
|
|
|
|
#_{ use … |
12
|
2
|
|
|
2
|
|
79576
|
use warnings; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
71
|
|
13
|
2
|
|
|
2
|
|
12
|
use strict; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
47
|
|
14
|
|
|
|
|
|
|
|
15
|
2
|
|
|
2
|
|
501
|
use utf8; |
|
2
|
|
|
|
|
19
|
|
|
2
|
|
|
|
|
9
|
|
16
|
2
|
|
|
2
|
|
51
|
use Carp; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
117
|
|
17
|
|
|
|
|
|
|
|
18
|
2
|
|
|
2
|
|
947
|
use SVG; |
|
2
|
|
|
|
|
32465
|
|
|
2
|
|
|
|
|
16
|
|
19
|
2
|
|
|
2
|
|
3997
|
use Geo::OSM::Render::Renderer; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
1357
|
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
#_} |
22
|
|
|
|
|
|
|
our $VERSION = 0.01; |
23
|
|
|
|
|
|
|
our @ISA = qw(Geo::OSM::Render::Renderer); |
24
|
|
|
|
|
|
|
#_{ Synopsis |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=head1 SYNOPSIS |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=cut |
30
|
|
|
|
|
|
|
#_} |
31
|
|
|
|
|
|
|
#_{ Overview |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
=head1 OVERVIEW |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
… |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
=cut |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
#_} |
40
|
|
|
|
|
|
|
#_{ Methods |
41
|
|
|
|
|
|
|
#_{ POD |
42
|
|
|
|
|
|
|
=head1 METHODS |
43
|
|
|
|
|
|
|
=cut |
44
|
|
|
|
|
|
|
#_} |
45
|
|
|
|
|
|
|
sub new { #_{ |
46
|
|
|
|
|
|
|
#_{ POD |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=head2 new |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
my $proj = Geo::OSM::Render::Projection::CH_LV03->new(); |
51
|
|
|
|
|
|
|
my $vp = Geo::OSM::Render::Viewport::Clipped->new(…); |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
my $osm_renderer_svg = Geo::OSM::Render::Renderer->new( |
54
|
|
|
|
|
|
|
$svg_filename, |
55
|
|
|
|
|
|
|
$proj, |
56
|
|
|
|
|
|
|
$vp |
57
|
|
|
|
|
|
|
); |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
… |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
$osm_renderer_svg->end(); |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=cut |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
#_} |
66
|
|
|
|
|
|
|
|
67
|
1
|
|
|
1
|
1
|
16
|
my $class = shift; |
68
|
1
|
|
|
|
|
3
|
my $svg_filename = shift; |
69
|
|
|
|
|
|
|
|
70
|
1
|
|
|
|
|
12
|
my $self = $class->SUPER::new(@_); |
71
|
|
|
|
|
|
|
|
72
|
1
|
50
|
|
|
|
6
|
croak "Wrong class $class" unless $self->isa('Geo::OSM::Render::Renderer'); |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
# while (@_) { |
76
|
|
|
|
|
|
|
# if ($_[0] -> isa('Geo::OSM::Render::Viewport::Clipped')) { |
77
|
|
|
|
|
|
|
# $self->{viewport} = shift; |
78
|
|
|
|
|
|
|
# next; |
79
|
|
|
|
|
|
|
# } |
80
|
|
|
|
|
|
|
# if ($_[0] -> isa('Geo::OSM::Render::Projection')) { |
81
|
|
|
|
|
|
|
# $self->{projection} = shift; |
82
|
|
|
|
|
|
|
# next; |
83
|
|
|
|
|
|
|
# } |
84
|
|
|
|
|
|
|
# last; |
85
|
|
|
|
|
|
|
# } |
86
|
|
|
|
|
|
|
|
87
|
1
|
50
|
|
|
|
7
|
croak 'Viewport must be Geo::OSM::Render::Viewport::Clipped' unless $self->{viewport } -> isa('Geo::OSM::Render::Viewport::Clipped'); |
88
|
1
|
50
|
|
|
|
7
|
croak 'Projection not defined' unless $self->{projection}; |
89
|
|
|
|
|
|
|
|
90
|
1
|
50
|
|
|
|
94
|
open ($self->{svg_fh}, '>', $svg_filename) or croak "Could not open $svg_filename"; |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
$self->{svg} = SVG->new( |
93
|
|
|
|
|
|
|
width => $self->{viewport}->map_width (), |
94
|
|
|
|
|
|
|
height => $self->{viewport}->map_height() |
95
|
1
|
50
|
|
|
|
8
|
) or croak "Could not start svg"; |
96
|
|
|
|
|
|
|
|
97
|
1
|
|
|
|
|
432
|
return $self; |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
} #_} |
100
|
|
|
|
|
|
|
sub end { #_{ |
101
|
|
|
|
|
|
|
#_{ POD |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=head2 end |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
When finished rendering, this method writes the SVG. |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=cut |
108
|
|
|
|
|
|
|
#_} |
109
|
1
|
|
|
1
|
1
|
56
|
my $self = shift; |
110
|
1
|
|
|
|
|
4
|
my $svg_text = $self->{svg}->xmlify(); |
111
|
1
|
|
|
|
|
1036
|
print {$self->{svg_fh}} $svg_text; |
|
1
|
|
|
|
|
16
|
|
112
|
1
|
|
|
|
|
125
|
close $self->{svg_fh}; |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
} #_} |
115
|
|
|
|
|
|
|
sub render_node { #_{ |
116
|
|
|
|
|
|
|
#_{ POD |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=head2 render_node |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
$osm_renderer_svg -> render_node( |
121
|
|
|
|
|
|
|
$node, |
122
|
|
|
|
|
|
|
r => $radius, |
123
|
|
|
|
|
|
|
styles=> { … } |
124
|
|
|
|
|
|
|
); |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
Renders a L<< node|Geo::OSM::Primitive::Node >>. |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
See also L. |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=cut |
131
|
|
|
|
|
|
|
#_} |
132
|
|
|
|
|
|
|
|
133
|
2
|
|
|
2
|
1
|
69
|
my $self = shift; |
134
|
2
|
|
|
|
|
4
|
my $node = shift; |
135
|
|
|
|
|
|
|
|
136
|
2
|
|
|
|
|
7
|
my %opts = @_; |
137
|
|
|
|
|
|
|
|
138
|
2
|
|
|
|
|
10
|
$self->SUPER::render_node($node); |
139
|
|
|
|
|
|
|
|
140
|
2
|
|
50
|
|
|
6
|
my $r = delete $opts{radius} // 1; |
141
|
2
|
|
50
|
|
|
5
|
my $styles = delete $opts{styles} // {}; |
142
|
|
|
|
|
|
|
|
143
|
2
|
|
|
|
|
11
|
my ($x_map, $y_map) = $self->node_to_map_coordinates($node); |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
$self->{svg}->circle( |
146
|
2
|
|
|
|
|
14
|
cx => $x_map, |
147
|
|
|
|
|
|
|
cy => $y_map, |
148
|
|
|
|
|
|
|
r => $r, |
149
|
|
|
|
|
|
|
style=>$styles |
150
|
|
|
|
|
|
|
); |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
} #_} |
153
|
|
|
|
|
|
|
sub render_way { #_{ |
154
|
|
|
|
|
|
|
#_{ POD |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=head2 render_way |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
$osm_renderer_svg -> render_way( |
159
|
|
|
|
|
|
|
styles=> { … } |
160
|
|
|
|
|
|
|
); |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
Renders a L<< way|Geo::OSM::Primitive::Way >>. |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
See also L<< Geo::OSM::Render::Renderer/render_way >>. |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
=cut |
167
|
|
|
|
|
|
|
#_} |
168
|
|
|
|
|
|
|
|
169
|
1
|
|
|
1
|
1
|
52
|
my $self = shift; |
170
|
1
|
|
|
|
|
3
|
my $way = shift; |
171
|
|
|
|
|
|
|
|
172
|
1
|
|
|
|
|
3
|
my %opts = @_; |
173
|
|
|
|
|
|
|
|
174
|
1
|
|
50
|
|
|
5
|
my $styles = delete $opts{styles} // {}; |
175
|
|
|
|
|
|
|
|
176
|
1
|
|
|
|
|
5
|
$self->SUPER::render_way($way); |
177
|
|
|
|
|
|
|
|
178
|
1
|
|
|
|
|
5
|
my @nodes = $way->nodes(); |
179
|
1
|
|
|
|
|
9
|
my $points = ''; |
180
|
1
|
|
|
|
|
2
|
for my $node (@nodes) { |
181
|
4
|
|
|
|
|
9
|
my ($x_map, $y_map) = $self->node_to_map_coordinates($node); |
182
|
4
|
100
|
|
|
|
11
|
$points .= ' ' if $points; |
183
|
4
|
|
|
|
|
22
|
$points .= "$x_map,$y_map"; |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
$self->{svg}->polyline( |
187
|
1
|
|
|
|
|
33
|
points => $points, |
188
|
|
|
|
|
|
|
style => $styles |
189
|
|
|
|
|
|
|
); |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
} #_} |
192
|
|
|
|
|
|
|
sub line { |
193
|
|
|
|
|
|
|
#_{ POD |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=head2 line |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
$osm_renderer_svg -> line( |
198
|
|
|
|
|
|
|
$lat_start, $lon_start, |
199
|
|
|
|
|
|
|
$lat_end , $lon_end, |
200
|
|
|
|
|
|
|
styles=> { … } |
201
|
|
|
|
|
|
|
); |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
Draws a line on the SVG map. |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
See also L<< Geo::OSM::Render::Renderer/render_way >>. |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=cut |
209
|
|
|
|
|
|
|
|
210
|
1
|
|
|
1
|
1
|
64
|
my $self = shift; |
211
|
1
|
|
|
|
|
2
|
my $lat_start = shift; |
212
|
1
|
|
|
|
|
2
|
my $lon_start = shift; |
213
|
1
|
|
|
|
|
2
|
my $lat_end = shift; |
214
|
1
|
|
|
|
|
5
|
my $lon_end = shift; |
215
|
1
|
|
|
|
|
3
|
my %opts = @_; |
216
|
|
|
|
|
|
|
|
217
|
1
|
|
50
|
|
|
4
|
my $styles = delete $opts{styles} // {}; |
218
|
|
|
|
|
|
|
|
219
|
1
|
|
|
|
|
4
|
my ($map_x_start, $map_y_start) = $self->lat_lon_to_map_coordinates($lat_start, $lon_start); |
220
|
1
|
|
|
|
|
3
|
my ($map_x_end , $map_y_end ) = $self->lat_lon_to_map_coordinates($lat_end , $lon_end ); |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
$self->{svg}->line( |
223
|
1
|
|
|
|
|
7
|
x1 => $map_x_start, y1 => $map_y_start, |
224
|
|
|
|
|
|
|
x2 => $map_x_end , y2 => $map_y_end, |
225
|
|
|
|
|
|
|
style => $styles |
226
|
|
|
|
|
|
|
); |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
#_} |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
# sub _determine_width_height { #_{ |
233
|
|
|
|
|
|
|
# #_{ POD |
234
|
|
|
|
|
|
|
# |
235
|
|
|
|
|
|
|
# =head2 _determine_width_height |
236
|
|
|
|
|
|
|
# |
237
|
|
|
|
|
|
|
# This method determines the width and height of the produced SVG so that C<< max($width, $height) >> is equal to C<< $max_width_height >> which was passed in the |
238
|
|
|
|
|
|
|
# L method. |
239
|
|
|
|
|
|
|
# |
240
|
|
|
|
|
|
|
# =cut |
241
|
|
|
|
|
|
|
# |
242
|
|
|
|
|
|
|
# my $self = shift; |
243
|
|
|
|
|
|
|
# |
244
|
|
|
|
|
|
|
# #_} |
245
|
|
|
|
|
|
|
# |
246
|
|
|
|
|
|
|
# ( |
247
|
|
|
|
|
|
|
# $self->{x_min}, $self->{y_min}, |
248
|
|
|
|
|
|
|
# $self->{x_max}, $self->{y_max} |
249
|
|
|
|
|
|
|
# ) = ( |
250
|
|
|
|
|
|
|
# &{$self->{cp_lat_lon_2_x_y}}($self->{lat_min}, $self->{lon_min}), |
251
|
|
|
|
|
|
|
# &{$self->{cp_lat_lon_2_x_y}}($self->{lat_max}, $self->{lon_max}) |
252
|
|
|
|
|
|
|
# ); |
253
|
|
|
|
|
|
|
# |
254
|
|
|
|
|
|
|
# my $width_ = $self->{x_max}-$self->{x_min}; |
255
|
|
|
|
|
|
|
# my $height_ = $self->{y_max}-$self->{y_min}; |
256
|
|
|
|
|
|
|
# |
257
|
|
|
|
|
|
|
# if ($width_ > $height_) { |
258
|
|
|
|
|
|
|
# $self->{width } = $self->{max_width_height}; |
259
|
|
|
|
|
|
|
# $self->{height} = $self->{max_width_height} / $width_*$height_; |
260
|
|
|
|
|
|
|
# } |
261
|
|
|
|
|
|
|
# else { |
262
|
|
|
|
|
|
|
# $self->{height} = $self->{max_width_height}; |
263
|
|
|
|
|
|
|
# $self->{width } = $self->{max_width_height} / $height_*$width_; |
264
|
|
|
|
|
|
|
# } |
265
|
|
|
|
|
|
|
# |
266
|
|
|
|
|
|
|
# } #_} |
267
|
|
|
|
|
|
|
# sub _x_y_to_svg_x_y { #_{ |
268
|
|
|
|
|
|
|
# #_{ POD |
269
|
|
|
|
|
|
|
# |
270
|
|
|
|
|
|
|
# =head2 _x_y_to_svg_x_y |
271
|
|
|
|
|
|
|
# |
272
|
|
|
|
|
|
|
# my ($svg_x, $svg_y) = $self->_x_y_to_svg_x_y($x, $y); |
273
|
|
|
|
|
|
|
# |
274
|
|
|
|
|
|
|
# This method converts an C coordinate pair to svg coordinates. Ideally, the |
275
|
|
|
|
|
|
|
# returned values are greater or equal 0 and smaller or equal to the svg width or |
276
|
|
|
|
|
|
|
# height respectively. |
277
|
|
|
|
|
|
|
# |
278
|
|
|
|
|
|
|
# =cut |
279
|
|
|
|
|
|
|
# #_} |
280
|
|
|
|
|
|
|
# |
281
|
|
|
|
|
|
|
# my $self = shift; |
282
|
|
|
|
|
|
|
# my $x = shift; |
283
|
|
|
|
|
|
|
# my $y = shift; |
284
|
|
|
|
|
|
|
# |
285
|
|
|
|
|
|
|
# my $todo_width = 1; |
286
|
|
|
|
|
|
|
# my $todo_height = 1; |
287
|
|
|
|
|
|
|
# |
288
|
|
|
|
|
|
|
# # In SVG, the coordinate 0/0 marks the *upper* left corner, so |
289
|
|
|
|
|
|
|
# # for y, we have to make an additional substraction for $y. |
290
|
|
|
|
|
|
|
# my $x_ = ($x - $self->{x_min}) / $todo_width * $self->{width }; |
291
|
|
|
|
|
|
|
# my $y_ = $self->{height} - ($y - $self->{y_min}) / $todo_height * $self->{height}; |
292
|
|
|
|
|
|
|
# |
293
|
|
|
|
|
|
|
# return ($x_, $y_); |
294
|
|
|
|
|
|
|
# |
295
|
|
|
|
|
|
|
# } #_} |
296
|
|
|
|
|
|
|
#_} |
297
|
|
|
|
|
|
|
#_{ POD: Author |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
=head1 AUTHOR |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
René Nyffenegger |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=cut |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
#_} |
306
|
|
|
|
|
|
|
#_{ POD: Copyright and License |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
309
|
|
|
|
|
|
|
Copyright © 2017 René Nyffenegger, Switzerland. All rights reserved. |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
312
|
|
|
|
|
|
|
under the terms of the the Artistic License (2.0). You may obtain a |
313
|
|
|
|
|
|
|
copy of the full license at: L |
314
|
|
|
|
|
|
|
=cut |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
#_} |
317
|
|
|
|
|
|
|
#_{ POD: Source Code |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
=head1 Source Code |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
The source code is on L<< github|https://github.com/ReneNyffenegger/perl-Geo-OSM-Render >>. Meaningful pull requests are welcome. |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
=cut |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
#_} |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
'tq84'; |