diff options
| author | Birte Kristina Friesel <birte.friesel@uos.de> | 2025-07-10 19:17:48 +0200 | 
|---|---|---|
| committer | Birte Kristina Friesel <birte.friesel@uos.de> | 2025-07-10 19:17:48 +0200 | 
| commit | d6cca3f837337c12095cb71f694f68fb66cc4ccb (patch) | |
| tree | fafd5f0265921b1eecec02cf1ca348a0ce2174b4 /lib/Travelynx/Model/InTransit.pm | |
| parent | 24a01da9e9555edc3b1097b49db036f7e14e27cc (diff) | |
in transit: show estimated train position and full route (greyed out)2.15.13
Diffstat (limited to 'lib/Travelynx/Model/InTransit.pm')
| -rw-r--r-- | lib/Travelynx/Model/InTransit.pm | 133 | 
1 files changed, 133 insertions, 0 deletions
| 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; | 
