Map-Metro

 view release on metacpan or  search on metacpan

lib/Map/Metro/Graph.pm  view on Meta::CPAN


    foreach my $conn ($self->all_connections) {
        $graph->add_weighted_edge($conn->origin_line_station->line_station_id,
                                  $conn->destination_line_station->line_station_id,
                                  $conn->weight);
    }
    return $graph;
}
sub calculate_shortest_paths { shift->full_graph->APSP_Floyd_Warshall }

sub nocase {
    my $text = shift;
    if($] >= 5.016000) {
        $text = fc $text;
    }
    else {
        $text = lc $text;
    }
    return $text;
}

sub parse {
    my $self = shift;

    $self->build_network;
    $self->construct_connections;

    return $self;
}

sub build_network {
    my $self = shift;

    my @rows = split /\r?\n/ => $self->filepath->slurp_utf8;
    my $context = undef;

    ROW:
    foreach my $row (@rows) {
        next ROW if !length $row || $row =~ m{^[ \t]*#};

        if($row =~ m{^--(\w+)} && (any { $_ eq $1 } qw/stations transfers lines segments/)) {
            $context = $1;
            next ROW;
        }

          $context eq 'stations'  ? $self->add_station($row)
        : $context eq 'transfers' ? $self->add_transfer($row)
        : $context eq 'lines'     ? $self->add_line($row)
        : $context eq 'segments'  ? $self->add_segment($row)
        :                           ()
        ;
    }
}

around add_station => sub {
    my $next = shift;
    my $self = shift;
    my $text = shift;

    $text = trim $text;
    my @names = split m{\h*%\h*} => $text;
    my $name = shift @names;

    if(my $station = $self->get_station_by_name($name, check => 0)) {
        return $station;
    }

    my $id = $self->station_count + 1;
    my $station = Map::Metro::Graph::Station->new(original_name => $name, do_undiacritic => $self->do_undiacritic, eh $name, $id);

    foreach my $another_name (@names) {
        if($another_name =~ m{^:(.+)}) {
            $station->add_search_name($1);
        }
        else {
            $station->add_alternative_name($another_name);
        }
    }
    $self->emit->before_add_station($station);
    $self->$next($station);
};

around add_transfer => sub {
    my $next = shift;
    my $self = shift;
    my $text = shift;

    $text = trim $text;

    my($origin_station_name, $destination_station_name, $option_string) = split /\|/ => $text;
    my $origin_station = $self->get_station_by_name($origin_station_name);
    my $destination_station = $self->get_station_by_name($destination_station_name);

    my $options = defined $option_string ? $self->make_options($option_string, keys => [qw/weight/]) : {};

    my $transfer = Map::Metro::Graph::Transfer->new(origin_station => $origin_station,
                                                    destination_station => $destination_station,
                                                    %$options);

    $self->$next($transfer);
};

around add_line => sub {
    my $next = shift;
    my $self = shift;
    my $text = shift;

    $text = trim $text;
    my($id, $name, $description, $option_string) = split /\|/ => $text;

    my $options = defined $option_string ? $self->make_options($option_string, keys => [qw/color width/]) : {};
    my $line = Map::Metro::Graph::Line->new(%{ $options }, id => $id, name => $name, description => $description);

    $self->$next($line);
};

around add_segment => sub {
    my $next = shift;
    my $self = shift;
    my $text = shift;

    $text = trim $text;
    my($linestring, $start, $end, $option_string) = split /\|/ => $text;
    my @line_ids_with_dir = split m/,/ => $linestring;
    my @clean_line_ids = map { (my $clean = $_) =~ s{[^a-z0-9]}{}gi; $clean } @line_ids_with_dir;

    my $options = defined $option_string ? $self->make_options($option_string, keys => [qw/dir/]) : {};

    #* Check that lines and stations in segments exist in the other lists
    my($origin_station, $destination_station);

    try {
        $self->get_line_by_id($_) foreach @clean_line_ids;
        $origin_station = $self->get_station_by_name($start);
        $destination_station = $self->get_station_by_name($end);
    }
    catch {
        die($_->$_call_if_object('desc') || $_);
    };
    my @both_dir = ();
    my @forward = ();
    my @backward = ();
    my @segments = ();

    foreach my $line_info (@line_ids_with_dir) {
        if($line_info =~ m{^[a-z0-9]+$}i) {
            push @both_dir => $line_info;
        }
        elsif($line_info =~ m{^([a-z0-9]+)->$}i) {
            push @forward => $1;
        }
        elsif($line_info =~ m{^([a-z0-9]+)<-$}i) {
            push @backward => $1;
        }
    }

    if(scalar @both_dir) {
        push @segments => Map::Metro::Graph::Segment->new(line_ids => \@both_dir, origin_station => $origin_station, destination_station => $destination_station);
    }
    if(scalar @forward) {
        push @segments => Map::Metro::Graph::Segment->new(line_ids => \@forward, is_one_way => 1, origin_station => $origin_station, destination_station => $destination_station);
    }
    if(scalar @backward) {
        push @segments => Map::Metro::Graph::Segment->new(line_ids => \@backward, is_one_way => 1, origin_station => $destination_station, destination_station => $origin_station);
    }

    $self->$next(@segments);
};

around add_line_station => sub {
    my $next = shift;
    my $self = shift;
    my $line_station = shift;

    my $exists = $self->get_line_station_by_line_and_station_id($line_station->line->id, $line_station->station->id);
    return $exists if $exists;

    $self->$next($line_station);
    return $line_station;
};

sub get_line_by_id {
    my $self = shift;
    my $line_id = shift; # Str



( run in 1.334 second using v1.01-cache-2.11-cpan-71847e10f99 )