Files
Bus-Infotainment--IBus-/lib/backend/modules/tracker.dart
ImBenji c2ebac5bb5 shtuff
2024-05-01 19:28:51 +01:00

215 lines
6.6 KiB
Dart

import 'dart:async';
import 'dart:math';
import 'dart:typed_data';
import 'package:bus_infotainment/backend/live_information.dart';
import 'package:bus_infotainment/backend/modules/info_module.dart';
import 'package:bus_infotainment/tfl_datasets.dart';
import 'package:bus_infotainment/utils/OrdinanceSurveyUtils.dart';
import 'package:bus_infotainment/utils/audio%20wrapper.dart';
import 'package:flutter/foundation.dart';
import 'package:geolocator/geolocator.dart';
import 'package:vector_math/vector_math.dart';
class TrackerModule extends InfoModule {
// Constructor
TrackerModule() {
locationStream();
if (!kIsWeb)
{
Geolocator.getLastKnownPosition().then((Position? position) {
this._position = position;
updateNearestStop();
});
}
liveInformation.routeVariantDelegate.addListener((routeVariant) {
print("Route variant changed");
updateNearestStop();
});
}
// Location Tracker - will update the recorded location when the user moves.
Position? _position;
Position? get position => _position;
StreamSubscription<Position> locationStream() => Geolocator.getPositionStream(
locationSettings: const LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 1,
)
).listen((Position position) {
if (position == null) {
return;
}
this._position = position;
updateNearestStop();
});
// Location Refresher - will update the recorded location periodically.
Timer refreshTimer() => Timer.periodic(Duration(seconds: 1), (timer) async {
_position = await Geolocator.getCurrentPosition();
});
BusRouteStop? nearestStop;
bool hasArrived = false;
Future<void> updateNearestStop() async {
if (liveInformation.getRouteVariant() == null) {
return;
}
// Get the closest stop
BusRouteStop closestStop = liveInformation.getRouteVariant()!.busStops.first;
double closestDistance = OSGrid
.toNorthingEasting(_position!.latitude, _position!.longitude)
.distanceTo(Vector2(closestStop.easting.toDouble(), closestStop.northing.toDouble()));
for (BusRouteStop stop in liveInformation.getRouteVariant()!.busStops) {
double distance = OSGrid
.toNorthingEasting(_position!.latitude, _position!.longitude)
.distanceTo(Vector2(stop.easting.toDouble(), stop.northing.toDouble()));
if (distance < closestDistance) {
closestStop = stop;
closestDistance = distance;
}
}
double relativeDistance = _calculateRelativeDistance(closestStop, _position!.latitude, _position!.longitude);
if (relativeDistance < -10) {
print("Closest stop is behind us: ${closestStop.formattedStopName}");
print("Relative distance: $relativeDistance");
int stopIndex = liveInformation.getRouteVariant()!.busStops.indexOf(closestStop);
int maxStops = liveInformation.getRouteVariant()!.busStops.length;
closestStop = liveInformation.getRouteVariant()!.busStops[min(stopIndex + 1, maxStops)];
print("Closest stop is now: ${closestStop.formattedStopName}");
} else {
print("Closest stop is in front of us: ${closestStop.formattedStopName}");
}
bool preExisting = true;
if (nearestStop != closestStop) {
nearestStop = closestStop;
hasArrived = false;
preExisting = false;
}
print("Closest stop is the same as before");
double distance = OSGrid
.toNorthingEasting(_position!.latitude, _position!.longitude)
.distanceTo(Vector2(nearestStop!.easting.toDouble(), nearestStop!.northing.toDouble()));
// get the speed in mph
double speed = _position!.speed * 2.23694;
print("Speed: $speed");
Duration? duration;
{
// Testing some audio stuff
Uint8List? audioBytes = liveInformation.announcementModule.announcementCache[nearestStop!.getAudioFileName()];
if (audioBytes != null) {
AudioWrapperByteSource audioSource = AudioWrapperByteSource(audioBytes!);
AudioWrapper audio = AudioWrapper();
await audio.loadSource(audioSource);
duration = await audio.getDuration();
print("Duration of audio: $duration");
} else {
print("Audio bytes are null");
duration = Duration(seconds: 0);
}
}
// get the estimated distance travelled in 5 seconds, in meters
double distanceTravelled = speed * (3 + duration!.inSeconds);
// adjust for the it takes to send the announcement to other devices
distance -= distanceTravelled;
// get the time to the stop in seconds
double timeToStop = distance / speed;
print("Distance to stop: $distance");
print("Time to stop: $timeToStop");
int secondsBefore = 7;
print("Seconds before: $secondsBefore");
if ((timeToStop < secondsBefore ) && !hasArrived && relativeDistance > 0) {
print("We are at the stop");
hasArrived = true;
liveInformation.announcementModule.queueAnnounceByAudioName(
displayText: "${nearestStop!.formattedStopName}",
audioNames: [
// "A_NEXT_STOP_001.mp3",
nearestStop!.getAudioFileName()
],
sendToServer: true
);
}
if (!hasArrived && !preExisting) {
liveInformation.announcementModule.queueAnnounceByAudioName(
displayText: "${closestStop.formattedStopName}",
audioNames: [],
sendToServer: true
);
}
print("Closest stop: ${closestStop.formattedStopName} in ${closestDistance.round()} meters");
}
}
double _calculateRelativeDistance(BusRouteStop stop, double latitude, double longitude) {
List<double> toLatLong = OSGrid.toLatLong(stop.northing.toDouble(), stop.easting.toDouble());
Vector2 stopPoint = OSGrid.toNorthingEasting(toLatLong[0], toLatLong[1]);
Vector2 currentPoint = OSGrid.toNorthingEasting(latitude, longitude);
// calculate the heading from the current point to the stop point
// 0 degrees is north, 90 degrees is east, 180 degrees is south, 270 degrees is west
double toHeading = degrees(atan2(stopPoint.x - currentPoint.x, stopPoint.y - currentPoint.y));
toHeading = (toHeading + 360) % 360;
// get the dot product of the heading and the stop heading
double dotProduct = cos(radians(toHeading)) * cos(radians(stop.heading.toDouble())) + sin(radians(toHeading)) * sin(radians(stop.heading.toDouble()));
return (dotProduct.sign) * _calculateDistance(latitude, longitude, toLatLong[0], toLatLong[1]);
}
double _calculateDistance(double lat1, double lon1, double lat2, double lon2) {
// Convert to eastings and northings
Vector2 point1 = OSGrid.toNorthingEasting(lat1, lon1);
Vector2 point2 = OSGrid.toNorthingEasting(lat2, lon2);
return point1.distanceTo(point2);
}