diff options
Diffstat (limited to 'lib')
| -rwxr-xr-x | lib/Travelynx.pm | 70 | ||||
| -rwxr-xr-x | lib/Travelynx/Controller/Traveling.pm | 9 | ||||
| -rw-r--r-- | lib/Travelynx/Model/InTransit.pm | 133 | 
3 files changed, 203 insertions, 9 deletions
| diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm index 78642ff..7dba658 100755 --- a/lib/Travelynx.pm +++ b/lib/Travelynx.pm @@ -1615,10 +1615,10 @@ sub startup {  						rt_arrival    =>  						  ( $stop->[2]{rt_arr} || $stop->[2]{sched_arr} )  					); -					if ($stop->[2]{platform}) { +					if ( $stop->[2]{platform} ) {  						$self->in_transit->set_arrival_platform( -							uid => $uid, -							db => $db, +							uid              => $uid, +							db               => $db,  							arrival_platform => $stop->[2]{platform}  						);  					} @@ -2704,14 +2704,43 @@ sub startup {  					latlon => $_->{from_latlon} // $_->{dep_latlon}  				  }  			} @journeys; +			my @extra_stations; + +			if ( $opt{show_all_stops} ) { +				for my $journey (@journeys) { +					my @j_stops = map { +						{ +							name   => $_->[2], +							latlon => [ $_->[1], $_->[0] ] +						} +					} grep { defined $_->[2] } +					  @{ $journey->{polyline} // [] }; +					@extra_stations +					  = uniq_by { $_->{name} } ( @extra_stations, @j_stops ); +				} +			}  			my @station_coordinates  			  = map { [ $_->{latlon}, $_->{name} ] } @stations; +			my @extra_station_coordinates +			  = map { [ $_->{latlon}, $_->{name} ] } @extra_stations; + +			my @now_coordinates = map { +				[ +					$_->{now_latlon}, +					$_->{train_type} . ' ' +					  . ( $_->{train_line} // $_->{train_no} ) +				] +			} @journeys;  			my @station_pairs;  			my @polylines;  			my %seen; +			# not part of the travelled route, but trip route before/after the journey. +			# Only used if show_full_route is set. +			my @extra_polylines; +  			my @skipped_journeys;  			my @polyline_journeys = grep { $_->{polyline} } @journeys;  			my @beeline_journeys  = grep { not $_->{polyline} } @journeys; @@ -2787,12 +2816,28 @@ sub startup {  				if ( $from_index > $to_index ) {  					( $to_index, $from_index ) = ( $from_index, $to_index );  				} +				if ( $opt{show_full_route} ) { +					my @pre_polyline  = @polyline[ 0 .. $from_index ]; +					my @post_polyline = @polyline[ $to_index .. $#polyline ]; +					my @pre_polyline_coords; +					for my $coord (@pre_polyline) { +						push( @pre_polyline_coords, +							[ $coord->[1], $coord->[0] ] ); +					} +					my @post_polyline_coords; +					for my $coord (@post_polyline) { +						push( @post_polyline_coords, +							[ $coord->[1], $coord->[0] ] ); +					} +					push( @extra_polylines, +						( \@pre_polyline_coords, \@post_polyline_coords ) ); +				}  				@polyline = @polyline[ $from_index .. $to_index ];  				my @polyline_coords;  				for my $coord (@polyline) {  					push( @polyline_coords, [ $coord->[1], $coord->[0] ] );  				} -				push( @polylines, [@polyline_coords] ); +				push( @polylines, \@polyline_coords );  			}  			for my $journey (@beeline_journeys) { @@ -2900,7 +2945,7 @@ sub startup {  					{  						polylines => $json->encode( \@station_pairs ),  						color     => '#673ab7', -						opacity   => @polylines +						opacity   => scalar @polylines  						? $with_polyline  						      ? 0.4  						      : 0.6 @@ -2910,8 +2955,14 @@ sub startup {  						polylines => $json->encode( \@polylines ),  						color     => '#673ab7',  						opacity   => 0.8, -					} +					}, +					{ +						polylines => $json->encode( \@extra_polylines ), +						color     => '#665577', +						opacity   => 0.6, +					},  				], +				markers => \@now_coordinates,  			};  			if (@station_coordinates) { @@ -2925,6 +2976,13 @@ sub startup {  				  = [ [ $min_lat, $min_lon ], [ $max_lat, $max_lon ] ];  			} +			if (@extra_station_coordinates) { +				$ret->{station_coordinates} = [ +					uniq_by { $_->[1] } +					( @station_coordinates, @extra_station_coordinates ) +				]; +			} +  			return $ret;  		}  	); diff --git a/lib/Travelynx/Controller/Traveling.pm b/lib/Travelynx/Controller/Traveling.pm index 6176415..a28ae98 100755 --- a/lib/Travelynx/Controller/Traveling.pm +++ b/lib/Travelynx/Controller/Traveling.pm @@ -370,7 +370,8 @@ sub homepage {  			my $map_data = {};  			if ( $status->{arr_name} ) {  				$map_data = $self->journeys_to_map_data( -					journeys => [$status], +					journeys        => [$status], +					show_full_route => 1,  				);  			}  			my $journey_visibility @@ -460,7 +461,8 @@ sub status_card {  		my $map_data = {};  		if ( $status->{arr_name} ) {  			$map_data = $self->journeys_to_map_data( -				journeys => [$status], +				journeys        => [$status], +				show_full_route => 1,  			);  		}  		my $journey_visibility @@ -2492,7 +2494,8 @@ sub edit_journey {  					$key => $journey->{$key}->strftime('%d.%m.%Y %H:%M:%S') );  			}  			else { -				$self->param( $key => $journey->{$key}->strftime('%d.%m.%Y %H:%M') ); +				$self->param( +					$key => $journey->{$key}->strftime('%d.%m.%Y %H:%M') );  			}  		}  	} diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index 16946ff..40c96c8 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -10,6 +10,7 @@ use warnings;  use 5.020;  use DateTime; +use GIS::Distance;  use JSON;  my %visibility_itoa = ( @@ -633,6 +634,7 @@ sub get {  	if ( $opt{with_polyline} and $ret ) {  		$ret->{dep_latlon} = [ $ret->{dep_lat}, $ret->{dep_lon} ];  		$ret->{arr_latlon} = [ $ret->{arr_lat}, $ret->{arr_lon} ]; +		$ret->{now_latlon} = $self->estimate_trip_position($ret);  	}  	if ( $opt{with_visibility} and $ret ) { @@ -1549,4 +1551,135 @@ sub update_visibility {  	);  } +sub estimate_trip_position_between_stops { +	my ( $self, %opt ) = @_; + +	my $time_complete = $opt{now} - $opt{from_ts}; +	my $time_total    = $opt{to_ts} - $opt{from_ts}; +	my $ratio         = $time_complete / $time_total; + +	my $distance = GIS::Distance->new; +	my $polyline = $opt{polyline}; +	my ( $i_from, $i_to ); + +	for my $i ( 0 .. $#{$polyline} ) { +		if (    not defined $i_from +			and $polyline->[$i][2] +			and $polyline->[$i][2] == $opt{from}[1] ) +		{ +			$i_from = $i; +		} +		elsif ( not defined $i_to +			and $polyline->[$i][2] +			and $polyline->[$i][2] == $opt{to}[1] ) +		{ +			$i_to = $i; +			last; +		} +	} +	if ( $i_from and $i_to ) { +		my $total_distance = 0; +		for my $i ( $i_from + 1 .. $i_to ) { +			my $prev = $polyline->[ $i - 1 ]; +			my $this = $polyline->[$i]; +			if ( $prev and $this ) { +				$total_distance +				  += $distance->distance_metal( $prev->[1], $prev->[0], +					$this->[1], $this->[0] ); +			} +		} + +		my $marker_distance = $total_distance * $ratio; +		$total_distance = 0; +		for my $i ( $i_from + 1 .. $i_to ) { +			my $prev = $polyline->[ $i - 1 ]; +			my $this = $polyline->[$i]; +			if ( $prev and $this ) { +				my $prev_distance = $total_distance; +				$total_distance +				  += $distance->distance_metal( $prev->[1], $prev->[0], +					$this->[1], $this->[0] ); +				if ( $total_distance > $marker_distance ) { +					my $sub_ratio = 1; +					if ( $total_distance != $prev_distance ) { +						$sub_ratio = ( $marker_distance - $prev_distance ) +						  / ( $total_distance - $prev_distance ); +					} +					return ( +						$prev->[1] + ( $this->[1] - $prev->[1] ) * $sub_ratio, +						$prev->[0] + ( $this->[0] - $prev->[0] ) * $sub_ratio, +					); +				} +			} +		} +	} +	return ( +		$opt{from}[2]{lat} + ( $opt{to}[2]{lat} - $opt{from}[2]{lat} ) * $ratio, +		$opt{from}[2]{lon} + ( $opt{to}[2]{lon} - $opt{from}[2]{lon} ) * $ratio +	); +} + +sub estimate_trip_position { +	my ( $self, $in_transit ) = @_; + +	my @now_latlon; +	my $next_stop; +	my @route = @{ $in_transit->{route} }; + +	# estimate_train_position runs before postprocess, so all route +	# timestamps are provided in UNIX seconds and not as DateTime objects. +	my $now = DateTime->now( time_zone => 'Europe/Berlin' )->epoch; + +	if ( +		0 +		and $now <= ( +			$route[0][2]{rt_arr} // $route[0][2]{sched_arr} +			  // $route[0][2]{rt_dep} // $route[0][2]{sched_dep} // 0 +		) +	  ) +	{ +		return [ $route[0][2]{lat}, $route[0][2]{lon} ]; +	} + +	my $prev_ts; +	for my $i ( 0 .. $#route ) { +		my $ts = $route[$i][2]{rt_arr} // $route[$i][2]{sched_arr} +		  // $route[$i][2]{rt_dep} // $route[$i][2]{sched_dep} // 0; +		if (    not $next_stop +			and $ts +			and $prev_ts +			and $now > $prev_ts +			and $now < $ts ) +		{ +			@now_latlon = $self->estimate_trip_position_between_stops( +				now      => $now, +				from     => $route[ $i - 1 ], +				from_ts  => $prev_ts, +				to       => $route[$i], +				to_ts    => $ts, +				polyline => $in_transit->{polyline}, +			); +			$next_stop = { +				type    => 'next', +				station => $route[$i], +			}; +		} +		$prev_ts = $ts; +	} + +	# Actually, the vehicle's position isn't well-known in this case. +	#if (not @now_latlon and $in_transit->{sched_dep_ts} and $in_transit->{sched_arr_ts}) { +	#	my $time_complete = $now - ($in_transit->{real_dep_ts} // $in_transit->{sched_dep_ts}); +	#	my $time_total = ($in_transit->{real_arr_ts} // $in_transit->{sched_arr_ts}) - ($in_transit->{real_dep_ts} // $in_transit->{sched_dep_ts}); +	#	my $completion = $time_complete / $time_total; +	#	$completion = $completion < 0 ? 0 : $completion > 1 ? 1 : $completion; +	#	@now_latlon = ( +	#		$in_transit->{dep_lat} + ($in_transit->{arr_lat} - $in_transit->{dep_lat}) * $completion, +	#		$in_transit->{dep_lon} + ($in_transit->{arr_lon} - $in_transit->{dep_lon}) * $completion, +	#	); +	#} + +	return \@now_latlon; +} +  1; | 
