295 lines
7.9 KiB
Dart
295 lines
7.9 KiB
Dart
|
|
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:bus_infotainment/audio_cache.dart';
|
|
import 'package:bus_infotainment/backend/live_information.dart';
|
|
import 'package:bus_infotainment/backend/modules/info_module.dart';
|
|
import 'package:bus_infotainment/utils/NameBeautify.dart';
|
|
import 'package:bus_infotainment/utils/OrdinanceSurveyUtils.dart';
|
|
import 'package:fast_csv/csv_converter.dart';
|
|
import 'package:vector_math/vector_math.dart';
|
|
|
|
class BusSequences extends InfoModule {
|
|
|
|
Map<String, BusRoute> routes = {};
|
|
|
|
Map<String, BusDestination> destinations = {};
|
|
|
|
BusSequences.fromCSV(String destinationsCSV, String busSequencesCSV) {
|
|
|
|
// Init the bus destinations
|
|
List<List<String>> destinationRows = CsvConverter().convert(destinationsCSV);
|
|
destinationRows.removeAt(0);
|
|
|
|
print("Destination rows: ${destinationRows.length}");
|
|
|
|
for (int i = 0; i < destinationRows.length; i++) {
|
|
try {
|
|
|
|
List<dynamic> entries = destinationRows[i];
|
|
// print("Parsing destination row $i: $entries");
|
|
|
|
String routeNumber = entries[0].toString();
|
|
|
|
BusRoute route = routes.containsKey(routeNumber) ? routes[routeNumber]! : BusRoute(routeNumber: routeNumber);
|
|
|
|
String blind = entries[1].toString();
|
|
|
|
double lat = double.parse(entries[2].toString());
|
|
double long = double.parse(entries[3].toString());
|
|
|
|
Vector2 grid = OSGrid.toNorthingEasting(lat, long);
|
|
|
|
BusDestination destination = BusDestination();
|
|
destination.destination = blind;
|
|
destination.easting = grid.x;
|
|
destination.northing = grid.y;
|
|
|
|
route.destinations.add(destination);
|
|
|
|
routes[routeNumber] = route;
|
|
destinations[blind] = destination;
|
|
} catch (e) {}
|
|
}
|
|
|
|
print("Loaded ${destinations.length} destinations");
|
|
|
|
// Init the bus routes
|
|
|
|
List<List<dynamic>> busSequenceRows = CsvConverter().convert(busSequencesCSV);
|
|
busSequenceRows.removeAt(0);
|
|
|
|
for (int i = 0; i < busSequenceRows.length; i++) {
|
|
|
|
try
|
|
{
|
|
|
|
List<dynamic> entries = busSequenceRows[i];
|
|
// print("Parsing bus sequence row $i: $entries");
|
|
|
|
String routeNumber = entries[0].toString();
|
|
|
|
BusRoute route = routes.containsKey(routeNumber) ? routes[routeNumber]! : BusRoute(routeNumber: routeNumber);
|
|
|
|
int routeVariant = int.parse(entries[1]);
|
|
|
|
BusRouteStop stop = BusRouteStop();
|
|
|
|
stop.stopName = entries[6].toString();
|
|
stop.stopCode = entries[4].toString();
|
|
stop.easting = int.parse(entries[7]);
|
|
stop.northing = int.parse(entries[8]);
|
|
stop.heading = int.parse(entries[9] != "" ? entries[9] : "-1");
|
|
|
|
BusRouteVariant variant = route.routeVariants.containsKey(routeVariant) ? route.routeVariants[routeVariant]! : BusRouteVariant(routeVariant: routeVariant, busRoute: route);
|
|
|
|
variant.busStops.add(stop);
|
|
|
|
|
|
route.routeVariants[routeVariant] = variant;
|
|
routes[routeNumber] = route;
|
|
|
|
}
|
|
catch (e) {
|
|
print("Error parsing bus sequence: $e");
|
|
}
|
|
}
|
|
|
|
print("Loaded ${routes.length} routes");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class BusRoute {
|
|
|
|
String routeNumber = "";
|
|
|
|
List<BusDestination> destinations = [];
|
|
|
|
AnnouncementCache? announcementCache;
|
|
|
|
Map<int, BusRouteVariant> routeVariants = {};
|
|
|
|
BusRoute({
|
|
this.routeNumber = "-1",
|
|
this.announcementCache,
|
|
});
|
|
|
|
}
|
|
|
|
class BusRouteVariant {
|
|
|
|
int routeVariant = -1;
|
|
|
|
List<BusRouteStop> busStops = [];
|
|
|
|
late BusRoute busRoute;
|
|
|
|
BusRouteVariant({
|
|
this.routeVariant = -1,
|
|
required this.busRoute,
|
|
});
|
|
|
|
BusDestination? _destination;
|
|
BusDestination? get destination {
|
|
if (_destination == null) {
|
|
|
|
// Get the nearest destination
|
|
BusDestination? nearestDestinationA;
|
|
double nearestDistanceA = double.infinity;
|
|
|
|
Vector2 stopLocation = Vector2(busStops.last.northing.toDouble(), busStops.last.easting.toDouble());
|
|
|
|
for (BusDestination destination in busRoute.destinations) {
|
|
|
|
Vector2 destinationLocation = Vector2(destination.northing.toDouble(), destination.easting.toDouble());
|
|
|
|
double distance = stopLocation.distanceTo(destinationLocation);
|
|
|
|
if (distance < nearestDistanceA) {
|
|
nearestDestinationA = destination;
|
|
nearestDistanceA = distance;
|
|
}
|
|
|
|
}
|
|
|
|
// get the nearest destination from global pool of destinations
|
|
BusDestination? nearestDestinationB;
|
|
double nearestDistanceB = double.infinity;
|
|
|
|
for (BusDestination destination in LiveInformation().busSequences.destinations.values) {
|
|
|
|
Vector2 destinationLocation = Vector2(destination.northing.toDouble(), destination.easting.toDouble());
|
|
|
|
double distance = stopLocation.distanceTo(destinationLocation);
|
|
|
|
if (distance < nearestDistanceB) {
|
|
nearestDestinationB = destination;
|
|
nearestDistanceB = distance;
|
|
}
|
|
|
|
}
|
|
|
|
print("Nearest destination A: $nearestDestinationA, distance: $nearestDistanceA");
|
|
print("Nearest destination B: $nearestDestinationB, distance: $nearestDistanceB");
|
|
|
|
// Choose the nearest destination
|
|
if (nearestDistanceA < nearestDistanceB) {
|
|
_destination = nearestDestinationA;
|
|
} else {
|
|
_destination = nearestDestinationB;
|
|
}
|
|
|
|
}
|
|
|
|
return _destination;
|
|
}
|
|
|
|
@override
|
|
String toString() {
|
|
return 'BusRouteVariant{routeVariant: $routeVariant, busRoute: ${busRoute.routeNumber}, busStops: ${busStops.length}, destinations: ${busRoute.destinations.length}}';
|
|
}
|
|
}
|
|
|
|
class BusRouteStop {
|
|
|
|
String stopName = "";
|
|
|
|
int easting = -1;
|
|
int northing = -1;
|
|
int heading = -1;
|
|
|
|
String stopCode = "";
|
|
|
|
String get formattedStopName {
|
|
return NameBeautify.beautifyStopName(stopName);
|
|
}
|
|
|
|
String getAudioFileName() {
|
|
|
|
// Convert the stop name to all caps
|
|
String stopName = this.stopName.toUpperCase();
|
|
|
|
stopName = NameBeautify.beautifyStopName(stopName);
|
|
|
|
// replace & with N
|
|
stopName = stopName.replaceAll('&', 'N');
|
|
|
|
stopName = stopName.replaceAll('/', '');
|
|
|
|
stopName = stopName.replaceAll('\'', '');
|
|
|
|
stopName = stopName.replaceAll(' ', ' ');
|
|
|
|
// Replace space with underscore
|
|
stopName = stopName.replaceAll(' ', '_');
|
|
|
|
// convert to all caps
|
|
stopName = stopName.toUpperCase();
|
|
|
|
stopName = "S_${stopName}_001.mp3";
|
|
|
|
return stopName;
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class BusDestination {
|
|
|
|
String destination = "";
|
|
|
|
double easting = -1;
|
|
double northing = -1;
|
|
|
|
Future<Uint8List> getAudioBytes() async {
|
|
|
|
// Convert the stop name to all caps
|
|
String name = destination.toUpperCase();
|
|
|
|
name = NameBeautify.beautifyStopName(name);
|
|
|
|
// replace & with N
|
|
name = name.replaceAll('&', 'N');
|
|
|
|
name = name.replaceAll('/', '');
|
|
|
|
name = name.replaceAll('\'', '');
|
|
|
|
name = name.replaceAll(' ', ' ');
|
|
|
|
// Replace space with underscore
|
|
name = name.replaceAll(' ', '_');
|
|
|
|
// convert to all caps
|
|
name = name.toUpperCase();
|
|
|
|
String audioNameA = "D_${name}_001.mp3";
|
|
String audioNameB = "S_${name}_001.mp3";
|
|
String audioNameC = "A_${name}_001.mp3";
|
|
|
|
print("Audio name A: $audioNameA");
|
|
print("Audio name B: $audioNameB");
|
|
print("Audio name C: $audioNameC");
|
|
|
|
await LiveInformation().announcementModule.announcementCache.loadAnnouncementsFromBytes(await LiveInformation().announcementModule.getBundleBytes(), [audioNameA, audioNameB, audioNameC]);
|
|
|
|
Uint8List? audioBytesA = LiveInformation().announcementModule.announcementCache[audioNameA];
|
|
Uint8List? audioBytesB = LiveInformation().announcementModule.announcementCache[audioNameB];
|
|
Uint8List? audioBytesC = LiveInformation().announcementModule.announcementCache[audioNameC];
|
|
|
|
if (audioBytesA != null) return audioBytesA;
|
|
if (audioBytesB != null) return audioBytesB;
|
|
if (audioBytesC != null) return audioBytesC;
|
|
|
|
print("No audio bytes found for $name");
|
|
|
|
return Uint8List(0);
|
|
|
|
}
|
|
|
|
|
|
} |