line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
2
|
|
|
2
|
|
56782
|
use 5.10.0; |
|
2
|
|
|
|
|
6
|
|
2
|
2
|
|
|
2
|
|
10
|
use strict; |
|
2
|
|
|
|
|
1
|
|
|
2
|
|
|
|
|
48
|
|
3
|
2
|
|
|
2
|
|
9
|
use warnings; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
123
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
package Map::Metro; |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
# ABSTRACT: Public transport graphing |
8
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:CSSON'; # AUTHORITY |
9
|
|
|
|
|
|
|
our $VERSION = '0.2404'; |
10
|
|
|
|
|
|
|
|
11
|
2
|
|
|
2
|
|
787
|
use Map::Metro::Elk; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
8
|
|
12
|
2
|
|
|
2
|
|
3693
|
use Module::Pluggable search_path => ['Map::Metro::Plugin::Map'], require => 1, sub_name => 'system_maps'; |
|
2
|
|
|
|
|
11658
|
|
|
2
|
|
|
|
|
12
|
|
13
|
2
|
|
|
2
|
|
1085
|
use Types::Standard qw/ArrayRef Str/; |
|
2
|
|
|
|
|
85230
|
|
|
2
|
|
|
|
|
15
|
|
14
|
2
|
|
|
2
|
|
1134
|
use Try::Tiny; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
96
|
|
15
|
2
|
|
|
2
|
|
7
|
use List::Util qw/any/; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
91
|
|
16
|
|
|
|
|
|
|
|
17
|
2
|
|
|
2
|
|
847
|
use Map::Metro::Graph; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
71
|
|
18
|
2
|
|
|
2
|
|
14
|
use Map::Metro::Exceptions; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
1397
|
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
has map => ( |
21
|
|
|
|
|
|
|
is => 'ro', |
22
|
|
|
|
|
|
|
traits => ['Array'], |
23
|
|
|
|
|
|
|
isa => ArrayRef, |
24
|
|
|
|
|
|
|
predicate => 1, |
25
|
|
|
|
|
|
|
handles => { |
26
|
|
|
|
|
|
|
get_map => 'get', |
27
|
|
|
|
|
|
|
}, |
28
|
|
|
|
|
|
|
); |
29
|
|
|
|
|
|
|
has mapclasses => ( |
30
|
|
|
|
|
|
|
is => 'ro', |
31
|
|
|
|
|
|
|
traits => ['Array'], |
32
|
|
|
|
|
|
|
isa => ArrayRef, |
33
|
|
|
|
|
|
|
default => sub { [] }, |
34
|
|
|
|
|
|
|
handles => { |
35
|
|
|
|
|
|
|
add_mapclass => 'push', |
36
|
|
|
|
|
|
|
get_mapclass => 'get', |
37
|
|
|
|
|
|
|
}, |
38
|
|
|
|
|
|
|
); |
39
|
|
|
|
|
|
|
has hooks => ( |
40
|
|
|
|
|
|
|
is => 'ro', |
41
|
|
|
|
|
|
|
isa => ArrayRef[ Str ], |
42
|
|
|
|
|
|
|
traits => ['Array'], |
43
|
|
|
|
|
|
|
default => sub { [] }, |
44
|
|
|
|
|
|
|
handles => { |
45
|
|
|
|
|
|
|
all_hooks => 'elements', |
46
|
|
|
|
|
|
|
hook_count => 'count', |
47
|
|
|
|
|
|
|
}, |
48
|
|
|
|
|
|
|
); |
49
|
|
|
|
|
|
|
has _plugin_ns => ( |
50
|
|
|
|
|
|
|
is => 'ro', |
51
|
|
|
|
|
|
|
isa => Str, |
52
|
|
|
|
|
|
|
default => 'Plugin::Map', |
53
|
|
|
|
|
|
|
init_arg => undef, |
54
|
|
|
|
|
|
|
); |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
around BUILDARGS => sub { |
57
|
|
|
|
|
|
|
my ($orig, $class, @args) = @_; |
58
|
|
|
|
|
|
|
my %args; |
59
|
|
|
|
|
|
|
if(scalar @args == 1) { |
60
|
|
|
|
|
|
|
$args{'map'} = shift @args; |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
elsif(scalar @args % 2 != 0) { |
63
|
|
|
|
|
|
|
my $map = shift @args; |
64
|
|
|
|
|
|
|
%args = @args; |
65
|
|
|
|
|
|
|
$args{'map'} = $map; |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
else { |
68
|
|
|
|
|
|
|
%args = @args; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
if(exists $args{'map'} && !ArrayRef->check($args{'map'})) { |
72
|
|
|
|
|
|
|
$args{'map'} = [$args{'map'}]; |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
if(exists $args{'hooks'} && !ArrayRef->check($args{'hooks'})) { |
75
|
|
|
|
|
|
|
$args{'hooks'} = [$args{'hooks'}]; |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
return $class->$orig(%args); |
79
|
|
|
|
|
|
|
}; |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub BUILD { |
82
|
1
|
|
|
1
|
0
|
795
|
my $self = shift; |
83
|
1
|
|
|
|
|
2
|
my @args = @_; |
84
|
|
|
|
|
|
|
|
85
|
1
|
50
|
|
|
|
29
|
if($self->has_map) { |
86
|
1
|
|
|
|
|
6
|
my @system_maps = map { s{^Map::Metro::Plugin::Map::}{}; $_ } $self->system_maps; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
87
|
1
|
50
|
|
0
|
|
305
|
if(any { $_ eq $self->get_map(0) } @system_maps) { |
|
0
|
|
|
|
|
0
|
|
88
|
0
|
|
|
|
|
0
|
my $mapclass = 'Map::Metro::Plugin::Map::'.$self->get_map(0); |
89
|
0
|
|
|
|
|
0
|
my $mapobj = $mapclass->new(hooks => $self->hooks); |
90
|
0
|
|
|
|
|
0
|
$self->add_mapclass($mapobj); |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
else { |
93
|
1
|
|
|
1
|
|
7
|
try { die no_such_map mapname => $self->get_map(0) } catch { die $_->desc }; |
|
1
|
|
|
|
|
75
|
|
|
1
|
|
|
|
|
1057
|
|
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
# Borrowed from Mojo::Util |
99
|
|
|
|
|
|
|
sub decamelize { |
100
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
101
|
0
|
|
|
|
|
|
my $string = shift; |
102
|
|
|
|
|
|
|
|
103
|
0
|
0
|
|
|
|
|
return $string if $string !~ m{[A-Z]}; |
104
|
|
|
|
|
|
|
return join '_' => map { |
105
|
0
|
|
|
|
|
|
join ('_' => map { lc } grep { length } split m{([A-Z]{1}[^A-Z]*)}) |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
} split '::' => $string; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub parse { |
110
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
111
|
0
|
|
|
|
|
|
my %args = @_; |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
return Map::Metro::Graph->new(filepath => $self->get_mapclass(0)->maplocation, |
114
|
|
|
|
|
|
|
do_undiacritic => $self->get_mapclass(0)->do_undiacritic, |
115
|
|
|
|
|
|
|
wanted_hook_plugins => [$self->all_hooks], |
116
|
0
|
0
|
|
|
|
|
exists $args{'override_line_change_weight'} ? (override_line_change_weight => $args{'override_line_change_weight'}) : (), |
117
|
|
|
|
|
|
|
)->parse; |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
sub available_maps { |
121
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
122
|
0
|
|
|
|
|
|
return sort $self->system_maps; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
1; |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
__END__ |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
=pod |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
=encoding utf-8 |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=head1 NAME |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
Map::Metro - Public transport graphing |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
=begin html |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
<p> |
142
|
|
|
|
|
|
|
<img src="https://img.shields.io/badge/perl-5.10+-blue.svg" alt="Requires Perl 5.10+" /> |
143
|
|
|
|
|
|
|
<a href="https://travis-ci.org/Csson/p5-Map-Metro"><img src="https://api.travis-ci.org/Csson/p5-Map-Metro.svg?branch=master" alt="Travis status" /></a> |
144
|
|
|
|
|
|
|
<a href="http://cpants.cpanauthors.org/dist/Map-Metro-0.2404"><img src="https://badgedepot.code301.com/badge/kwalitee/Map-Metro/0.2404" alt="Distribution kwalitee" /></a> |
145
|
|
|
|
|
|
|
<a href="http://matrix.cpantesters.org/?dist=Map-Metro%200.2404"><img src="https://badgedepot.code301.com/badge/cpantesters/Map-Metro/0.2404" alt="CPAN Testers result" /></a> |
146
|
|
|
|
|
|
|
<img src="https://img.shields.io/badge/coverage-72.9%-red.svg" alt="coverage 72.9%" /> |
147
|
|
|
|
|
|
|
</p> |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=end html |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=head1 VERSION |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
Version 0.2404, released 2016-04-30. |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=head1 SYNOPSIS |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
# Install a map |
158
|
|
|
|
|
|
|
$ cpanm Map::Metro::Plugin::Map::Stockholm |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
# And then |
161
|
|
|
|
|
|
|
my $graph = Map::Metro->new('Stockholm', hooks => ['PrettyPrinter'])->parse; |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
my $routing = $graph->routing_for('Universitetet', 'Kista'); |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
# or in a terminal |
166
|
|
|
|
|
|
|
$ map-metro.pl route Stockholm Universitetet Kista |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
prints |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
From Universitetet to Kista |
171
|
|
|
|
|
|
|
=========================== |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
-- Route 1 (cost 15) ---------- |
174
|
|
|
|
|
|
|
[ T14 ] Universitetet |
175
|
|
|
|
|
|
|
[ T14 ] Tekniska högskolan |
176
|
|
|
|
|
|
|
[ T14 ] Stadion |
177
|
|
|
|
|
|
|
[ T14 ] Ãstermalmstorg |
178
|
|
|
|
|
|
|
[ T14 ] T-Centralen |
179
|
|
|
|
|
|
|
[ * T11 ] T-Centralen |
180
|
|
|
|
|
|
|
[ T11 ] RÃ¥dhuset |
181
|
|
|
|
|
|
|
[ T11 ] Fridhemsplan |
182
|
|
|
|
|
|
|
[ T11 ] Stadshagen |
183
|
|
|
|
|
|
|
[ T11 ] Västra skogen |
184
|
|
|
|
|
|
|
[ T11 ] Solna centrum |
185
|
|
|
|
|
|
|
[ T11 ] Näckrosen |
186
|
|
|
|
|
|
|
[ T11 ] Hallonbergen |
187
|
|
|
|
|
|
|
[ T11 ] Kista |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
T11 Blue line |
190
|
|
|
|
|
|
|
T14 Red line |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
*: Transfer to other line |
193
|
|
|
|
|
|
|
+: Transfer to other station |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=head1 DESCRIPTION |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
The purpose of this distribution is to find the shortest L<unique|/"What is a unique path?"> route/routes between two stations in a transport network. |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
See L<Task::MapMetro::Maps> for a list of released maps. |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
=head2 Methods |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
=head3 new($city, hooks => []) |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
B<C<$city>> |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
The name of the city you want to search connections in. Mandatory, unless you are only going to call L</"available_maps">. |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
B<C<$hooks>> |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
Array reference of L<Hooks|Map::Metro::Hook> that listens for events. |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=head3 parse() |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
Returns a L<Map::Metro::Graph> object containing the entire graph. |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=head3 available_maps() |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
Returns an array reference containing the names of all Map::Metro maps installed on the system. |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=head2 What is a unique path? |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
The following rules are a guideline: |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
If the starting station and finishing station... |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
...are on the same line there will be no changes to other lines. |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
...shares multiple lines (e.g., both stations are on both line 2 and 4), each line constitutes a route. |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
...are on different lines, line changes will take place at suitable station(s). There is no guarantee that the same stations will be chosen for line changes between searches, if there are more than one suitable station to make a change at. |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=head1 MORE INFORMATION |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
L<Map::Metro::Graph> - How to use graph object. |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
L<Map::Metro::Plugin::Map> - How to make your own maps. |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
L<Map::Metro::Hook> - How to extend Map::Metro via hooks/events. |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
L<Map::Metro::Cmd> - A guide to the command line application. |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
L<Map::Metro::Graph::Connection> - Defines a MMG::Connection. |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
L<Map::Metro::Graph::Line> - Defines a MMG::Line. |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
L<Map::Metro::Graph::LineStation> - Defines a MMG::LineStation. |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
L<Map::Metro::Graph::Route> - Defines a MMG::Route. |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
L<Map::Metro::Graph::Routing> - Defines a MMG::Routing. |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
L<Map::Metro::Graph::Segment> - Defines a MMG::Segment. |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
L<Map::Metro::Graph::Station> - Defines a MMG::Station. |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
L<Map::Metro::Graph::Step> - Defines a MMG::Step. |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
L<Map::Metro::Graph::Transfer> - Defines a MMG::Transfer. |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
=head2 Hierarchy |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
The following is a conceptual overview of the various parts of a graph: |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
At first, the map file is parsed. The four types of information (stations, transfers, lines and segments) are translated |
266
|
|
|
|
|
|
|
into their respective objects. |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
Next, lines and stations are put together into L<LineStations|Map::Metro::Graph::LineStation>. Every two adjacent LineStations |
269
|
|
|
|
|
|
|
are put into two L<Connections|Map::Metro::Graph::Connection> (one for each direction). |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
Now the network is complete, and it is time to start traversing it. |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
Once a request to search for paths between two stations is given, we first search for the starting L<Station|Map::Metro::Graph::Station> given either a |
274
|
|
|
|
|
|
|
station id or station name. Then we find all L<LineStations|Map::Metro::Graph::LineStation> for that station. |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
Then we do the same for the destination station. |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
And then we walk through the network, from L<LineStation|Map::Metro::Graph::LineStation> to L<LineStation|Map::Metro::Graph::LineStation>, finding their L<Connections|Map::Metro::Graph::Connection> |
279
|
|
|
|
|
|
|
and turning them into L<Steps|Map::Metro::Graph::Step>, which we then add to the L<Route|Map::Metro::Graph::Route>. |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
All L<Routes|Map::Metro::Graph::Route> between the two L<Stations|Map::Metro::Graph::Station> are then put into a L<Routing|Map::Metro::Graph::Routing>, which is returned to the user. |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
=head1 PERFORMANCE |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
Since 0.2200 performance is less of an issue than it used to be, but it could still be improved. Prior to that version the entire network was analyzed up-front. This is unnecessary when searching one (or a few) routes. For long-running applications it is still possible to pre-calculate all paths, see L<asps|Map::Metro::Graph/"asps()">. |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
It is also possible to run the backend to some commands in a server, see L<App::Map::Metro>. |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
=head1 STATUS |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
This is somewhat experimental. I don't expect that the map file format will I<break>, but it might be |
292
|
|
|
|
|
|
|
extended. Only the documented api should be used, though breaking changes might occur. |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
For all maps in the Map::Metro::Plugin::Map namespace (unless noted): |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=over 4 |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
=item * |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
These maps are not an official source. Use accordingly. |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
=item * |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
There should be a note regarding what routes the map covers. |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
=back |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
=head1 COMPATIBILITY |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
Under Perl 5.16 or greater, C<fc> will be used instead of C<lc> for some string comparisons. Depending on the map definition |
311
|
|
|
|
|
|
|
this might lead to some maps not working properly on pre-5.16 Perls. |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
Prior to version 0.2400, C<Map::Metro> required at least Perl 5.16. |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
=head1 Map::Metro or Map::Tube? |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
L<Map::Tube> is the main alternative to C<Map::Metro>. They both have their strong and weak points. |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
=over 4 |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
=item * |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
Map::Tube is faster. |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
=item * |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
Map::Tube is more stable: It has been on Cpan for a long time, and is under active development. |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
=item * |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
Map::Metro has (in my opinion) a better map format. |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=item * |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
Map::Metro supports eg. transfers between stations. |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
=item * |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
See L<Task::MapMetro::Maps> and L<Task::Map::Tube> for available maps. |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
=item * |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
It is possible to convert Map::Metro maps into Map::Tube maps using L<map-metro.pl|Map::Metro::Cmd/"map-metro.pl metro_to_tube $city">. |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
=back |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
=head1 SEE ALSO |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
=over 4 |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
=item * |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
L<Task::MapMetro::Maps> - Available maps |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
=item * |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
L<Map::Tube> - An alternative |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
=back |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
=head1 SOURCE |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
L<https://github.com/Csson/p5-Map-Metro> |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
=head1 HOMEPAGE |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
L<https://metacpan.org/release/Map-Metro> |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=head1 AUTHOR |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
Erik Carlsson <info@code301.com> |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
This software is copyright (c) 2016 by Erik Carlsson. |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
378
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
=cut |