File Coverage

blib/lib/Map/Metro/Graph.pm
Criterion Covered Total %
statement 229 278 82.3
branch 49 78 62.8
condition 16 33 48.4
subroutine 51 59 86.4
pod 2 18 11.1
total 347 466 74.4


line stmt bran cond sub pod time code
1 2     2   15 use 5.10.0;
  2         5  
2 2     2   7 use strict;
  2         1  
  2         31  
3 2     2   5 use warnings;
  2         2  
  2         106  
4              
5             package Map::Metro::Graph;
6              
7             # ABSTRACT: An entire graph
8             our $AUTHORITY = 'cpan:CSSON'; # AUTHORITY
9             our $VERSION = '0.2404';
10              
11 2     2   7 use if $] >= 5.016000, feature => 'fc';
  2         2  
  2         12  
12              
13 2     2   212 use Map::Metro::Elk;
  2         2  
  2         14  
14 2     2   2653 use Types::Standard qw/ArrayRef Bool Int Maybe Object Str/;
  2         2  
  2         10  
15 2     2   1827 use Map::Metro::Types qw/Connection Line LineStation Routing Segment Station Step Transfer/;
  2         4  
  2         17  
16 2     2   2266 use Types::Path::Tiny qw/AbsFile/;
  2         27128  
  2         13  
17 2     2   1765 use Graph;
  2         123156  
  2         73  
18 2     2   14 use List::Util qw/any none/;
  2         2  
  2         131  
19 2     2   910 use String::Trim qw/trim/;
  2         980  
  2         97  
20 2     2   781 use Eponymous::Hash qw/eh/;
  2         2074  
  2         9  
21 2     2   77 use Try::Tiny;
  2         2  
  2         93  
22 2     2   733 use Safe::Isa qw/$_call_if_object/;
  2         572  
  2         176  
23              
24 2     2   701 use Map::Metro::Exceptions;
  2         4  
  2         311  
25              
26 2     2   780 use Map::Metro::Graph::Connection;
  2         6  
  2         59  
27 2     2   781 use Map::Metro::Graph::Line;
  2         3  
  2         59  
28 2     2   773 use Map::Metro::Graph::LineStation;
  2         6  
  2         61  
29 2     2   730 use Map::Metro::Graph::Route;
  2         5  
  2         64  
30 2     2   872 use Map::Metro::Graph::Routing;
  2         5  
  2         69  
31 2     2   802 use Map::Metro::Graph::Segment;
  2         6  
  2         60  
32 2     2   885 use Map::Metro::Graph::Station;
  2         6  
  2         71  
33 2     2   964 use Map::Metro::Graph::Step;
  2         4  
  2         58  
34 2     2   833 use Map::Metro::Graph::Transfer;
  2         5  
  2         63  
35 2     2   869 use Map::Metro::Emitter;
  2         4  
  2         7181  
36              
37             has filepath => (
38             is => 'ro',
39             isa => AbsFile,
40             required => 1,
41             );
42             has wanted_hook_plugins => (
43             is => 'ro',
44             isa => ArrayRef[Str],
45             default => sub { [] },
46             traits => ['Array'],
47             predicate => 1,
48             handles => {
49             all_wanted_hook_plugins => 'elements',
50             }
51             );
52             has do_undiacritic => (
53             is => 'rw',
54             isa => Bool,
55             default => 1,
56             );
57             has default_line_change_weight => (
58             is => 'ro',
59             isa => Int,
60             default => 3,
61             );
62             has override_line_change_weight => (
63             is => 'ro',
64             isa => Maybe[Int],
65             predicate => 1,
66             );
67             has emit => (
68             is => 'ro',
69             isa => Object,
70             init_arg => undef,
71             lazy => 1,
72             default => sub { Map::Metro::Emitter->new(wanted_hook_plugins => [shift->all_wanted_hook_plugins]) },
73             handles => [qw/get_plugin all_plugins plugin_names/],
74             );
75              
76             has stations => (
77             is => 'ro',
78             traits => ['Array'],
79             isa => ArrayRef[ Station ],
80             predicate => 1,
81             default => sub { [] },
82             init_arg => undef,
83             handles => {
84             add_station => 'push',
85             get_station => 'get',
86             find_station => 'first',
87             filter_stations => 'grep',
88             all_stations => 'elements',
89             station_count => 'count',
90             },
91             );
92             has lines => (
93             is => 'ro',
94             traits => ['Array'],
95             isa => ArrayRef[ Line ],
96             predicate => 1,
97             default => sub { [] },
98             init_arg => undef,
99             handles => {
100             add_line => 'push',
101             find_line => 'first',
102             all_lines => 'elements',
103             },
104             );
105             has segments => (
106             is => 'ro',
107             traits => ['Array'],
108             isa => ArrayRef[ Segment ],
109             predicate => 1,
110             default => sub { [] },
111             init_arg => undef,
112             handles => {
113             add_segment => 'push',
114             all_segments => 'elements',
115             filter_segments => 'grep',
116             },
117             );
118             has line_stations => (
119             is => 'ro',
120             traits => ['Array'],
121             isa => ArrayRef[ LineStation ],
122             predicate => 1,
123             default => sub { [] },
124             init_arg => undef,
125             handles => {
126             add_line_station => 'push',
127             all_line_stations => 'elements',
128             line_station_count => 'count',
129             find_line_stations => 'grep',
130             find_line_station => 'first',
131             },
132             );
133             has connections => (
134             is => 'ro',
135             traits => ['Array'],
136             isa => ArrayRef[ Connection ],
137             predicate => 1,
138             default => sub { [] },
139             init_arg => undef,
140             handles => {
141             add_connection => 'push',
142             all_connections => 'elements',
143             connection_count => 'count',
144             find_connection => 'first',
145             filter_connections => 'grep',
146             get_connection => 'get',
147             },
148             );
149             has transfers => (
150             is => 'ro',
151             traits => ['Array'],
152             isa => ArrayRef[ Transfer ],
153             predicate => 1,
154             default => sub { [] },
155             init_arg => undef,
156             handles => {
157             add_transfer => 'push',
158             all_transfers => 'elements',
159             transfer_count => 'count',
160             get_transfer => 'get',
161             filter_transfers => 'grep',
162             },
163             );
164             has routings => (
165             is => 'ro',
166             traits => ['Array'],
167             isa => ArrayRef[ Routing ],
168             predicate => 1,
169             default => sub { [] },
170             init_arg => undef,
171             handles => {
172             add_routing => 'push',
173             all_routings => 'elements',
174             routing_count => 'count',
175             find_routing => 'first',
176             filter_routings => 'grep',
177             get_routing => 'get',
178             },
179             );
180              
181             has full_graph => (
182             is => 'ro',
183             lazy => 1,
184             predicate => 1,
185             builder => 1,
186             );
187              
188             has asps => (
189             is => 'rw',
190             lazy => 1,
191             builder => 'calculate_shortest_paths',
192             predicate => 1,
193             init_arg => undef,
194             );
195              
196             sub _build_full_graph {
197 1     1   1 my $self = shift;
198              
199 1         9 my $graph = Graph->new;
200              
201 1         248 foreach my $conn ($self->all_connections) {
202 60         8492 $graph->add_weighted_edge($conn->origin_line_station->line_station_id,
203             $conn->destination_line_station->line_station_id,
204             $conn->weight);
205             }
206 1         126 return $graph;
207             }
208 0     0 0 0 sub calculate_shortest_paths { shift->full_graph->APSP_Floyd_Warshall }
209              
210             sub nocase {
211 4800     4800 0 3139 my $text = shift;
212 4800 50       4466 if($] >= 5.016000) {
213 4800         4472 $text = fc $text;
214             }
215             else {
216 0         0 $text = lc $text;
217             }
218 4800         4510 return $text;
219             }
220              
221             sub parse {
222 4     4 0 2469 my $self = shift;
223              
224 4         12 $self->build_network;
225 4         27 $self->construct_connections;
226              
227 4         27 return $self;
228             }
229              
230             sub build_network {
231 4     4 0 4 my $self = shift;
232              
233 4         99 my @rows = split /\r?\n/ => $self->filepath->slurp_utf8;
234 4         2649 my $context = undef;
235              
236             ROW:
237 4         183 foreach my $row (@rows) {
238 196 100 66     869 next ROW if !length $row || $row =~ m{^[ \t]*#};
239              
240 176 100 66 32   383 if($row =~ m{^--(\w+)} && (any { $_ eq $1 } qw/stations transfers lines segments/)) {
  32         61  
241 12         20 $context = $1;
242 12         30 next ROW;
243             }
244              
245 164 50       641 $context eq 'stations' ? $self->add_station($row)
    100          
    50          
    100          
246             : $context eq 'transfers' ? $self->add_transfer($row)
247             : $context eq 'lines' ? $self->add_line($row)
248             : $context eq 'segments' ? $self->add_segment($row)
249             : ()
250             ;
251             }
252             }
253              
254             around add_station => sub {
255             my $next = shift;
256             my $self = shift;
257             my $text = shift;
258              
259             $text = trim $text;
260             my @names = split m{\h*%\h*} => $text;
261             my $name = shift @names;
262              
263             if(my $station = $self->get_station_by_name($name, check => 0)) {
264             return $station;
265             }
266              
267             my $id = $self->station_count + 1;
268             my $station = Map::Metro::Graph::Station->new(original_name => $name, do_undiacritic => $self->do_undiacritic, eh $name, $id);
269              
270             foreach my $another_name (@names) {
271             if($another_name =~ m{^:(.+)}) {
272             $station->add_search_name($1);
273             }
274             else {
275             $station->add_alternative_name($another_name);
276             }
277             }
278             $self->emit->before_add_station($station);
279             $self->$next($station);
280             };
281              
282             around add_transfer => sub {
283             my $next = shift;
284             my $self = shift;
285             my $text = shift;
286              
287             $text = trim $text;
288              
289             my($origin_station_name, $destination_station_name, $option_string) = split /\|/ => $text;
290             my $origin_station = $self->get_station_by_name($origin_station_name);
291             my $destination_station = $self->get_station_by_name($destination_station_name);
292              
293             my $options = defined $option_string ? $self->make_options($option_string, keys => [qw/weight/]) : {};
294              
295             my $transfer = Map::Metro::Graph::Transfer->new(origin_station => $origin_station,
296             destination_station => $destination_station,
297             %$options);
298              
299             $self->$next($transfer);
300             };
301              
302             around add_line => sub {
303             my $next = shift;
304             my $self = shift;
305             my $text = shift;
306              
307             $text = trim $text;
308             my($id, $name, $description, $option_string) = split /\|/ => $text;
309              
310             my $options = defined $option_string ? $self->make_options($option_string, keys => [qw/color width/]) : {};
311             my $line = Map::Metro::Graph::Line->new(%{ $options }, id => $id, name => $name, description => $description);
312              
313             $self->$next($line);
314             };
315              
316             around add_segment => sub {
317             my $next = shift;
318             my $self = shift;
319             my $text = shift;
320              
321             $text = trim $text;
322             my($linestring, $start, $end, $option_string) = split /\|/ => $text;
323             my @line_ids_with_dir = split m/,/ => $linestring;
324             my @clean_line_ids = map { (my $clean = $_) =~ s{[^a-z0-9]}{}gi; $clean } @line_ids_with_dir;
325              
326             my $options = defined $option_string ? $self->make_options($option_string, keys => [qw/dir/]) : {};
327              
328             #* Check that lines and stations in segments exist in the other lists
329             my($origin_station, $destination_station);
330              
331             try {
332             $self->get_line_by_id($_) foreach @clean_line_ids;
333             $origin_station = $self->get_station_by_name($start);
334             $destination_station = $self->get_station_by_name($end);
335             }
336             catch {
337             die($_->$_call_if_object('desc') || $_);
338             };
339             my @both_dir = ();
340             my @forward = ();
341             my @backward = ();
342             my @segments = ();
343              
344             foreach my $line_info (@line_ids_with_dir) {
345             if($line_info =~ m{^[a-z0-9]+$}i) {
346             push @both_dir => $line_info;
347             }
348             elsif($line_info =~ m{^([a-z0-9]+)->$}i) {
349             push @forward => $1;
350             }
351             elsif($line_info =~ m{^([a-z0-9]+)<-$}i) {
352             push @backward => $1;
353             }
354             }
355              
356             if(scalar @both_dir) {
357             push @segments => Map::Metro::Graph::Segment->new(line_ids => \@both_dir, origin_station => $origin_station, destination_station => $destination_station);
358             }
359             if(scalar @forward) {
360             push @segments => Map::Metro::Graph::Segment->new(line_ids => \@forward, is_one_way => 1, origin_station => $origin_station, destination_station => $destination_station);
361             }
362             if(scalar @backward) {
363             push @segments => Map::Metro::Graph::Segment->new(line_ids => \@backward, is_one_way => 1, origin_station => $destination_station, destination_station => $origin_station);
364             }
365              
366             $self->$next(@segments);
367             };
368              
369             around add_line_station => sub {
370             my $next = shift;
371             my $self = shift;
372             my $line_station = shift;
373              
374             my $exists = $self->get_line_station_by_line_and_station_id($line_station->line->id, $line_station->station->id);
375             return $exists if $exists;
376              
377             $self->$next($line_station);
378             return $line_station;
379             };
380              
381             sub get_line_by_id {
382 193     193 0 765 my $self = shift;
383 193         169 my $line_id = shift; # Str
384 193   100 282   5559 return $self->find_line(sub { $_->id eq $line_id }) || die lineid_does_not_exist_in_line_list line_id => $line_id;
  282         5798  
385             }
386              
387             sub get_station_by_name {
388 233     233 0 267 my $self = shift;
389 233         217 my $station_name = shift; # Str
390 233         276 my %args = @_;
391 233 100       340 my $check = exists $args{'check'} ? $args{'check'} : 1;
392              
393 233     2376   6868 my $station = $self->find_station(sub { nocase($_->name) eq nocase($station_name) });
  2376         50451  
394 233 100       651 return $station if Station->check($station);
395              
396 81 100       917 if($check) {
397 1     20   32 $station = $self->find_station(sub { nocase($_->original_name) eq nocase($station_name) });
  20         438  
398 1 50       6 return $station if Station->check($station);
399              
400             $station = $self->find_station(sub {
401 20     20   30 my $current_station = $_;
402 20 50       631 if(any { nocase($station_name) eq nocase($_) } $current_station->all_alternative_names) {
  0         0  
403 0         0 return $current_station;
404             }
405 1         38 });
406 1 50       5 return $station if Station->check($station);
407              
408             $station = $self->find_station(sub {
409 20     20   28 my $current_station = $_;
410 20 50       627 if(any { nocase($station_name) eq nocase($_) } $current_station->all_search_names) {
  4         10  
411 0         0 return $current_station;
412             }
413 1         46 });
414 1 50       7 return $station if Station->check($station);
415              
416 1         14 die station_name_does_not_exist_in_station_list station_name => $station_name;
417             }
418             }
419              
420             sub get_station_by_id {
421 2     2 0 3 my $self = shift;
422 2         2 my $id = shift; # Int
423              
424 2   50 5   67 return $self->find_station(sub { $_->id == $id }) || die stationid_does_not_exist station_id => $id;
  5         120  
425             }
426              
427             sub get_line_stations_by_station {
428 82     82 0 68 my $self = shift;
429 82         52 my $station = shift; # Station
430 82     2132   2431 return $self->find_line_stations(sub { $_->station->id == $station->id });
  2132         45889  
431             }
432              
433             sub get_line_station_by_line_and_station_id {
434 384     384 0 320 my $self = shift;
435 384         293 my $line_id = shift;
436 384         289 my $station_id = shift;
437              
438 384 100   4920   11135 return $self->find_line_station(sub { $_->line->id eq $line_id && $_->station->id == $station_id });
  4920         105687  
439             }
440              
441             sub get_line_station_by_id {
442 16     16 0 12 my $self = shift;
443 16         14 my $line_station_id = shift; # Int
444              
445 16     38   482 return $self->find_line_station(sub { $_->line_station_id == $line_station_id });
  38         901  
446             }
447              
448             sub get_connection_by_line_station_ids {
449 5     5 0 4 my $self = shift;
450 5         4 my $first_ls_id = shift; # Int
451 5         6 my $second_ls_id = shift; # Int
452              
453 5         8 my $first_ls = $self->get_line_station_by_id($first_ls_id);
454 5         13 my $second_ls = $self->get_line_station_by_id($second_ls_id);
455              
456             return $self->find_connection(
457             sub {
458 13 100   13   308 $_->origin_line_station->line_station_id == $first_ls->line_station_id
459             && $_->destination_line_station->line_station_id == $second_ls->line_station_id
460             }
461 5         156 );
462             }
463              
464             sub next_line_station_id {
465 0     0 0 0 my $self = shift;
466              
467 0         0 return $self->line_station_count + 1;
468             }
469              
470             sub make_options {
471 0     0 0 0 my $self = shift;
472 0         0 my $string = shift;
473 0         0 my %args = @_;
474 0 0       0 my $keys = exists $args{'keys'} ? $args{'keys'} : [];
475              
476 0         0 my $options = {};
477 0         0 my @options = split /, ?/ => $string;
478              
479             OPTION:
480 0         0 foreach my $option (@options) {
481 0         0 my($key, $value) = split /:/ => $option;
482              
483 0 0 0 0   0 next OPTION if scalar @$keys && (none { $key eq $_ } @$keys);
  0         0  
484 0         0 $options->{ $key } = $value;
485             }
486 0         0 return $options;
487             }
488              
489             sub construct_connections {
490 4     4 0 6 my $self = shift;
491              
492 4 50 33     112 if(!($self->has_stations && $self->has_lines && $self->has_segments)) {
      33        
493 0         0 die incomplete_parse mapfile => $self->filepath;
494             }
495              
496             #* Walk through all segments, and all lines for
497             #* that segment. Add pairwise connections between
498             #* all pair of stations on the same line
499 4         6 my $next_line_station_id = 0;
500             SEGMENT:
501 4         120 foreach my $segment ($self->all_segments) {
502              
503             LINE:
504 76         2248 foreach my $line_id ($segment->all_line_ids) {
505 96         169 my $line = $self->get_line_by_id($line_id);
506              
507 96   66     2343 my $origin_line_station = $self->get_line_station_by_line_and_station_id($line_id, $segment->origin_station->id)
508             ||
509             Map::Metro::Graph::LineStation->new(
510             line_station_id => ++$next_line_station_id,
511             station => $segment->origin_station,
512             line => $line,
513             );
514 96         407 $origin_line_station = $self->add_line_station($origin_line_station);
515 96         2243 $segment->origin_station->add_line($line);
516              
517 96   66     2359 my $destination_line_station = $self->get_line_station_by_line_and_station_id($line_id, $segment->destination_station->id)
518             ||
519             Map::Metro::Graph::LineStation->new(
520             line_station_id => ++$next_line_station_id,
521             station => $segment->destination_station,
522             line => $line,
523             );
524 96         439 $destination_line_station = $self->add_line_station($destination_line_station);
525 96         2315 $segment->destination_station->add_line($line);
526              
527 96         189 my $weight = 1;
528              
529 96         173 my $conn = Map::Metro::Graph::Connection->new(origin_line_station => $origin_line_station,
530             destination_line_station => $destination_line_station,
531             weight => $weight);
532              
533 96         162 my $inv_conn = Map::Metro::Graph::Connection->new(origin_line_station => $destination_line_station,
534             destination_line_station => $origin_line_station,
535             weight => $weight);
536              
537 96         2307 $origin_line_station->station->add_connecting_station($destination_line_station->station);
538 96 50       2350 $destination_line_station->station->add_connecting_station($origin_line_station->station) if !$segment->is_one_way;
539              
540 96         2747 $self->add_connection($conn);
541 96 50       2185 $self->add_connection($inv_conn) if !$segment->is_one_way;
542             }
543             }
544              
545             #* Walk through all stations, and fetch all line_stations per station
546             #* Then add a connection between all line_stations of every station
547             STATION:
548 4         129 foreach my $station ($self->all_stations) {
549 80         106 my @line_stations_at_station = $self->get_line_stations_by_station($station);
550              
551             LINE_STATION:
552 80         181 foreach my $line_station (@line_stations_at_station) {
553 104         103 my @other_line_stations = grep { $_->line_station_id != $line_station->line_station_id } @line_stations_at_station;
  152         3638  
554              
555             OTHER_LINE_STATION:
556 104         147 foreach my $other_line_station (@other_line_stations) {
557              
558 48 50       1361 my $weight = $self->has_override_line_change_weight ? $self->override_line_change_weight : $self->default_line_change_weight;
559 48         95 my $conn = Map::Metro::Graph::Connection->new(origin_line_station => $line_station,
560             destination_line_station => $other_line_station,
561             weight => $weight);
562 48         1374 $self->add_connection($conn);
563             }
564             }
565             }
566              
567             #* Walk through all transfers, and add connections between all line stations of the two stations
568             TRANSFER:
569 4         137 foreach my $transfer ($self->all_transfers) {
570 0         0 my $origin_station = $transfer->origin_station;
571 0         0 my $destination_station = $transfer->destination_station;
572 0         0 my @line_stations_at_origin = $self->get_line_stations_by_station($origin_station);
573              
574             ORIGIN_LINE_STATION:
575 0         0 foreach my $origin_line_station (@line_stations_at_origin) {
576 0         0 my @line_stations_at_destination = $self->get_line_stations_by_station($destination_station);
577              
578             DESTINATION_LINE_STATION:
579 0         0 foreach my $destination_line_station (@line_stations_at_destination) {
580              
581 0         0 my $conn = Map::Metro::Graph::Connection->new(origin_line_station => $origin_line_station,
582             destination_line_station => $destination_line_station,
583             weight => $transfer->weight);
584              
585 0         0 my $inv_conn = Map::Metro::Graph::Connection->new(origin_line_station => $destination_line_station,
586             destination_line_station => $origin_line_station,
587             weight => $transfer->weight);
588              
589 0         0 $origin_line_station->station->add_connecting_station($destination_line_station->station);
590 0         0 $destination_line_station->station->add_connecting_station($origin_line_station->station);
591              
592 0         0 $self->add_connection($conn);
593 0         0 $self->add_connection($inv_conn);
594             }
595             }
596              
597             }
598             }
599              
600             # --> Station
601             sub ensure_station {
602 2     2 0 3 my $self = shift;
603 2         5 my $place = shift; # Int|Str|Station
604              
605 2 50       7 return $place if Station->check($place);
606              
607             try {
608 2 50   2   68 if(Int->check($place)) {
609 2         22 $place = $self->get_station_by_id($place);
610             }
611             else {
612 0         0 $place = $self->get_station_by_name($place);
613             }
614             }
615             catch {
616 0     0   0 my $error = $_;
617 0   0     0 die ($error->$_call_if_object('desc') || $error);
618 2         34 };
619 2         28 return $place;
620             }
621              
622             # --> Routing
623             sub routing_for {
624 1     1 1 6 my $self = shift;
625 1         3 my $origin = shift; # Int|Str|Station The first station. Station id, name or object.
626 1         2 my $destination = shift; # Int|Str|Station The final station. Station id, name or object.
627              
628 1         4 my $origin_station = $self->ensure_station($origin);
629 1         2 my $destination_station = $self->ensure_station($destination);
630              
631 1         4 my @origin_line_station_ids = map { $_->line_station_id } $self->get_line_stations_by_station($origin_station);
  1         29  
632 1         4 my @destination_line_station_ids = map { $_->line_station_id } $self->get_line_stations_by_station($destination_station);
  1         26  
633              
634 1 50       29 if($self->has_routings) {
635 1 0   0   34 my $existing_routing = $self->find_routing(sub { $_->origin_station->id == $origin_station->id && $_->destination_station->id == $destination_station->id });
  0         0  
636 1 50       6 return $existing_routing if $existing_routing;
637             }
638 1         23 $self->emit->before_start_routing;
639 1         5 my $routing = Map::Metro::Graph::Routing->new(origin_station => $origin_station, destination_station => $destination_station);
640              
641             #* Find all lines going from origin station
642             #* Find all lines going to destination station
643             #* Get all routes between them
644             #* and then, in the third and fourth for, loop over the
645             #* found routes and add info about all stations on all lines
646             ORIGIN_LINE_STATION:
647 1         3 foreach my $origin_id (@origin_line_station_ids) {
648 1         4 my $origin = $self->get_line_station_by_id($origin_id);
649              
650             DESTINATION_LINE_STATION:
651 1         4 foreach my $dest_id (@destination_line_station_ids) {
652 1         3 my $dest = $self->get_line_station_by_id($dest_id);
653              
654 1 50       26 my $graphroute = [ $self->has_asps ? $self->asps->path_vertices($origin_id, $dest_id) : $self->full_graph->SP_Dijkstra($origin_id, $dest_id) ];
655              
656 1 50 33     15651 if($origin->possible_on_same_line($dest) && !$origin->on_same_line($dest)) {
657 0         0 next DESTINATION_LINE_STATION;
658             }
659              
660 1         30 my $route = Map::Metro::Graph::Route->new;
661              
662 1         2 my($prev_step, $prev_conn, $next_step, $next_conn);
663              
664             LINE_STATION:
665 1         4 foreach my $index (0 .. scalar @$graphroute - 2) {
666 3         5 my $this_line_station_id = $graphroute->[ $index ];
667 3         4 my $next_line_station_id = $graphroute->[ $index + 1 ];
668 3   100     9 my $next_next_line_station_id = $graphroute->[ $index + 2 ] // undef;
669              
670              
671              
672 3         9 my $conn = $self->get_connection_by_line_station_ids($this_line_station_id, $next_line_station_id);
673              
674             #* Don't continue beyond this route, even it connections exist.
675 3 100       12 if($index + 2 < scalar @$graphroute) {
676 2 50       7 $next_conn = defined $next_next_line_station_id ? $self->get_connection_by_line_station_ids($this_line_station_id, $next_line_station_id) : undef;
677 2 50       12 $next_step = Map::Metro::Graph::Step->new(from_connection => $next_conn) if defined $next_conn;
678             }
679             else {
680 1         3 $next_conn = $next_step = undef;
681             }
682              
683 3         6 my $step = Map::Metro::Graph::Step->new(from_connection => $conn);
684 3 100       53 $step->previous_step($prev_step) if $prev_step;
685 3 100       53 $step->next_step($next_step) if $next_step;
686              
687 3 100       54 $next_step->previous_step($step) if defined $next_step;
688              
689 3         84 $route->add_step($step);
690 3         3 $prev_step = $step;
691 3         5 $step = $next_step;
692              
693             }
694              
695             LINE_STATION:
696 1         4 foreach my $index (0 .. scalar @$graphroute - 1) {
697 4         7 my $line_station = $self->get_line_station_by_id($graphroute->[$index]);
698              
699 4         119 $route->add_line_station($line_station);
700             }
701              
702 1 50       5 next DESTINATION_LINE_STATION if $route->transfer_on_first_station;
703 1 50       5 next DESTINATION_LINE_STATION if $route->transfer_on_final_station;
704              
705 1         31 $routing->add_route($route);
706             }
707             }
708 1 50       31 $self->emit->before_add_routing($routing) if $self->has_wanted_hook_plugins;
709 1         29 $self->add_routing($routing);
710              
711 1         4 return $routing;
712             }
713              
714             # --> ArrayRef[Routing] Routings between every pair of Stations
715             sub all_pairs {
716 0     0 1   my $self = shift;
717              
718 0           my $routings = [];
719 0           $self->calculate_shortest_paths;
720              
721             STATION:
722 0           foreach my $station ($self->all_stations) {
723 0           my @other_stations = grep { $_->id != $station->id } $self->all_stations;
  0            
724              
725             OTHER_STATION:
726 0           foreach my $other_station (@other_stations) {
727 0           push @$routings => $self->routing_for($station, $other_station);
728             }
729             }
730 0           return $routings;
731             }
732              
733             sub to_hash {
734 0     0 0   my $self = shift;
735              
736             return {
737             routings => [
738 0           map { $_->to_hash } $self->all_routings
  0            
739             ],
740             }
741             }
742              
743             1;
744              
745             __END__
746              
747             =pod
748              
749             =encoding UTF-8
750              
751             =head1 NAME
752              
753             Map::Metro::Graph - An entire graph
754              
755             =head1 VERSION
756              
757             Version 0.2404, released 2016-04-30.
758              
759              
760              
761             =head1 SYNOPSIS
762              
763             my $graph = Map::Metro->new('Stockholm')->parse;
764              
765             my $routing = $graph->routing_for('Universitetet', 'Kista');
766              
767             # And then it's traversing time. Also see the
768             # Map::Metro::Plugin::Hook::PrettyPrinter hook
769             say $routing->origin_station->name;
770             say $routing->destination_station->name;
771              
772             foreach my $route ($routing->all_routes) {
773             foreach my $step ($route->all_steps) {
774             say 'Transfer!' if $step->was_line_transfer;
775             say $step->origin_line_station->line->id;
776             say $step->origin_line_station->station->name;
777             }
778             say '----';
779             }
780              
781             #* The constructed Graph object is also available
782             my $full_graph = $graph->full_graph;
783              
784             =head1 DESCRIPTION
785              
786             This class is at the core of L<Map::Metro>. After a map has been parsed the returned instance of this class contains
787             the entire network (graph) in a hierarchy of objects.
788              
789             =head1 ATTRIBUTES
790              
791              
792             =head2 filepath
793              
794             =begin HTML
795              
796             <table cellpadding="0" cellspacing="0">
797             <tr>
798             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Path::Tiny#AbsFile">AbsFile</a></td>
799             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">required</td>
800             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
801             </tr>
802             </table>
803              
804             <p></p>
805              
806             =end HTML
807              
808             =begin markdown
809              
810             <table cellpadding="0" cellspacing="0">
811             <tr>
812             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Path::Tiny#AbsFile">AbsFile</a></td>
813             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">required</td>
814             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
815             </tr>
816             </table>
817              
818             <p></p>
819              
820             =end markdown
821              
822             =head2 default_line_change_weight
823              
824             =begin HTML
825              
826             <table cellpadding="0" cellspacing="0">
827             <tr>
828             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#Int">Int</a></td>
829             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">optional, default: <code>3</code></td>
830             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
831             </tr>
832             </table>
833              
834             <p></p>
835              
836             =end HTML
837              
838             =begin markdown
839              
840             <table cellpadding="0" cellspacing="0">
841             <tr>
842             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#Int">Int</a></td>
843             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">optional, default: <code>3</code></td>
844             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
845             </tr>
846             </table>
847              
848             <p></p>
849              
850             =end markdown
851              
852             =head2 do_undiacritic
853              
854             =begin HTML
855              
856             <table cellpadding="0" cellspacing="0">
857             <tr>
858             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#Bool">Bool</a></td>
859             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">optional, default: <code>1</code></td>
860             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read/write</td>
861             </tr>
862             </table>
863              
864             <p></p>
865              
866             =end HTML
867              
868             =begin markdown
869              
870             <table cellpadding="0" cellspacing="0">
871             <tr>
872             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#Bool">Bool</a></td>
873             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">optional, default: <code>1</code></td>
874             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read/write</td>
875             </tr>
876             </table>
877              
878             <p></p>
879              
880             =end markdown
881              
882             =head2 full_graph
883              
884             =begin HTML
885              
886             <table cellpadding="0" cellspacing="0">
887             <tr>
888             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">optional</td>
889             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
890             </tr>
891             </table>
892              
893             <p></p>
894              
895             =end HTML
896              
897             =begin markdown
898              
899             <table cellpadding="0" cellspacing="0">
900             <tr>
901             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">optional</td>
902             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
903             </tr>
904             </table>
905              
906             <p></p>
907              
908             =end markdown
909              
910             =head2 override_line_change_weight
911              
912             =begin HTML
913              
914             <table cellpadding="0" cellspacing="0">
915             <tr>
916             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#Maybe">Maybe</a> [ <a href="https://metacpan.org/pod/Types::Standard#Int">Int</a> ]</td>
917             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">optional</td>
918             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
919             </tr>
920             </table>
921              
922             <p></p>
923              
924             =end HTML
925              
926             =begin markdown
927              
928             <table cellpadding="0" cellspacing="0">
929             <tr>
930             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#Maybe">Maybe</a> [ <a href="https://metacpan.org/pod/Types::Standard#Int">Int</a> ]</td>
931             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">optional</td>
932             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
933             </tr>
934             </table>
935              
936             <p></p>
937              
938             =end markdown
939              
940             =head2 wanted_hook_plugins
941              
942             =begin HTML
943              
944             <table cellpadding="0" cellspacing="0">
945             <tr>
946             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#ArrayRef">ArrayRef</a> [ <a href="https://metacpan.org/pod/Types::Standard#Str">Str</a> ]</td>
947             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">optional, default is a <code>coderef</code></td>
948             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
949             </tr>
950             </table>
951              
952             <p></p>
953              
954             =end HTML
955              
956             =begin markdown
957              
958             <table cellpadding="0" cellspacing="0">
959             <tr>
960             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#ArrayRef">ArrayRef</a> [ <a href="https://metacpan.org/pod/Types::Standard#Str">Str</a> ]</td>
961             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">optional, default is a <code>coderef</code></td>
962             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
963             </tr>
964             </table>
965              
966             <p></p>
967              
968             =end markdown
969              
970             =head2 asps
971              
972             =begin HTML
973              
974             <table cellpadding="0" cellspacing="0">
975             <tr>
976             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">not in constructor</td>
977             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read/write</td>
978             </tr>
979             </table>
980              
981             <p></p>
982              
983             =end HTML
984              
985             =begin markdown
986              
987             <table cellpadding="0" cellspacing="0">
988             <tr>
989             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">not in constructor</td>
990             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read/write</td>
991             </tr>
992             </table>
993              
994             <p></p>
995              
996             =end markdown
997              
998             =head2 connections
999              
1000             =begin HTML
1001              
1002             <table cellpadding="0" cellspacing="0">
1003             <tr>
1004             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#ArrayRef">ArrayRef</a> [ <a href="https://metacpan.org/pod/Types::Standard#Connection">Connection</a> ]</td>
1005             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">not in constructor</td>
1006             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
1007             </tr>
1008             </table>
1009              
1010             <p></p>
1011              
1012             =end HTML
1013              
1014             =begin markdown
1015              
1016             <table cellpadding="0" cellspacing="0">
1017             <tr>
1018             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#ArrayRef">ArrayRef</a> [ <a href="https://metacpan.org/pod/Types::Standard#Connection">Connection</a> ]</td>
1019             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">not in constructor</td>
1020             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
1021             </tr>
1022             </table>
1023              
1024             <p></p>
1025              
1026             =end markdown
1027              
1028             =head2 emit
1029              
1030             =begin HTML
1031              
1032             <table cellpadding="0" cellspacing="0">
1033             <tr>
1034             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#Object">Object</a></td>
1035             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">not in constructor</td>
1036             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
1037             </tr>
1038             </table>
1039              
1040             <p></p>
1041              
1042             =end HTML
1043              
1044             =begin markdown
1045              
1046             <table cellpadding="0" cellspacing="0">
1047             <tr>
1048             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#Object">Object</a></td>
1049             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">not in constructor</td>
1050             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
1051             </tr>
1052             </table>
1053              
1054             <p></p>
1055              
1056             =end markdown
1057              
1058             =head2 line_stations
1059              
1060             =begin HTML
1061              
1062             <table cellpadding="0" cellspacing="0">
1063             <tr>
1064             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#ArrayRef">ArrayRef</a> [ <a href="https://metacpan.org/pod/Types::Standard#LineStation">LineStation</a> ]</td>
1065             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">not in constructor</td>
1066             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
1067             </tr>
1068             </table>
1069              
1070             <p></p>
1071              
1072             =end HTML
1073              
1074             =begin markdown
1075              
1076             <table cellpadding="0" cellspacing="0">
1077             <tr>
1078             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#ArrayRef">ArrayRef</a> [ <a href="https://metacpan.org/pod/Types::Standard#LineStation">LineStation</a> ]</td>
1079             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">not in constructor</td>
1080             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
1081             </tr>
1082             </table>
1083              
1084             <p></p>
1085              
1086             =end markdown
1087              
1088             =head2 lines
1089              
1090             =begin HTML
1091              
1092             <table cellpadding="0" cellspacing="0">
1093             <tr>
1094             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#ArrayRef">ArrayRef</a> [ <a href="https://metacpan.org/pod/Types::Standard#Line">Line</a> ]</td>
1095             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">not in constructor</td>
1096             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
1097             </tr>
1098             </table>
1099              
1100             <p></p>
1101              
1102             =end HTML
1103              
1104             =begin markdown
1105              
1106             <table cellpadding="0" cellspacing="0">
1107             <tr>
1108             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#ArrayRef">ArrayRef</a> [ <a href="https://metacpan.org/pod/Types::Standard#Line">Line</a> ]</td>
1109             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">not in constructor</td>
1110             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
1111             </tr>
1112             </table>
1113              
1114             <p></p>
1115              
1116             =end markdown
1117              
1118             =head2 routings
1119              
1120             =begin HTML
1121              
1122             <table cellpadding="0" cellspacing="0">
1123             <tr>
1124             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#ArrayRef">ArrayRef</a> [ <a href="https://metacpan.org/pod/Types::Standard#Routing">Routing</a> ]</td>
1125             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">not in constructor</td>
1126             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
1127             </tr>
1128             </table>
1129              
1130             <p></p>
1131              
1132             =end HTML
1133              
1134             =begin markdown
1135              
1136             <table cellpadding="0" cellspacing="0">
1137             <tr>
1138             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#ArrayRef">ArrayRef</a> [ <a href="https://metacpan.org/pod/Types::Standard#Routing">Routing</a> ]</td>
1139             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">not in constructor</td>
1140             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
1141             </tr>
1142             </table>
1143              
1144             <p></p>
1145              
1146             =end markdown
1147              
1148             =head2 segments
1149              
1150             =begin HTML
1151              
1152             <table cellpadding="0" cellspacing="0">
1153             <tr>
1154             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#ArrayRef">ArrayRef</a> [ <a href="https://metacpan.org/pod/Types::Standard#Segment">Segment</a> ]</td>
1155             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">not in constructor</td>
1156             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
1157             </tr>
1158             </table>
1159              
1160             <p></p>
1161              
1162             =end HTML
1163              
1164             =begin markdown
1165              
1166             <table cellpadding="0" cellspacing="0">
1167             <tr>
1168             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#ArrayRef">ArrayRef</a> [ <a href="https://metacpan.org/pod/Types::Standard#Segment">Segment</a> ]</td>
1169             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">not in constructor</td>
1170             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
1171             </tr>
1172             </table>
1173              
1174             <p></p>
1175              
1176             =end markdown
1177              
1178             =head2 stations
1179              
1180             =begin HTML
1181              
1182             <table cellpadding="0" cellspacing="0">
1183             <tr>
1184             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#ArrayRef">ArrayRef</a> [ <a href="https://metacpan.org/pod/Map::Metro::Types#Station">Station</a> ]</td>
1185             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">not in constructor</td>
1186             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
1187             </tr>
1188             </table>
1189              
1190             <p></p>
1191              
1192             =end HTML
1193              
1194             =begin markdown
1195              
1196             <table cellpadding="0" cellspacing="0">
1197             <tr>
1198             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#ArrayRef">ArrayRef</a> [ <a href="https://metacpan.org/pod/Map::Metro::Types#Station">Station</a> ]</td>
1199             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">not in constructor</td>
1200             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
1201             </tr>
1202             </table>
1203              
1204             <p></p>
1205              
1206             =end markdown
1207              
1208             =head2 transfers
1209              
1210             =begin HTML
1211              
1212             <table cellpadding="0" cellspacing="0">
1213             <tr>
1214             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#ArrayRef">ArrayRef</a> [ <a href="https://metacpan.org/pod/Types::Standard#Transfer">Transfer</a> ]</td>
1215             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">not in constructor</td>
1216             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
1217             </tr>
1218             </table>
1219              
1220             <p></p>
1221              
1222             =end HTML
1223              
1224             =begin markdown
1225              
1226             <table cellpadding="0" cellspacing="0">
1227             <tr>
1228             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Standard#ArrayRef">ArrayRef</a> [ <a href="https://metacpan.org/pod/Types::Standard#Transfer">Transfer</a> ]</td>
1229             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">not in constructor</td>
1230             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td>
1231             </tr>
1232             </table>
1233              
1234             <p></p>
1235              
1236             =end markdown
1237              
1238             =head1 METHODS
1239              
1240             =head2 routing_for
1241              
1242             my $routing = $graph->routing_for($origin_station, $destination_station);
1243              
1244             C<$origin_station> and C<$destination_station> can be either a station id, a station name or a L<Station|Map::Metro::Graph::Station> object. Both are required, but they can be of different types.
1245              
1246             Returns a L<Routing|Map::Metro::Graph::Routing>.
1247              
1248             =head2 all_pairs
1249              
1250             Takes no arguments. Returns an array reference of L<Routings|Map::Metro::Graph::Routing> between every combination of L<Stations|Map::Metro::Graph::Station>.
1251              
1252             =head2 asps
1253              
1254             L<Map::Metro> uses L<Graph> under the hood. This method returns the L<Graph/"All-Pairs Shortest Paths (APSP)"> object returned
1255             by the APSP_Floyd_Warshall() method. If you prefer to traverse the graph via this object, observe that the vertices is identified
1256             by their C<line_station_id> in L<Map::Metro::Graph::LineStation>.
1257              
1258             Call this method after creation if you prefer long startup times but faster searches.
1259              
1260             =head2 full_graph
1261              
1262             This returns the complete L<Graph> object created from parsing the map.
1263              
1264             =head1 SOURCE
1265              
1266             L<https://github.com/Csson/p5-Map-Metro>
1267              
1268             =head1 HOMEPAGE
1269              
1270             L<https://metacpan.org/release/Map-Metro>
1271              
1272             =head1 AUTHOR
1273              
1274             Erik Carlsson <info@code301.com>
1275              
1276             =head1 COPYRIGHT AND LICENSE
1277              
1278             This software is copyright (c) 2016 by Erik Carlsson.
1279              
1280             This is free software; you can redistribute it and/or modify it under
1281             the same terms as the Perl 5 programming language system itself.
1282              
1283             =cut