diff options
Diffstat (limited to 'lib/DBInfoscreen/Controller/Map.pm')
-rw-r--r-- | lib/DBInfoscreen/Controller/Map.pm | 750 |
1 files changed, 156 insertions, 594 deletions
diff --git a/lib/DBInfoscreen/Controller/Map.pm b/lib/DBInfoscreen/Controller/Map.pm index cea5155..bced612 100644 --- a/lib/DBInfoscreen/Controller/Map.pm +++ b/lib/DBInfoscreen/Controller/Map.pm @@ -1,6 +1,6 @@ package DBInfoscreen::Controller::Map; -# Copyright (C) 2011-2020 Daniel Friesel +# Copyright (C) 2011-2020 Birte Kristina Friesel # # SPDX-License-Identifier: AGPL-3.0-or-later @@ -10,7 +10,7 @@ use Mojo::Promise; use DateTime; use DateTime::Format::Strptime; -use Geo::Distance; +use GIS::Distance; use List::Util qw(); my $strp = DateTime::Format::Strptime->new( @@ -18,22 +18,27 @@ my $strp = DateTime::Format::Strptime->new( time_zone => 'Europe/Berlin', ); +# Input: +# - polyline: Travel::Status::DE::HAFAS::Journey->polyline +# - from_name: station name +# - to_name: station name +# Ouptut: +# - from_index: polyline index that corresponds to from_name +# - to_index: polyline index that corresponds to to_name sub get_route_indexes { - my ( $features, $from_name, $to_name ) = @_; + my ( $polyline, $from_name, $to_name ) = @_; my ( $from_index, $to_index ); - for my $i ( 0 .. $#{$features} ) { - my $this_point = $features->[$i]; + for my $i ( 0 .. $#{$polyline} ) { + my $this_point = $polyline->[$i]; if ( not defined $from_index - and $this_point->{properties}{type} - and $this_point->{properties}{type} eq 'stop' - and $this_point->{properties}{name} eq $from_name ) + and $this_point->{name} + and $this_point->{name} eq $from_name ) { $from_index = $i; } - elsif ( $this_point->{properties}{type} - and $this_point->{properties}{type} eq 'stop' - and $this_point->{properties}{name} eq $to_name ) + elsif ( $this_point->{name} + and $this_point->{name} eq $to_name ) { $to_index = $i; last; @@ -42,108 +47,30 @@ sub get_route_indexes { return ( $from_index, $to_index ); } -# Returns timestamped train positions between stop1 and stop2 (must not have -# intermittent stops) in 10-second steps. -sub estimate_timestamped_positions { - my (%opt) = @_; - - my $from_dt = $opt{from}{dep}; - my $to_dt = $opt{to}{arr}; - my $from_name = $opt{from}{name}; - my $to_name = $opt{to}{name}; - my $features = $opt{features}; - - my $duration = $to_dt->epoch - $from_dt->epoch; - - my @train_positions; - - my @completion_ratios - = map { ( $_ * 10 / $duration ) } ( 0 .. $duration / 10 ); - - my ( $from_index, $to_index ) - = get_route_indexes( $features, $from_name, $to_name ); - - my $location_epoch = $from_dt->epoch; - my $geo = Geo::Distance->new; - - if ( defined $from_index and defined $to_index ) { - my $total_distance = 0; - for my $j ( $from_index + 1 .. $to_index ) { - my $prev = $features->[ $j - 1 ]{geometry}{coordinates}; - my $this = $features->[$j]{geometry}{coordinates}; - if ( $prev and $this ) { - $total_distance += $geo->distance( - 'kilometer', $prev->[0], $prev->[1], - $this->[0], $this->[1] - ); - } - } - my @marker_distances = map { $total_distance * $_ } @completion_ratios; - $total_distance = 0; - for my $j ( $from_index + 1 .. $to_index ) { - my $prev = $features->[ $j - 1 ]{geometry}{coordinates}; - my $this = $features->[$j]{geometry}{coordinates}; - if ( $prev and $this ) { - my $prev_distance = $total_distance; - $total_distance += $geo->distance( - 'kilometer', $prev->[0], $prev->[1], - $this->[0], $this->[1] - ); - for my $i ( @train_positions .. $#marker_distances ) { - my $marker_distance = $marker_distances[$i]; - if ( $total_distance > $marker_distance ) { - - # completion ratio for the line between (prev, this) - my $sub_ratio = 1; - if ( $total_distance != $prev_distance ) { - $sub_ratio = ( $marker_distance - $prev_distance ) - / ( $total_distance - $prev_distance ); - } - - my $lat = $prev->[1] - + ( $this->[1] - $prev->[1] ) * $sub_ratio; - my $lon = $prev->[0] - + ( $this->[0] - $prev->[0] ) * $sub_ratio; - - push( @train_positions, - [ $location_epoch, $lat, $lon ] ); - $location_epoch += 10; - } - } - if ( @train_positions == @completion_ratios ) { - return @train_positions; - } - } - } - if (@train_positions) { - return @train_positions; - } - } - return; -} - # Input: # now: DateTime # from: current/previous stop # {dep => DateTime, name => str, lat => float, lon => float} # to: next stop # {arr => DateTime, name => str, lat => float, lon => float} -# features: https://github.com/public-transport/hafas-client/blob/4/docs/trip.md features array +# route: Travel::Status::DE::HAFAS::Journey->route +# polyline: Travel::Status::DE::HAFAS::Journey->polyline (list of lon/lat hashes) # Output: list of estimated train positions in [lat, lon] format. # - current position # - position 2 seconds from now # - position 4 seconds from now # - ... sub estimate_train_positions { - my (%opt) = @_; + my ( $self, %opt ) = @_; my $now = $opt{now}; - my $from_dt = $opt{from}{dep} // $opt{from}{arr}; - my $to_dt = $opt{to}{arr} // $opt{to}{dep}; - my $from_name = $opt{from}{name}; - my $to_name = $opt{to}{name}; - my $features = $opt{features}; + my $from_dt = $opt{from}->dep // $opt{from}->arr; + my $to_dt = $opt{to}->arr // $opt{to}->dep; + my $from_name = $opt{from}->loc->name; + my $to_name = $opt{to}->loc->name; + my $route = $opt{route}; + my $polyline = $opt{polyline}; my @train_positions; @@ -153,34 +80,32 @@ sub estimate_train_positions { my @completion_ratios = map { ( $time_complete + ( $_ * 2 ) ) / $time_total } ( 0 .. 45 ); - my $geo = Geo::Distance->new; + my $distance = GIS::Distance->new; my ( $from_index, $to_index ) - = get_route_indexes( $features, $from_name, $to_name ); + = get_route_indexes( $polyline, $from_name, $to_name ); if ( defined $from_index and defined $to_index ) { my $total_distance = 0; for my $j ( $from_index + 1 .. $to_index ) { - my $prev = $features->[ $j - 1 ]{geometry}{coordinates}; - my $this = $features->[$j]{geometry}{coordinates}; + my $prev = $polyline->[ $j - 1 ]; + my $this = $polyline->[$j]; if ( $prev and $this ) { - $total_distance += $geo->distance( - 'kilometer', $prev->[0], $prev->[1], - $this->[0], $this->[1] - ); + $total_distance + += $distance->distance_metal( $prev->{lat}, $prev->{lon}, + $this->{lat}, $this->{lon} ); } } my @marker_distances = map { $total_distance * $_ } @completion_ratios; $total_distance = 0; for my $j ( $from_index + 1 .. $to_index ) { - my $prev = $features->[ $j - 1 ]{geometry}{coordinates}; - my $this = $features->[$j]{geometry}{coordinates}; + my $prev = $polyline->[ $j - 1 ]; + my $this = $polyline->[$j]; if ( $prev and $this ) { my $prev_distance = $total_distance; - $total_distance += $geo->distance( - 'kilometer', $prev->[0], $prev->[1], - $this->[0], $this->[1] - ); + $total_distance + += $distance->distance_metal( $prev->{lat}, $prev->{lon}, + $this->{lat}, $this->{lon} ); for my $i ( @train_positions .. $#marker_distances ) { my $marker_distance = $marker_distances[$i]; if ( $total_distance > $marker_distance ) { @@ -192,10 +117,10 @@ sub estimate_train_positions { / ( $total_distance - $prev_distance ); } - my $lat = $prev->[1] - + ( $this->[1] - $prev->[1] ) * $sub_ratio; - my $lon = $prev->[0] - + ( $this->[0] - $prev->[0] ) * $sub_ratio; + my $lat = $prev->{lat} + + ( $this->{lat} - $prev->{lat} ) * $sub_ratio; + my $lon = $prev->{lon} + + ( $this->{lon} - $prev->{lon} ) * $sub_ratio; push( @train_positions, [ $lat, $lon ] ); } @@ -210,16 +135,23 @@ sub estimate_train_positions { } } else { + $self->log->debug( + "Did not find route indexes for $from_name → $to_name"); + $self->log->debug( +"Falling back to $opt{from}{lat} $opt{from}{lon} → $opt{to}{lat} $opt{to}{lon}" + ); for my $ratio (@completion_ratios) { my $lat - = $opt{from}{lat} + ( $opt{to}{lat} - $opt{from}{lat} ) * $ratio; + = $opt{from}->loc->lat + + ( $opt{to}->loc->lat - $opt{from}->loc->lat ) * $ratio; my $lon - = $opt{from}{lon} + ( $opt{to}{lon} - $opt{from}{lon} ) * $ratio; + = $opt{from}->loc->lon + + ( $opt{to}->loc->lon - $opt{from}->loc->lon ) * $ratio; push( @train_positions, [ $lat, $lon ] ); } return @train_positions; } - return [ $opt{to}{lat}, $opt{to}{lon} ]; + return [ $opt{to}->loc->lat, $opt{to}->loc->lon ]; } # Input: @@ -230,7 +162,7 @@ sub estimate_train_positions { # name: str # arr: DateTime # dep: DateTime -# features: ref to transport.rest features list +# polyline: ref to Travel::Status::DE::HAFAS::Journey polyline list # Output: # next_stop: {type, station} # positions: [current position [lat, lon], 2s from now, 4s from now, ...] @@ -241,27 +173,28 @@ sub estimate_train_positions2 { my @train_positions; my $next_stop; - my $geo = Geo::Distance->new; + my $distance = GIS::Distance->new; my $stop_distance_sum = 0; my $avg_inter_stop_beeline = 0; for my $i ( 1 .. $#route ) { if ( not $next_stop - and ( $route[$i]{arr} // $route[$i]{dep} ) - and ( $route[ $i - 1 ]{dep} // $route[ $i - 1 ]{arr} ) - and $now > ( $route[ $i - 1 ]{dep} // $route[ $i - 1 ]{arr} ) - and $now < ( $route[$i]{arr} // $route[$i]{dep} ) ) + and ( $route[$i]->arr // $route[$i]->dep ) + and ( $route[ $i - 1 ]->dep // $route[ $i - 1 ]->arr ) + and $now > ( $route[ $i - 1 ]->dep // $route[ $i - 1 ]->arr ) + and $now < ( $route[$i]->arr // $route[$i]->dep ) ) { # HAFAS does not provide delays for past stops $self->backpropagate_delay( $route[ $i - 1 ], $route[$i] ); # (current position, future positons...) in 2 second steps - @train_positions = estimate_train_positions( + @train_positions = $self->estimate_train_positions( from => $route[ $i - 1 ], to => $route[$i], now => $now, - features => $opt{features}, + route => $opt{route}, + polyline => $opt{polyline}, ); $next_stop = { @@ -274,18 +207,16 @@ sub estimate_train_positions2 { and $now <= ( $route[ $i - 1 ]{dep} // $route[ $i - 1 ]{arr} ) ) { @train_positions - = ( [ $route[ $i - 1 ]{lat}, $route[ $i - 1 ]{lon} ] ); + = ( [ $route[ $i - 1 ]->loc->lat, $route[ $i - 1 ]->loc->lon ] ); $next_stop = { type => 'present', station => $route[ $i - 1 ], }; } - $stop_distance_sum += $geo->distance( - 'meter', - $route[ $i - 1 ]{lon}, - $route[ $i - 1 ]{lat}, - $route[$i]{lon}, $route[$i]{lat} - ); + $stop_distance_sum += $distance->distance_metal( + $route[ $i - 1 ]->loc->lat, $route[ $i - 1 ]->loc->lon, + $route[$i]->loc->lat, $route[$i]->loc->lon + ) / 1000; } if ($#route) { @@ -293,7 +224,7 @@ sub estimate_train_positions2 { } if ( @route and not $next_stop ) { - @train_positions = ( [ $route[-1]{lat}, $route[-1]{lon} ] ); + @train_positions = ( [ $route[-1]->loc->lat, $route[-1]->loc->lon ] ); $next_stop = { type => 'present', station => $route[-1] @@ -310,161 +241,18 @@ sub estimate_train_positions2 { }; } -sub estimate_train_intersection { - my (%opt) = @_; - my @route1 = @{ $opt{routes}[0] // [] }; - my @route2 = @{ $opt{routes}[1] // [] }; - - my $ret; - - my $i1 = 0; - my $i2 = 0; - - my @pairs; - my @meeting_points; - my $geo = Geo::Distance->new; - - # skip last route element as we compare route[i] with route[i+1] - while ( $i1 < $#route1 and $i2 < $#route2 ) { - my $dep1 = $route1[$i1]{dep}; - my $arr1 = $route1[ $i1 + 1 ]{arr}; - my $dep2 = $route2[$i2]{dep}; - my $arr2 = $route2[ $i2 + 1 ]{arr}; - - if ( not( $dep1 and $arr1 ) ) { - - #say "skip 1 $route1[$i1]{name}"; - $i1++; - next; - } - - if ( not( $dep2 and $arr2 ) ) { - - #say "skip 2 $route2[$i2]{name}"; - $i2++; - next; - } - - if ( $arr1 <= $dep2 ) { - $i1++; - } - elsif ( $arr2 <= $dep1 ) { - $i2++; - } - elsif ( $arr2 <= $arr1 ) { - push( @pairs, [ $i1, $i2 ] ); - if ( $route1[$i1]{name} eq $route2[ $i2 + 1 ]{name} - and $route2[$i2]{name} eq $route1[ $i1 + 1 ]{name} ) - { - # both i1 name == i2+1 name and i1 name == i2 name are valid cases - # (trains don't just intersect when they travel in opposing - # directions -- they may also travel in the same direction - # with different speed and overtake each other). - # We need both stop pairs later on, so we save both. - $ret->{stop_pair} = [ - [ $route1[$i1]{name}, $route1[ $i1 + 1 ]{name} ], - [ $route2[$i2]{name}, $route2[ $i2 + 1 ]{name} ] - ]; - } - $i2++; - } - elsif ( $arr1 <= $arr2 ) { - push( @pairs, [ $i1, $i2 ] ); - if ( $route1[$i1]{name} eq $route2[ $i2 + 1 ]{name} - and $route2[$i2]{name} eq $route1[ $i1 + 1 ]{name} ) - { - $ret->{stop_pair} = [ - [ $route1[$i1]{name}, $route1[ $i1 + 1 ]{name} ], - [ $route2[$i2]{name}, $route2[ $i2 + 1 ]{name} ] - ]; - } - $i1++; - } - else { - $i1++; - } - } - - for my $pair (@pairs) { - my ( $i1, $i2 ) = @{$pair}; - my @train1_positions = estimate_timestamped_positions( - from => $route1[$i1], - to => $route1[ $i1 + 1 ], - features => $opt{features}[0], - ); - my @train2_positions = estimate_timestamped_positions( - from => $route2[$i2], - to => $route2[ $i2 + 1 ], - features => $opt{features}[1], - ); - $i1 = 0; - $i2 = 0; - while ( $i1 <= $#train1_positions and $i2 <= $#train2_positions ) { - if ( $train1_positions[$i1][0] < $train2_positions[$i2][0] ) { - $i1++; - } - elsif ( $train1_positions[$i2][0] < $train2_positions[$i2][0] ) { - $i2++; - } - else { - if ( - ( - my $distance = $geo->distance( - 'kilometer', - $train1_positions[$i1][2], - $train1_positions[$i1][1], - $train2_positions[$i2][2], - $train2_positions[$i2][1] - ) - ) < 1 - ) - { - my $ts = DateTime->from_epoch( - epoch => $train1_positions[$i1][0], - time_zone => 'Europe/Berlin' - ); - $ret->{first_meeting_time} //= $ts; - push( - @meeting_points, - { - timestamp => $ts, - lat => ( - $train1_positions[$i1][1] - + $train2_positions[$i2][1] - ) / 2, - lon => ( - $train1_positions[$i1][2] - + $train2_positions[$i2][2] - ) / 2, - distance => $distance, - } - ); - } - $i1++; - $i2++; - } - } - } - - $ret->{meeting_points} = \@meeting_points; - - return $ret; -} - sub route_to_ajax { my (@stopovers) = @_; my @route_entries; for my $stop (@stopovers) { - my @stop_entries = ( $stop->{stop}{name} ); + my @stop_entries = ( $stop->loc->name ); my $platform; - if ( $stop->{arrival} - and my $arr = $strp->parse_datetime( $stop->{arrival} ) ) - { - my $delay = ( $stop->{arrivalDelay} // 0 ) / 60; - $platform = $stop->{arrivalPlatform}; + if ( my $arr = $stop->arr and not $stop->arr_cancelled ) { + my $delay = $stop->arr_delay // 0; + $platform = $stop->platform; push( @stop_entries, $arr->epoch, $delay ); } @@ -472,11 +260,9 @@ sub route_to_ajax { push( @stop_entries, q{}, q{} ); } - if ( $stop->{departure} - and my $dep = $strp->parse_datetime( $stop->{departure} ) ) - { - my $delay = ( $stop->{departureDelay} // 0 ) / 60; - $platform //= $stop->{departurePlatform} // q{}; + if ( my $dep = $stop->dep and not $stop->dep_cancelled ) { + my $delay = $stop->dep_delay // 0; + $platform //= $stop->platform // q{}; push( @stop_entries, $dep->epoch, $delay, $platform ); } @@ -490,56 +276,6 @@ sub route_to_ajax { return join( '|', @route_entries ); } -# Input: List of transport.rest stopovers -# Output: List of preprocessed stops. Each is a hash with the following keys: -# lat: float -# lon: float -# name: str -# arr: DateTime -# dep: DateTime -# arr_delay: int -# dep_delay: int -# platform: str -sub stopovers_to_route { - my (@stopovers) = @_; - my @route; - - for my $stop (@stopovers) { - my @stop_lines = ( $stop->{stop}{name} ); - my ( $platform, $arr, $dep, $arr_delay, $dep_delay ); - - if ( $stop->{arrival} - and $arr = $strp->parse_datetime( $stop->{arrival} ) ) - { - $arr_delay = ( $stop->{arrivalDelay} // 0 ) / 60; - $platform //= $stop->{arrivalPlatform}; - } - - if ( $stop->{departure} - and $dep = $strp->parse_datetime( $stop->{departure} ) ) - { - $dep_delay = ( $stop->{departureDelay} // 0 ) / 60; - $platform //= $stop->{departurePlatform}; - } - - push( - @route, - { - lat => $stop->{stop}{location}{latitude}, - lon => $stop->{stop}{location}{longitude}, - name => $stop->{stop}{name}, - arr => $arr, - dep => $dep, - arr_delay => $arr_delay, - dep_delay => $dep_delay, - platform => $platform, - } - ); - - } - return @route; -} - sub polyline_to_line_pairs { my (@polyline) = @_; my @line_pairs; @@ -547,138 +283,14 @@ sub polyline_to_line_pairs { push( @line_pairs, [ - [ $polyline[ $i - 1 ][1], $polyline[ $i - 1 ][0] ], - [ $polyline[$i][1], $polyline[$i][0] ] + [ $polyline[ $i - 1 ]{lat}, $polyline[ $i - 1 ]{lon} ], + [ $polyline[$i]{lat}, $polyline[$i]{lon} ] ] ); } return @line_pairs; } -sub intersection { - my ($self) = @_; - - my @trips = split( qr{;}, $self->stash('trips') ); - my @trip_ids = map { [ split( qr{,}, $_ ) ] } @trips; - - $self->render_later; - - my @polyline_requests - = map { $self->hafas->get_polyline_p( @{$_} ) } @trip_ids; - Mojo::Promise->all(@polyline_requests)->then( - sub { - my ( $pl1, $pl2 ) = map { $_->[0] } @_; - my @polyline1 = @{ $pl1->{polyline} }; - my @polyline2 = @{ $pl2->{polyline} }; - my @station_coordinates; - - my @markers; - my $next_stop; - - my $now = DateTime->now( time_zone => 'Europe/Berlin' ); - - my @line1_pairs = polyline_to_line_pairs(@polyline1); - my @line2_pairs = polyline_to_line_pairs(@polyline2); - - my @route1 - = stopovers_to_route( @{ $pl1->{raw}{stopovers} // [] } ); - my @route2 - = stopovers_to_route( @{ $pl2->{raw}{stopovers} // [] } ); - - my $train1_pos = $self->estimate_train_positions2( - now => $now, - route => \@route1, - features => $pl1->{raw}{polyline}{features}, - ); - - my $train2_pos = $self->estimate_train_positions2( - now => $now, - route => \@route2, - features => $pl2->{raw}{polyline}{features}, - ); - - my $intersection = estimate_train_intersection( - routes => [ \@route1, \@route2 ], - features => [ - $pl1->{raw}{polyline}{features}, - $pl2->{raw}{polyline}{features} - ], - ); - - for my $meeting_point ( @{ $intersection->{meeting_points} } ) { - push( - @station_coordinates, - [ - [ $meeting_point->{lat}, $meeting_point->{lon} ], - [ $meeting_point->{timestamp}->strftime('%H:%M') ] - ] - ); - } - - push( - @markers, - { - lat => $train1_pos->{position_now}[0], - lon => $train1_pos->{position_now}[1], - title => $pl1->{name} - }, - { - lat => $train2_pos->{position_now}[0], - lon => $train2_pos->{position_now}[1], - title => $pl2->{name} - }, - ); - - $self->render( - 'route_map', - title => "DBF", - hide_opts => 1, - with_map => 1, - intersection => 1, - train1_no => - scalar( $pl1->{raw}{line}{additionalName} // $pl1->{name} ), - train2_no => - scalar( $pl2->{raw}{line}{additionalName} // $pl2->{name} ), - likely_pair => $intersection->{stop_pair} - ? $intersection->{stop_pair}[0] - : undef, - time => scalar $intersection->{first_meeting_time}, - polyline_groups => [ - { - polylines => [ @line1_pairs, @line2_pairs ], - color => '#ffffff', - opacity => 0, - fit_bounds => 1, - }, - { - polylines => [@line1_pairs], - color => '#005080', - opacity => 0.6, - }, - { - polylines => [@line2_pairs], - color => '#800050', - opacity => 0.6, - } - ], - markers => [@markers], - station_coordinates => [@station_coordinates], - ); - } - )->catch( - sub { - my ($err) = @_; - $self->render( - 'route_map', - title => "DBF", - hide_opts => 1, - with_map => 1, - error => $err, - ); - } - )->wait; -} - sub backpropagate_delay { my ( $self, $prev_stop, $next_stop ) = @_; @@ -702,17 +314,30 @@ sub route { my ($self) = @_; my $trip_id = $self->stash('tripid'); my $line_no = $self->stash('lineno'); + my $hafas = $self->param('hafas'); my $from_name = $self->param('from'); my $to_name = $self->param('to'); $self->render_later; - $self->hafas->get_polyline_p( $trip_id, $line_no )->then( + my $service = 'DB'; + if ( $hafas + and $hafas ne '1' + and Travel::Status::DE::HAFAS::get_service($hafas) ) + { + $service = $hafas; + } + + $self->hafas->get_polyline_p( + id => $trip_id, + line => $line_no, + service => $service + )->then( sub { - my ($pl) = @_; + my ($journey) = @_; - my @polyline = @{ $pl->{polyline} }; + my @polyline = $journey->polyline; my @station_coordinates; my @markers; @@ -723,61 +348,61 @@ sub route { # used to draw the train's journey on the map my @line_pairs = polyline_to_line_pairs(@polyline); - my @route = stopovers_to_route( @{ $pl->{raw}{stopovers} // [] } ); + my @route = $journey->route; my $train_pos = $self->estimate_train_positions2( now => $now, route => \@route, - features => $pl->{raw}{polyline}{features}, + polyline => \@polyline, ); # Prepare from/to markers and name/time/delay overlays for stations for my $stop (@route) { - my @stop_lines = ( $stop->{name} ); + my @stop_lines = ( $stop->loc->name ); - if ( $from_name and $stop->{name} eq $from_name ) { + if ( $from_name and $stop->loc->name eq $from_name ) { push( @markers, { - lon => $stop->{lon}, - lat => $stop->{lat}, - title => $stop->{name}, + lon => $stop->loc->lon, + lat => $stop->loc->lat, + title => $stop->loc->name, icon => 'goldIcon', } ); } - if ( $to_name and $stop->{name} eq $to_name ) { + if ( $to_name and $stop->loc->name eq $to_name ) { push( @markers, { - lon => $stop->{lon}, - lat => $stop->{lat}, - title => $stop->{name}, + lon => $stop->loc->lon, + lat => $stop->loc->lat, + title => $stop->loc->name, icon => 'greenIcon', } ); } - if ( $stop->{platform} ) { - push( @stop_lines, 'Gleis ' . $stop->{platform} ); + if ( $stop->platform ) { + push( @stop_lines, 'Gleis ' . $stop->platform ); } - if ( $stop->{arr} ) { - my $arr_line = $stop->{arr}->strftime('Ankunft: %H:%M'); - if ( $stop->{arr_delay} ) { - $arr_line .= sprintf( ' (%+d)', $stop->{arr_delay} ); + if ( $stop->arr ) { + my $arr_line = $stop->arr->strftime('Ankunft: %H:%M'); + if ( $stop->arr_delay ) { + $arr_line .= sprintf( ' (%+d)', $stop->arr_delay ); } push( @stop_lines, $arr_line ); } - if ( $stop->{dep} ) { - my $dep_line = $stop->{dep}->strftime('Abfahrt: %H:%M'); - if ( $stop->{dep_delay} ) { - $dep_line .= sprintf( ' (%+d)', $stop->{dep_delay} ); + if ( $stop->dep ) { + my $dep_line = $stop->dep->strftime('Abfahrt: %H:%M'); + if ( $stop->dep_delay ) { + $dep_line .= sprintf( ' (%+d)', $stop->dep_delay ); } push( @stop_lines, $dep_line ); } push( @station_coordinates, - [ [ $stop->{lat}, $stop->{lon} ], [@stop_lines], ] ); + [ [ $stop->loc->lat, $stop->loc->lon ], [@stop_lines], ] ); } push( @@ -785,34 +410,33 @@ sub route { { lat => $train_pos->{position_now}[0], lon => $train_pos->{position_now}[1], - title => $pl->{name} + title => $journey->name } ); $next_stop = $train_pos->{next_stop}; $self->render( 'route_map', - title => $pl->{name}, - hide_opts => 1, - with_map => 1, - ajax_req => "${trip_id}/${line_no}", - ajax_route => route_to_ajax( @{ $pl->{raw}{stopovers} // [] } ), + description => "Karte für " . $journey->name, + title => $journey->name, + hide_opts => 1, + with_map => 1, + ajax_req => "${trip_id}/${line_no}", + ajax_route => route_to_ajax( $journey->route ), ajax_polyline => join( '|', map { join( ';', @{$_} ) } @{ $train_pos->{positions} } ), origin => { - name => $pl->{raw}{origin}{name}, - ts => $pl->{raw}{departure} - ? scalar $strp->parse_datetime( $pl->{raw}{departure} ) - : undef, + name => ( $journey->route )[0]->loc->name, + ts => ( $journey->route )[0]->dep, }, destination => { - name => $pl->{raw}{destination}{name}, - ts => $pl->{raw}{arrival} - ? scalar $strp->parse_datetime( $pl->{raw}{arrival} ) - : undef, + name => $journey->route_end, + ts => ( $journey->route )[-1]->arr, }, - train_no => scalar $pl->{raw}{line}{additionalName}, - operator => scalar $pl->{raw}{line}{operator}{name}, + train_no => $journey->number + ? ( $journey->type . ' ' . $journey->number ) + : undef, + operator => $journey->operator, next_stop => $next_stop, polyline_groups => [ { @@ -823,7 +447,7 @@ sub route { } ], station_coordinates => [@station_coordinates], - station_radius => + station_radius => ( $train_pos->{avg_inter_stop_beeline} > 500 ? 250 : 100 ), markers => [@markers], ); @@ -847,44 +471,56 @@ sub ajax_route { my ($self) = @_; my $trip_id = $self->stash('tripid'); my $line_no = $self->stash('lineno'); + my $hafas = $self->param('hafas'); delete $self->stash->{layout}; $self->render_later; - $self->hafas->get_polyline_p( $trip_id, $line_no )->then( + my $service = 'DB'; + if ( $hafas + and $hafas ne '1' + and Travel::Status::DE::HAFAS::get_service($hafas) ) + { + $service = $hafas; + } + + $self->hafas->get_polyline_p( + id => $trip_id, + line => $line_no, + service => $service + )->then( sub { - my ($pl) = @_; + my ($journey) = @_; my $now = DateTime->now( time_zone => 'Europe/Berlin' ); - my @route = stopovers_to_route( @{ $pl->{raw}{stopovers} // [] } ); + my @route = $journey->route; + my @polyline = $journey->polyline; my $train_pos = $self->estimate_train_positions2( now => $now, route => \@route, - features => $pl->{raw}{polyline}{features}, + polyline => \@polyline, ); - my @polyline = @{ $pl->{polyline} }; $self->render( '_map_infobox', - ajax_req => "${trip_id}/${line_no}", - ajax_route => route_to_ajax( @{ $pl->{raw}{stopovers} // [] } ), + ajax_req => "${trip_id}/${line_no}", + ajax_route => route_to_ajax(@route), ajax_polyline => join( '|', map { join( ';', @{$_} ) } @{ $train_pos->{positions} } ), origin => { - name => $pl->{raw}{origin}{name}, - ts => $pl->{raw}{departure} - ? scalar $strp->parse_datetime( $pl->{raw}{departure} ) - : undef, + name => ( $journey->route )[0]->loc->name, + ts => ( $journey->route )[0]->dep, }, destination => { - name => $pl->{raw}{destination}{name}, - ts => $pl->{raw}{arrival} - ? scalar $strp->parse_datetime( $pl->{raw}{arrival} ) - : undef, + name => $journey->route_end, + ts => ( $journey->route )[-1]->arr, }, + train_no => $journey->number + ? ( $journey->type . ' ' . $journey->number ) + : undef, next_stop => $train_pos->{next_stop}, ); } @@ -899,78 +535,4 @@ sub ajax_route { )->wait; } -sub search { - my ($self) = @_; - - my $t1 = $self->param('train1'); - my $t2 = $self->param('train2'); - - my $t1_data; - my $t2_data; - - my @requests; - - if ( not( $t1 and $t1 =~ m{^\S+\s+\d+$} ) - or ( $t2 and not $t2 =~ m{^\S+\s+\d+$} ) ) - { - $self->render( - 'trainsearch', - title => 'Fahrtverlauf', - hide_opts => 1, - error => $t1 - ? "Züge müssen im Format 'Zugtyp Nummer' angegeben werden, z.B. 'RE 1234'" - : undef, - ); - return; - } - - $self->render_later; - - push( @requests, $self->hafas->trainsearch_p( train_no => $t1 ) ); - - if ($t2) { - push( @requests, $self->hafas->trainsearch_p( train_no => $t2 ) ); - } - - Mojo::Promise->all(@requests)->then( - sub { - my ( $t1_data, $t2_data ) = @_; - - if ($t2_data) { - $self->redirect_to( - sprintf( - "/intersection/%s,0;%s,0", - $t1_data->[0]{trip_id}, - $t2_data->[0]{trip_id}, - ) - ); - } - else { - $self->redirect_to( - sprintf( "/map/%s/0", $t1_data->[0]{trip_id}, ) ); - } - } - )->catch( - sub { - my ($err) = @_; - $self->render( - 'trainsearch', - title => 'Fahrtverlauf', - hide_opts => 1, - error => $err - ); - } - )->wait; -} - -sub search_form { - my ($self) = @_; - - $self->render( - 'trainsearch', - title => 'Fahrtverlauf', - hide_opts => 1, - ); -} - 1; |