diff --git a/Cargo.lock b/Cargo.lock index 91f6ebe..b6d331f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -674,9 +674,9 @@ dependencies = [ [[package]] name = "geo-types" -version = "0.7.11" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9705398c5c7b26132e74513f4ee7c1d7dafd786004991b375c172be2be0eecaa" +checksum = "9ff16065e5720f376fbced200a5ae0f47ace85fd70b7e54269790281353b6d61" dependencies = [ "approx", "num-traits", diff --git a/Cargo.toml b/Cargo.toml index c4e678f..9693e93 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ chrono-tz = "0.8.3" color-eyre = "0.6.2" csv = "1.3.0" geo = "0.26.0" -geo-types = "0.7.11" +geo-types = "0.7.13" geojson = "0.24.1" gtfs-rt = "0.3.0" gtfs-structures = "0.36.1" diff --git a/README.md b/README.md index 8dbcd05..6cd3785 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ cargo run --bin processstatic 3. Zip the folder `anteater_gtfs` with no underlying folder inside the final zip ```bash -zip -r anteater_express.zip anteater_express/ +zip -r anteater_gtfs.zip anteater_express/ ``` Now your Anteater static file is done! diff --git a/anteater_express.zip b/anteater_gtfs.zip similarity index 70% rename from anteater_express.zip rename to anteater_gtfs.zip index bf74896..eac788c 100644 Binary files a/anteater_express.zip and b/anteater_gtfs.zip differ diff --git a/anteater_gtfs/calendar.txt b/anteater_gtfs/calendar.txt index 0d4d663..732fbfe 100644 --- a/anteater_gtfs/calendar.txt +++ b/anteater_gtfs/calendar.txt @@ -1,3 +1,3 @@ service_id,monday,tuesday,wednesday,thursday,friday,saturday,sunday,start_date,end_date -monthurs,1,1,1,1,1,1,1,20230925,20231215 +monthurs,1,1,1,1,1,1,1,20240108,20240322 fri,0,0,0,0,1,0,0,20240108,20240322 diff --git a/anteater_gtfs/shapes.txt b/anteater_gtfs/shapes.txt index 4fcdb63..08f8730 100644 --- a/anteater_gtfs/shapes.txt +++ b/anteater_gtfs/shapes.txt @@ -295,108 +295,95 @@ shape_id,shape_pt_lat,shape_pt_lon,shape_pt_sequence,shape_dist_traveled 8006668shape,33.64842,-117.83832,76, 8006668shape,33.64873,-117.83891,77, 8006668shape,33.64917,-117.83958,78, -8006670shape,33.64895,-117.8451,0, -8006670shape,33.64897,-117.84489,1, -8006670shape,33.649,-117.84477,2, -8006670shape,33.64914,-117.84412,3, -8006670shape,33.64942,-117.84348,4, -8006670shape,33.64971,-117.84313,5, -8006670shape,33.64999,-117.84294,6, -8006670shape,33.65008,-117.84283,7, -8006670shape,33.65064,-117.84247,8, -8006670shape,33.65086,-117.84217,9, -8006670shape,33.65099,-117.84182,10, -8006670shape,33.64699,-117.82957,11, -8006670shape,33.64685,-117.82955,12, -8006670shape,33.6462,-117.82932,13, -8006670shape,33.64576,-117.82926,14, -8006670shape,33.64559,-117.82921,15, -8006670shape,33.64521,-117.82918,16, -8006670shape,33.64488,-117.82919,17, -8006670shape,33.64412,-117.82925,18, -8006670shape,33.64315,-117.82946,19, -8006670shape,33.64249,-117.82969,20, -8006670shape,33.63994,-117.83006,21, -8006670shape,33.63956,-117.83015,22, -8006670shape,33.63917,-117.83034,23, -8006670shape,33.63933,-117.83069,24, -8006670shape,33.63953,-117.83124,25, -8006670shape,33.63989,-117.83247,26, -8006670shape,33.64016,-117.83303,27, -8006670shape,33.64092,-117.8344,28, -8006670shape,33.64101,-117.83455,29, -8006670shape,33.64137,-117.83505,30, -8006670shape,33.64166,-117.83539,31, -8006670shape,33.64279,-117.83642,32, -8006670shape,33.64258,-117.83697,33, -8006670shape,33.64251,-117.83748,34, -8006670shape,33.64255,-117.83795,35, -8006670shape,33.6428,-117.83905,36, -8006670shape,33.64282,-117.83962,37, -8006670shape,33.6428,-117.83987,38, -8006670shape,33.64275,-117.84033,39, -8006670shape,33.64269,-117.84062,40, -8006670shape,33.64244,-117.84153,41, -8006670shape,33.6423,-117.8425,42, -8006670shape,33.64226,-117.84267,43, -8006670shape,33.64213,-117.8431,44, -8006670shape,33.64177,-117.84392,45, -8006670shape,33.64167,-117.84441,46, -8006670shape,33.64163,-117.84559,47, -8006670shape,33.64139,-117.84694,48, -8006670shape,33.64143,-117.84759,49, -8006670shape,33.64157,-117.84801,50, -8006670shape,33.64181,-117.84842,51, -8006670shape,33.64215,-117.84877,52, -8006670shape,33.64262,-117.84901,53, -8006670shape,33.64295,-117.84909,54, -8006670shape,33.643,-117.84915,55, -8006670shape,33.64347,-117.8492,56, -8006670shape,33.64439,-117.84919,57, -8006670shape,33.64468,-117.84915,58, -8006670shape,33.64561,-117.84878,59, -8006670shape,33.64597,-117.84875,60, -8006670shape,33.6465,-117.84889,61, -8006670shape,33.64665,-117.84832,62, -8006670shape,33.64683,-117.84802,63, -8006670shape,33.64703,-117.84782,64, -8006670shape,33.64723,-117.84765,65, -8006670shape,33.64824,-117.84697,66, -8006670shape,33.6485,-117.84665,67, -8006670shape,33.64856,-117.84661,68, -8006670shape,33.64876,-117.84621,69, -8006670shape,33.64887,-117.84579,70, -8006670shape,33.64895,-117.8451,71, -8006670shape,33.64895,-117.8451,72, -8006670shape,33.64897,-117.84489,73, -8006670shape,33.649,-117.84477,74, -8006670shape,33.64914,-117.84412,75, -8006670shape,33.64942,-117.84348,76, -8006670shape,33.64971,-117.84313,77, -8006670shape,33.64999,-117.84294,78, -8006670shape,33.65008,-117.84283,79, -8006670shape,33.65064,-117.84247,80, -8006670shape,33.65086,-117.84217,81, -8006670shape,33.65099,-117.84182,82, -8006670shape,33.65099,-117.84182,83, -8006670shape,33.6507,-117.84167,84, -8006670shape,33.65016,-117.84121,85, -8006670shape,33.64983,-117.84086,86, -8006670shape,33.6498,-117.84076,87, -8006670shape,33.64924,-117.83991,88, -8006670shape,33.64924,-117.83991,89, -8006670shape,33.64856,-117.83886,90, -8006670shape,33.64842,-117.8386,91, -8006670shape,33.64815,-117.83796,92, -8006670shape,33.64806,-117.83774,93, -8006670shape,33.64793,-117.83725,94, -8006670shape,33.64777,-117.83629,95, -8006670shape,33.64776,-117.83538,96, -8006670shape,33.64777,-117.8351,97, -8006670shape,33.64797,-117.83402,98, -8006670shape,33.6488,-117.83015,99, -8006670shape,33.6488,-117.83015,100, -8006670shape,33.64699,-117.82957,101, +8006670shape,33.649056,-117.839729,0, +8006670shape,33.648943,-117.839547,1, +8006670shape,33.648842,-117.839342,2, +8006670shape,33.648693,-117.839091,3, +8006670shape,33.648416,-117.838639,4, +8006670shape,33.648267,-117.838303,5, +8006670shape,33.648145,-117.837987,6, +8006670shape,33.648024,-117.837633,7, +8006670shape,33.647872,-117.83704,8, +8006670shape,33.647815,-117.836713,9, +8006670shape,33.647791,-117.836497,10, +8006670shape,33.647762,-117.836173,11, +8006670shape,33.64774,-117.83589,12, +8006670shape,33.647742,-117.835517,13, +8006670shape,33.6478,-117.834887,14, +8006670shape,33.647887,-117.8344,15, +8006670shape,33.648029,-117.833715,16, +8006670shape,33.648577,-117.831196,17, +8006670shape,33.64877,-117.830244,18, +8006670shape,33.648719,-117.830146,19, +8006670shape,33.647759,-117.82983,20, +8006670shape,33.646856,-117.829543,21, +8006670shape,33.644618,-117.829144,22, +8006670shape,33.642305,-117.829693,23, +8006670shape,33.640753,-117.829933,24, +8006670shape,33.63925,-117.83029,25, +8006670shape,33.639204,-117.830405,26, +8006670shape,33.63932,-117.830683,27, +8006670shape,33.639513,-117.831174,28, +8006670shape,33.639909,-117.832471,29, +8006670shape,33.640343,-117.833386,30, +8006670shape,33.640992,-117.834599,31, +8006670shape,33.641685,-117.835414,32, +8006670shape,33.642695,-117.836385,33, +8006670shape,33.642686,-117.836608,34, +8006670shape,33.642581,-117.836997,35, +8006670shape,33.642521,-117.837401,36, +8006670shape,33.642533,-117.837715,37, +8006670shape,33.642807,-117.839053,38, +8006670shape,33.642854,-117.839418,39, +8006670shape,33.6428,-117.839978,40, +8006670shape,33.642754,-117.840401,41, +8006670shape,33.642508,-117.841274,42, +8006670shape,33.64239,-117.841939,43, +8006670shape,33.642191,-117.842935,44, +8006670shape,33.64192,-117.84356,45, +8006670shape,33.641718,-117.844132,46, +8006670shape,33.641654,-117.84469,47, +8006670shape,33.64165,-117.845374,48, +8006670shape,33.641616,-117.845716,49, +8006670shape,33.641471,-117.846549,50, +8006670shape,33.641413,-117.846846,51, +8006670shape,33.6414,-117.847175,52, +8006670shape,33.641418,-117.847559,53, +8006670shape,33.641576,-117.848042,54, +8006670shape,33.641866,-117.84854,55, +8006670shape,33.642263,-117.848841,56, +8006670shape,33.642616,-117.849016,57, +8006670shape,33.643076,-117.849115,58, +8006670shape,33.643423,-117.849192,59, +8006670shape,33.643949,-117.849192,60, +8006670shape,33.644605,-117.849121,61, +8006670shape,33.645028,-117.849008,62, +8006670shape,33.645546,-117.848785,63, +8006670shape,33.645893,-117.848755,64, +8006670shape,33.646156,-117.848777,65, +8006670shape,33.646387,-117.848837,66, +8006670shape,33.646461,-117.848817,67, +8006670shape,33.646556,-117.848497,68, +8006670shape,33.646676,-117.848223,69, +8006670shape,33.646866,-117.847935,70, +8006670shape,33.647485,-117.84747,71, +8006670shape,33.648184,-117.846993,72, +8006670shape,33.64844,-117.846723,73, +8006670shape,33.648608,-117.846467,74, +8006670shape,33.648784,-117.845998,75, +8006670shape,33.648864,-117.845512,76, +8006670shape,33.648994,-117.844782,77, +8006670shape,33.649133,-117.844166,78, +8006670shape,33.64934,-117.843606,79, +8006670shape,33.649618,-117.843161,80, +8006670shape,33.649948,-117.84289,81, +8006670shape,33.650469,-117.842563,82, +8006670shape,33.650775,-117.842244,83, +8006670shape,33.65095,-117.841853,84, +8006670shape,33.650506,-117.841545,85, +8006670shape,33.64997,-117.841033,86, +8006670shape,33.649725,-117.840716,87, +8006670shape,33.649173,-117.839902,88, 8006672shape,33.649283,-117.839741,0, 8006672shape,33.649804,-117.840551,1, 8006672shape,33.650117,-117.840969,2, diff --git a/overrideshapes/M.geojson b/overrideshapes/M.geojson new file mode 100644 index 0000000..04306c0 --- /dev/null +++ b/overrideshapes/M.geojson @@ -0,0 +1,371 @@ +{ + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + [ + -117.839729, + 33.649056 + ], + [ + -117.839547, + 33.648943 + ], + [ + -117.839342, + 33.648842 + ], + [ + -117.839091, + 33.648693 + ], + [ + -117.838639, + 33.648416 + ], + [ + -117.838303, + 33.648267 + ], + [ + -117.837987, + 33.648145 + ], + [ + -117.837633, + 33.648024 + ], + [ + -117.83704, + 33.647872 + ], + [ + -117.836713, + 33.647815 + ], + [ + -117.836497, + 33.647791 + ], + [ + -117.836173, + 33.647762 + ], + [ + -117.83589, + 33.64774 + ], + [ + -117.835517, + 33.647742 + ], + [ + -117.834887, + 33.6478 + ], + [ + -117.8344, + 33.647887 + ], + [ + -117.833715, + 33.648029 + ], + [ + -117.831196, + 33.648577 + ], + [ + -117.830244, + 33.64877 + ], + [ + -117.830146, + 33.648719 + ], + [ + -117.82983, + 33.647759 + ], + [ + -117.829543, + 33.646856 + ], + [ + -117.829144, + 33.644618 + ], + [ + -117.829693, + 33.642305 + ], + [ + -117.829933, + 33.640753 + ], + [ + -117.83029, + 33.63925 + ], + [ + -117.830405, + 33.639204 + ], + [ + -117.830683, + 33.63932 + ], + [ + -117.831174, + 33.639513 + ], + [ + -117.832471, + 33.639909 + ], + [ + -117.833386, + 33.640343 + ], + [ + -117.834599, + 33.640992 + ], + [ + -117.835414, + 33.641685 + ], + [ + -117.836385, + 33.642695 + ], + [ + -117.836608, + 33.642686 + ], + [ + -117.836997, + 33.642581 + ], + [ + -117.837401, + 33.642521 + ], + [ + -117.837715, + 33.642533 + ], + [ + -117.839053, + 33.642807 + ], + [ + -117.839418, + 33.642854 + ], + [ + -117.839978, + 33.6428 + ], + [ + -117.840401, + 33.642754 + ], + [ + -117.841274, + 33.642508 + ], + [ + -117.841939, + 33.64239 + ], + [ + -117.842935, + 33.642191 + ], + [ + -117.84356, + 33.64192 + ], + [ + -117.844132, + 33.641718 + ], + [ + -117.84469, + 33.641654 + ], + [ + -117.845374, + 33.64165 + ], + [ + -117.845716, + 33.641616 + ], + [ + -117.846549, + 33.641471 + ], + [ + -117.846846, + 33.641413 + ], + [ + -117.847175, + 33.6414 + ], + [ + -117.847559, + 33.641418 + ], + [ + -117.848042, + 33.641576 + ], + [ + -117.84854, + 33.641866 + ], + [ + -117.848841, + 33.642263 + ], + [ + -117.849016, + 33.642616 + ], + [ + -117.849115, + 33.643076 + ], + [ + -117.849192, + 33.643423 + ], + [ + -117.849192, + 33.643949 + ], + [ + -117.849121, + 33.644605 + ], + [ + -117.849008, + 33.645028 + ], + [ + -117.848785, + 33.645546 + ], + [ + -117.848755, + 33.645893 + ], + [ + -117.848777, + 33.646156 + ], + [ + -117.848837, + 33.646387 + ], + [ + -117.848817, + 33.646461 + ], + [ + -117.848497, + 33.646556 + ], + [ + -117.848223, + 33.646676 + ], + [ + -117.847935, + 33.646866 + ], + [ + -117.84747, + 33.647485 + ], + [ + -117.846993, + 33.648184 + ], + [ + -117.846723, + 33.64844 + ], + [ + -117.846467, + 33.648608 + ], + [ + -117.845998, + 33.648784 + ], + [ + -117.845512, + 33.648864 + ], + [ + -117.844782, + 33.648994 + ], + [ + -117.844166, + 33.649133 + ], + [ + -117.843606, + 33.64934 + ], + [ + -117.843161, + 33.649618 + ], + [ + -117.84289, + 33.649948 + ], + [ + -117.842563, + 33.650469 + ], + [ + -117.842244, + 33.650775 + ], + [ + -117.841853, + 33.65095 + ], + [ + -117.841545, + 33.650506 + ], + [ + -117.841033, + 33.64997 + ], + [ + -117.840716, + 33.649725 + ], + [ + -117.839902, + 33.649173 + ] + ], + "type": "LineString" + }, + "id": "93f167e0a8a939a769d8bcc92e7caf00" + } + ], + "type": "FeatureCollection" +} \ No newline at end of file diff --git a/overrideshapes/features (10).geojson:Zone.Identifier b/overrideshapes/features (10).geojson:Zone.Identifier deleted file mode 100644 index 1b986fe..0000000 --- a/overrideshapes/features (10).geojson:Zone.Identifier +++ /dev/null @@ -1,3 +0,0 @@ -[ZoneTransfer] -ZoneId=3 -HostUrl=https://studio.mapbox.com/ diff --git a/route-sup.json b/route-sup.json index ca1da58..33058af 100644 --- a/route-sup.json +++ b/route-sup.json @@ -74,7 +74,8 @@ "name": "M_Friday.csv", "monthurs": false } - ] + ], + "overrideshape": "overrideshapes/M.geojson" }, { "name": "N", diff --git a/src/main.rs b/src/main.rs index cfdb4c3..0d5fcba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,24 +1,23 @@ - -use serde::{Deserialize, Serialize}; -use std::collections::{BTreeMap, HashMap}; -use std::time::Instant; -use protobuf::{CodedInputStream, Message as ProtobufMessage}; -use prost::Message; -use std::time::UNIX_EPOCH; -use gtfs_rt::EntitySelector; use chrono::Datelike; -use chrono_tz::US::Pacific; -use gtfs_rt::TimeRange; -use serde_json; use chrono::TimeZone; use chrono::Timelike; use chrono_tz::Tz; +use chrono_tz::US::Pacific; use chrono_tz::UTC; +use gtfs_rt::EntitySelector; +use gtfs_rt::TimeRange; +use prost::Message; +use protobuf::{CodedInputStream, Message as ProtobufMessage}; +use serde::{Deserialize, Serialize}; +use serde_json; +use std::collections::{BTreeMap, HashMap}; +use std::time::Instant; +use std::time::UNIX_EPOCH; extern crate rand; -use rand::Rng; use crate::rand::prelude::SliceRandom; +use rand::Rng; use redis::Commands; use redis::RedisError; @@ -33,7 +32,7 @@ struct TranslocRealtime { api_latest_version: String, generated_on: String, data: BTreeMap>, - api_version: String + api_version: String, } #[derive(Serialize, Deserialize, Debug, Clone)] @@ -64,27 +63,32 @@ struct ArrivalEstimates { #[derive(Serialize, Deserialize, Debug, Clone)] struct TranslocLocation { lat: f32, - lng: f32 + lng: f32, } -fn allowtrip(trip_id: &String, trip: >fs_structures::Trip, route_id: &String, gtfs: >fs_structures::Gtfs) -> bool { - - +fn allowtrip( + trip_id: &String, + trip: >fs_structures::Trip, + route_id: &String, + gtfs: >fs_structures::Gtfs, +) -> bool { let calendarselected = gtfs.calendar.get(trip.service_id.as_str()).unwrap(); - + //is it friday in Los Angeles? // Get the timezone for Los Angeles. -let current_time = chrono::Utc::now(); + let current_time = chrono::Utc::now(); -let tz: Tz = "America/Los_Angeles".parse().unwrap(); + let tz: Tz = "America/Los_Angeles".parse().unwrap(); -// Convert this to the Los Angeles timezone. + // Convert this to the Los Angeles timezone. -let current_time_la = current_time.with_timezone(&tz); + let current_time_la = current_time.with_timezone(&tz); -let is_friday = current_time_la.weekday() == chrono::Weekday::Fri; + let is_friday = current_time_la.weekday() == chrono::Weekday::Fri; -let current_time_in_seconds = (current_time_la.hour() * 3600) + (current_time_la.minute() * 60) + current_time_la.second(); + let current_time_in_seconds = (current_time_la.hour() * 3600) + + (current_time_la.minute() * 60) + + current_time_la.second(); if trip.route_id != *route_id { return false; @@ -92,23 +96,27 @@ let current_time_in_seconds = (current_time_la.hour() * 3600) + (current_time_la /*if trip.stop_times[0].departure_time.is_some() { let departure_time = trip.stop_times[0].departure_time.as_ref().unwrap(); - + let diff = *departure_time as i32 - current_time_in_seconds as i32; //large time means the trip hasn't started yet - //negative time means the trip has already started - - + //negative time means the trip has already started + + if diff > 1500 || diff < -3600 { return false; } }*/ - let departure_comparison = trip.stop_times.iter().find(|stop_time| stop_time.departure_time.is_some()); + let departure_comparison = trip + .stop_times + .iter() + .find(|stop_time| stop_time.departure_time.is_some()); if departure_comparison.is_some() { let departure_comparison = departure_comparison.unwrap(); - let diff = departure_comparison.departure_time.unwrap() as i32 - current_time_in_seconds as i32; + let diff = + departure_comparison.departure_time.unwrap() as i32 - current_time_in_seconds as i32; if diff > 1500 || diff < -3600 { return false; @@ -116,14 +124,10 @@ let current_time_in_seconds = (current_time_la.hour() * 3600) + (current_time_la } else { } -return match is_friday { - true => { - calendarselected.friday == true - }, - false => { - calendarselected.monday == true - } - } + return match is_friday { + true => calendarselected.friday == true, + false => calendarselected.monday == true, + }; } fn arrival_estimates_length_to_end(bus: &EachBus) -> i32 { @@ -131,7 +135,7 @@ fn arrival_estimates_length_to_end(bus: &EachBus) -> i32 { 'estimation: for estimate in bus.arrival_estimates.iter() { if estimate.stop_id.is_some() { - /* + /* if estimate.stop_id.as_ref().unwrap().as_str() == "8197566" || estimate.stop_id.as_ref().unwrap().as_str() == "8274064" { break 'estimation; } @@ -139,7 +143,9 @@ fn arrival_estimates_length_to_end(bus: &EachBus) -> i32 { } if estimate.route_id.is_some() { - if estimate.route_id.as_ref().unwrap().as_str() != bus.route_id.as_ref().unwrap().as_str() { + if estimate.route_id.as_ref().unwrap().as_str() + != bus.route_id.as_ref().unwrap().as_str() + { break 'estimation; } } @@ -155,14 +161,15 @@ fn arrival_estimates_length_to_end(bus: &EachBus) -> i32 { #[tokio::main] async fn main() -> Result<(), Box> { color_eyre::install()?; - // curl https://transloc-api-1-2.p.rapidapi.com/vehicles.json?agencies=1039 - //-H "X-Mashape-Key: b0ebd9e8a5msh5aca234d74ce282p1737bbjsnddd18d7b9365" + // curl https://transloc-api-1-2.p.rapidapi.com/vehicles.json?agencies=1039 + //-H "X-Mashape-Key: b0ebd9e8a5msh5aca234d74ce282p1737bbjsnddd18d7b9365" - let redisclient = RedisClient::open("redis://127.0.0.1:6379/").unwrap(); - let mut con = redisclient.get_connection().unwrap(); + let redisclient = RedisClient::open("redis://127.0.0.1:6379/").unwrap(); + let mut con = redisclient.get_connection().unwrap(); let gtfs = gtfs_structures::GtfsReader::default() - .read("anteater_gtfs").unwrap(); + .read("anteater_gtfs") + .unwrap(); let rawgtfs = gtfs_structures::RawGtfs::new("anteater_gtfs").unwrap(); @@ -172,18 +179,18 @@ async fn main() -> Result<(), Box> { "16aff0066fmsh91bdf05e1ddc2a9p1bf246jsn4e66fe3531f2", "X7rzqy7Zx8mshBtXeYQjrv0aLyrYp1HBttujsnJ6BgNQxIMetU", "1d4175ed60msh03c8157af1f76e9p1d8e56jsnc909aeb67a68", - "fd6fe9ee6dmshb6b307335f13cdap178324jsnaa4128a7eb3c" - ]; + "fd6fe9ee6dmshb6b307335f13cdap178324jsnaa4128a7eb3c", + ]; - -let tz: Tz = "America/Los_Angeles".parse().unwrap(); + let tz: Tz = "America/Los_Angeles".parse().unwrap(); loop { let current_time = chrono::Utc::now(); let current_time_la = current_time.with_timezone(&tz); - let is_weekend = current_time_la.weekday() == chrono::Weekday::Sat || current_time_la.weekday() == chrono::Weekday::Sun; + let is_weekend = current_time_la.weekday() == chrono::Weekday::Sat + || current_time_la.weekday() == chrono::Weekday::Sun; if current_time_la.hour() < 6 || is_weekend { println!("Sleeping for 10 minutes"); @@ -199,8 +206,8 @@ let tz: Tz = "America/Los_Angeles".parse().unwrap(); let mut rng = rand::thread_rng(); let choice = *(apikeys.choose(&mut rng).unwrap()); - - let res = client.get("https://transloc-api-1-2.p.rapidapi.com/vehicles.json?agencies=1039") + let res = client + .get("https://transloc-api-1-2.p.rapidapi.com/vehicles.json?agencies=1039") .header("X-Mashape-Key", choice) .send() .await; @@ -225,7 +232,7 @@ let tz: Tz = "America/Los_Angeles".parse().unwrap(); let import_data: TranslocRealtime = serde_json::from_str(body.as_str()).unwrap(); - let mut vehicle_id_to_trip_id:HashMap = HashMap::new(); + let mut vehicle_id_to_trip_id: HashMap = HashMap::new(); let mut grouped_by_route: HashMap> = HashMap::new(); @@ -234,154 +241,235 @@ let tz: Tz = "America/Los_Angeles".parse().unwrap(); for (i, bus) in buses.iter().enumerate() { if bus.route_id.is_some() { if grouped_by_route.contains_key(bus.route_id.as_ref().unwrap()) { - grouped_by_route.get_mut(bus.route_id.as_ref().unwrap()).unwrap().push(bus.clone()); + grouped_by_route + .get_mut(bus.route_id.as_ref().unwrap()) + .unwrap() + .push(bus.clone()); } else { - grouped_by_route.insert(bus.route_id.as_ref().unwrap().clone(), vec![bus.clone()]); + grouped_by_route + .insert(bus.route_id.as_ref().unwrap().clone(), vec![bus.clone()]); } } } } }); - -let current_time = chrono::Utc::now(); + let current_time = chrono::Utc::now(); -let tz: Tz = "America/Los_Angeles".parse().unwrap(); + let tz: Tz = "America/Los_Angeles".parse().unwrap(); -// Convert this to the Los Angeles timezone. + // Convert this to the Los Angeles timezone. -let current_time_la = current_time.with_timezone(&tz); + let current_time_la = current_time.with_timezone(&tz); -let midnight = current_time_la.date().and_hms(0, 0, 0); + let midnight = current_time_la.date().and_hms(0, 0, 0); -let midnight_timestamp = midnight.timestamp(); + let midnight_timestamp = midnight.timestamp(); -let mut delay_hashmap: HashMap = HashMap::new(); + let mut delay_hashmap: HashMap = HashMap::new(); for (route_id, buses) in grouped_by_route.iter() { //let sort the buses by completion let mut sorted_buses = buses.clone(); - - sorted_buses.sort_by(|bus_a, bus_b| arrival_estimates_length_to_end(bus_a).cmp(&arrival_estimates_length_to_end(bus_b))); - println!("order of completion [{}]: {:?}", route_id, &sorted_buses.iter().map(|x| arrival_estimates_length_to_end(&x)).collect::>()); - - let mut possible_trips = gtfs.trips.iter().filter(|(trip_id,trip)| allowtrip(&trip_id, &trip, &route_id, >fs)).map(|(trip_id, trip)| trip).collect::>(); + sorted_buses.sort_by(|bus_a, bus_b| { + arrival_estimates_length_to_end(bus_a).cmp(&arrival_estimates_length_to_end(bus_b)) + }); + + println!( + "order of completion [{}]: {:?}", + route_id, + &sorted_buses + .iter() + .map(|x| arrival_estimates_length_to_end(&x)) + .collect::>() + ); + + let mut possible_trips = gtfs + .trips + .iter() + .filter(|(trip_id, trip)| allowtrip(&trip_id, &trip, &route_id, >fs)) + .map(|(trip_id, trip)| trip) + .collect::>(); possible_trips.sort_by(|trip_a, trip_b| trip_a.id.cmp(&trip_b.id)); - println!("possible trips on Route {}: {:?}",gtfs.get_route(route_id).unwrap().short_name , possible_trips.iter().map(|x| x.id.clone()).collect::>()); + println!( + "possible trips on Route {}: {:?}", + gtfs.get_route(route_id).unwrap().short_name, + possible_trips + .iter() + .map(|x| x.id.clone()) + .collect::>() + ); - for (i,bus) in (&sorted_buses).iter().enumerate() { + for (i, bus) in (&sorted_buses).iter().enumerate() { if possible_trips.len() == 0 { - vehicle_id_to_trip_id.insert(bus.vehicle_id.as_ref().unwrap().clone(), format!("extra-{}-{i}", bus.route_id.as_ref().unwrap().clone())); + vehicle_id_to_trip_id.insert( + bus.vehicle_id.as_ref().unwrap().clone(), + format!("extra-{}-{i}", bus.route_id.as_ref().unwrap().clone()), + ); } else { if possible_trips.len() == 1 { - vehicle_id_to_trip_id.insert(bus.vehicle_id.as_ref().unwrap().clone(), possible_trips[0].id.clone()); + vehicle_id_to_trip_id.insert( + bus.vehicle_id.as_ref().unwrap().clone(), + possible_trips[0].id.clone(), + ); } else { let assigned_id = possible_trips[0].id.clone(); let mut closest_past_trip: Option = None; - let mut remove_before_index:Option = None; + let mut remove_before_index: Option = None; + + let searchable_stop_times_from_bus = bus + .arrival_estimates + .iter() + .filter(|arrival_estimate| { + arrival_estimate.arrival_at.is_some() + && arrival_estimate.stop_id.is_some() + }) + .collect::>(); - let searchable_stop_times_from_bus = bus.arrival_estimates.iter().filter(|arrival_estimate| arrival_estimate.arrival_at.is_some() && arrival_estimate.stop_id.is_some()).collect::>(); - //println!("lineup {} vs {}", searchable_stop_times_from_gtfs.len(), searchable_stop_times_from_bus.len()); - let mut timedifference:Option = None; + let mut timedifference: Option = None; //search through the entire trip list - 'search_trip_list: for (tripcounter,lookingtrip) in possible_trips.iter().rev().enumerate() { - let searchable_stop_times_from_gtfs = possible_trips[tripcounter].stop_times.iter().filter(|stop_time| stop_time.departure_time.is_some()).collect::>(); - let searchable_stop_times_stop_ids = searchable_stop_times_from_gtfs.iter().map(|stop_time| stop_time.stop.id.clone()).collect::>(); - - let searchable_stop_times_bus_filterable = searchable_stop_times_from_bus.iter().filter(|arrival_estimate| searchable_stop_times_stop_ids.contains(arrival_estimate.stop_id.as_ref().unwrap())).collect::>(); - - if searchable_stop_times_bus_filterable.len() > 0 { - let bus_arrival_timestamp = chrono::DateTime::parse_from_rfc3339(searchable_stop_times_bus_filterable[0].arrival_at.as_ref().unwrap()).unwrap().timestamp() - midnight_timestamp; - - // println!("{}, {}", searchable_stop_times_from_gtfs[0].departure_time.as_ref().unwrap(), bus_arrival_timestamp); - let time_diff = *searchable_stop_times_from_gtfs[0].departure_time.as_ref().unwrap() as i32 - bus_arrival_timestamp as i32; - //positive means the bus would get there before the scheduled time - //negative means that it's late, as the projected arrival time is greater than the scheduled time - - //bias algorithm towards late buses i think? - let score:f64 = { - if time_diff < 0 { - time_diff.abs() as f64 - } else { - time_diff.abs() as f64 - } - }; - - if true { - // println!("time diff: {}", time_diff); - match timedifference { - Some(x) => { - //if the previous trip comparison is worse - if (x.abs() as f64) > score { + 'search_trip_list: for (tripcounter, lookingtrip) in + possible_trips.iter().rev().enumerate() + { + let searchable_stop_times_from_gtfs = possible_trips[tripcounter] + .stop_times + .iter() + .filter(|stop_time| stop_time.departure_time.is_some()) + .collect::>(); + let searchable_stop_times_stop_ids = searchable_stop_times_from_gtfs + .iter() + .map(|stop_time| stop_time.stop.id.clone()) + .collect::>(); + + let searchable_stop_times_bus_filterable = + searchable_stop_times_from_bus + .iter() + .filter(|arrival_estimate| { + searchable_stop_times_stop_ids + .contains(arrival_estimate.stop_id.as_ref().unwrap()) + }) + .collect::>(); + + if searchable_stop_times_bus_filterable.len() > 0 { + let bus_arrival_timestamp = chrono::DateTime::parse_from_rfc3339( + searchable_stop_times_bus_filterable[0] + .arrival_at + .as_ref() + .unwrap(), + ) + .unwrap() + .timestamp() + - midnight_timestamp; + + // println!("{}, {}", searchable_stop_times_from_gtfs[0].departure_time.as_ref().unwrap(), bus_arrival_timestamp); + let time_diff = *searchable_stop_times_from_gtfs[0] + .departure_time + .as_ref() + .unwrap() + as i32 + - bus_arrival_timestamp as i32; + //positive means the bus would get there before the scheduled time + //negative means that it's late, as the projected arrival time is greater than the scheduled time + + //bias algorithm towards late buses i think? + let score: f64 = { + if time_diff < 0 { + time_diff.abs() as f64 + } else { + time_diff.abs() as f64 + } + }; + + if true { + // println!("time diff: {}", time_diff); + match timedifference { + Some(x) => { + //if the previous trip comparison is worse + if (x.abs() as f64) > score { + timedifference = Some(time_diff); + closest_past_trip = + Some(possible_trips[tripcounter].id.clone()); + remove_before_index = Some(tripcounter); + delay_hashmap.insert( + bus.vehicle_id.as_ref().unwrap().clone(), + time_diff, + ); + } else { + break 'search_trip_list; + } + } + None => { timedifference = Some(time_diff); - closest_past_trip = Some(possible_trips[tripcounter].id.clone()); - remove_before_index = Some(tripcounter); - delay_hashmap.insert(bus.vehicle_id.as_ref().unwrap().clone(), time_diff); - } else { - break 'search_trip_list; + closest_past_trip = + Some(possible_trips[tripcounter].id.clone()); + delay_hashmap.insert( + bus.vehicle_id.as_ref().unwrap().clone(), + time_diff, + ); } - }, - None => { - timedifference = Some(time_diff); - closest_past_trip = Some(possible_trips[tripcounter].id.clone()); - delay_hashmap.insert(bus.vehicle_id.as_ref().unwrap().clone(), time_diff); } + } else { } } else { + println!( + "No trips left to search for {}", + bus.vehicle_id.as_ref().unwrap().clone() + ); } - } else { - println!("No trips left to search for {}", bus.vehicle_id.as_ref().unwrap().clone()); - - - } } if remove_before_index.is_some() { possible_trips.drain(0..remove_before_index.unwrap() + 1); } - + let closest_past_trip = match closest_past_trip { Some(x) => x, - None => { - String::from("GoAnteaters!") - } + None => String::from("GoAnteaters!"), }; - println!("Route: {}, Bus: {} assigned to {}", gtfs.get_route(route_id).unwrap().short_name, bus.call_name.as_ref().unwrap(), &closest_past_trip); - vehicle_id_to_trip_id.insert(bus.vehicle_id.as_ref().unwrap().clone(), closest_past_trip); + println!( + "Route: {}, Bus: {} assigned to {}", + gtfs.get_route(route_id).unwrap().short_name, + bus.call_name.as_ref().unwrap(), + &closest_past_trip + ); + vehicle_id_to_trip_id + .insert(bus.vehicle_id.as_ref().unwrap().clone(), closest_past_trip); } } } + } - } - - println!("vehicle_id_to_trip_id: {:?}", vehicle_id_to_trip_id); - + println!("vehicle_id_to_trip_id: {:?}", vehicle_id_to_trip_id); - println!("Delay Hashmap {:#?}", delay_hashmap); + println!("Delay Hashmap {:#?}", delay_hashmap); import_data.data.iter().for_each(|(agency_id, buses)| { if agency_id.as_str() == "1039" { for (i, bus) in buses.iter().enumerate() { - let bruhposition = Some(gtfs_rt::Position { latitude: bus.location.lat, longitude: bus.location.lng, bearing: bus.heading, odometer: None, - speed: Some((bus.speed.unwrap_or(0.0) as f32 * (1.0/3.6)) as f32), + speed: Some((bus.speed.unwrap_or(0.0) as f32 * (1.0 / 3.6)) as f32), }); let trip_ident = gtfs_rt::TripDescriptor { - trip_id: Some(vehicle_id_to_trip_id.get(bus.vehicle_id.as_ref().unwrap()).unwrap().clone()), + trip_id: Some( + vehicle_id_to_trip_id + .get(bus.vehicle_id.as_ref().unwrap()) + .unwrap() + .clone(), + ), route_id: Some(bus.route_id.as_ref().unwrap().clone()), direction_id: Some(0), start_time: None, @@ -391,60 +479,84 @@ let mut delay_hashmap: HashMap = HashMap::new(); let vehicleposition = gtfs_rt::FeedEntity { id: bus.vehicle_id.as_ref().unwrap().clone(), - vehicle: Some( - gtfs_rt::VehiclePosition { - trip: Some(trip_ident.clone()), - vehicle: Some(gtfs_rt::VehicleDescriptor { - id: Some(bus.vehicle_id.as_ref().unwrap().clone()), - label: Some(bus.call_name.as_ref().unwrap().clone()), - license_plate: None, - }), - position: bruhposition, - current_stop_sequence: None, - stop_id: None, - current_status: None, - timestamp: Some(bus.last_updated_on.parse::>().unwrap().timestamp() as u64), - congestion_level: None, - occupancy_status: None - } - ), + vehicle: Some(gtfs_rt::VehiclePosition { + trip: Some(trip_ident.clone()), + vehicle: Some(gtfs_rt::VehicleDescriptor { + id: Some(bus.vehicle_id.as_ref().unwrap().clone()), + label: Some(bus.call_name.as_ref().unwrap().clone()), + license_plate: None, + }), + position: bruhposition, + current_stop_sequence: None, + stop_id: None, + current_status: None, + timestamp: Some( + bus.last_updated_on + .parse::>() + .unwrap() + .timestamp() as u64, + ), + congestion_level: None, + occupancy_status: None, + }), is_deleted: None, trip_update: None, - alert: None + alert: None, }; - let this_trip_length = std::cmp::min(arrival_estimates_length_to_end(bus) + 2, bus.arrival_estimates.len() as i32); - - let this_trip_updates:Vec = bus.arrival_estimates[0..this_trip_length as usize].to_vec(); - - let time_updates:Vec = this_trip_updates.iter().map(|x| gtfs_rt::trip_update::StopTimeUpdate { - stop_sequence: None, - stop_id: x.stop_id.clone(), - //unix time - arrival: Some(gtfs_rt::trip_update::StopTimeEvent { - time: Some(chrono::DateTime::parse_from_rfc3339(x.arrival_at.as_ref().unwrap()).unwrap().timestamp()), - delay: None, - uncertainty: None - - }), - departure: None, - schedule_relationship: Some(0) - }).collect::>(); + let this_trip_length = std::cmp::min( + arrival_estimates_length_to_end(bus) + 2, + bus.arrival_estimates.len() as i32, + ); + + let this_trip_updates: Vec = + bus.arrival_estimates[0..this_trip_length as usize].to_vec(); + + let time_updates: Vec = this_trip_updates + .iter() + .map(|x| gtfs_rt::trip_update::StopTimeUpdate { + stop_sequence: None, + stop_id: x.stop_id.clone(), + //unix time + arrival: Some(gtfs_rt::trip_update::StopTimeEvent { + time: Some( + chrono::DateTime::parse_from_rfc3339( + x.arrival_at.as_ref().unwrap(), + ) + .unwrap() + .timestamp(), + ), + delay: None, + uncertainty: None, + }), + departure: None, + schedule_relationship: Some(0), + }) + .collect::>(); let tripupdate = gtfs_rt::FeedEntity { id: bus.vehicle_id.as_ref().unwrap().clone(), vehicle: None, is_deleted: None, - trip_update: Some( - gtfs_rt::TripUpdate { trip: trip_ident, vehicle: - Some(gtfs_rt::VehicleDescriptor { + trip_update: Some(gtfs_rt::TripUpdate { + trip: trip_ident, + vehicle: Some(gtfs_rt::VehicleDescriptor { id: Some(bus.vehicle_id.as_ref().unwrap().clone()), label: Some(bus.call_name.as_ref().unwrap().clone()), license_plate: None, - }) - , stop_time_update: time_updates, timestamp: Some(bus.last_updated_on.parse::>().unwrap().timestamp() as u64), delay: delay_hashmap.get(bus.vehicle_id.as_ref().unwrap()).map(|x| *x as i32), } - ), - alert: None + }), + stop_time_update: time_updates, + timestamp: Some( + bus.last_updated_on + .parse::>() + .unwrap() + .timestamp() as u64, + ), + delay: delay_hashmap + .get(bus.vehicle_id.as_ref().unwrap()) + .map(|x| *x as i32), + }), + alert: None, }; listoftripupdates.push(tripupdate); @@ -457,10 +569,12 @@ let mut delay_hashmap: HashMap = HashMap::new(); header: gtfs_rt::FeedHeader { gtfs_realtime_version: String::from("2.0"), incrementality: None, - timestamp: Some(SystemTime::now() - .duration_since(SystemTime::UNIX_EPOCH) - .unwrap() - .as_secs()), + timestamp: Some( + SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs(), + ), }, entity: list_of_vehicle_positions, }; @@ -469,81 +583,69 @@ let mut delay_hashmap: HashMap = HashMap::new(); header: gtfs_rt::FeedHeader { gtfs_realtime_version: String::from("2.0"), incrementality: None, - timestamp: Some(SystemTime::now() - .duration_since(SystemTime::UNIX_EPOCH) - .unwrap() - .as_secs()), + timestamp: Some( + SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs(), + ), }, entity: listoftripupdates, }; - // println!("Encoded to protobuf! {:#?}", entire_feed_vehicles); + // println!("Encoded to protobuf! {:#?}", entire_feed_vehicles); //let entire_feed_vehicles = entire_feed_vehicles.encode_to_vec(); - let buf:Vec = entire_feed_vehicles.encode_to_vec(); - let trip_buf:Vec = trip_feed.encode_to_vec(); - - let _: () = con - .set( - format!( - "gtfsrt|{}|{}", - "f-anteaterexpress~rt", "vehicles" - ), - &buf, - ) - .unwrap(); - - let _:() = con - .set( - format!( - "gtfsrt|{}|{}", - "f-anteaterexpress~rt", "trips" - ), - &trip_buf, - ) - .unwrap(); - - let _:() = con - .set( - format!( - "gtfsrttime|{}|{}", - "f-anteaterexpress~rt", "vehicles" - ), - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_millis() - .to_string(), - ) - .unwrap(); - - let _:() = con - .set( - format!( - "gtfsrttime|{}|{}", - "f-anteaterexpress~rt", "trips" - ), - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_millis() - .to_string(), - ).unwrap(); - - let _ :()= con - .set( - format!( - "gtfsrtexists|{}", - "f-anteaterexpress~rt" - ), - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_millis() - .to_string(), - ) - .unwrap(); + let buf: Vec = entire_feed_vehicles.encode_to_vec(); + let trip_buf: Vec = trip_feed.encode_to_vec(); + + let _: () = con + .set( + format!("gtfsrt|{}|{}", "f-anteaterexpress~rt", "vehicles"), + &buf, + ) + .unwrap(); + + let _: () = con + .set( + format!("gtfsrt|{}|{}", "f-anteaterexpress~rt", "trips"), + &trip_buf, + ) + .unwrap(); + + let _: () = con + .set( + format!("gtfsrttime|{}|{}", "f-anteaterexpress~rt", "vehicles"), + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_millis() + .to_string(), + ) + .unwrap(); + + let _: () = con + .set( + format!("gtfsrttime|{}|{}", "f-anteaterexpress~rt", "trips"), + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_millis() + .to_string(), + ) + .unwrap(); + + let _: () = con + .set( + format!("gtfsrtexists|{}", "f-anteaterexpress~rt"), + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_millis() + .to_string(), + ) + .unwrap(); println!("Inserted into Redis!"); diff --git a/src/static/process.rs b/src/static/process.rs index 3b87489..70380ed 100644 --- a/src/static/process.rs +++ b/src/static/process.rs @@ -1,4 +1,5 @@ use csv::Writer; +use geo::GeodesicLength; use geo_types::geometry::LineString; use gtfs_structures; use polyline; @@ -9,14 +10,11 @@ use std::collections::{BTreeMap, HashMap}; use std::fs; use std::fs::File; use std::io::Write; -use geo::GeodesicLength; mod timeutil; use timeutil::string_h_m_to_u32; use geojson::GeoJson; - - #[derive(Deserialize, Debug, Serialize)] struct ScheduleManualInput { name: String, @@ -24,13 +22,13 @@ struct ScheduleManualInput { timed: Vec, files: Vec, extrasegments: Option>>, - overrideshape: Option + overrideshape: Option, } #[derive(Copy, Clone)] struct ComparisonOfSegments { distance: f64, - index: usize + index: usize, } #[derive(Deserialize, Debug, Serialize)] @@ -135,11 +133,11 @@ struct TranslocStops { } #[derive(Debug, Clone)] - struct Segmentinfo { - segment_id: String, - data: Vec, - length: f64 - } +struct Segmentinfo { + segment_id: String, + data: Vec, + length: f64, +} fn hextorgb(x: String) -> rgb::RGB { let numberarray: Vec = x.chars().collect(); @@ -160,6 +158,7 @@ fn hextorgb(x: String) -> rgb::RGB { }; } +// Written by Kyler Chin #[tokio::main] async fn main() { let blockedfromboardings = vec!["201"]; @@ -266,7 +265,7 @@ async fn main() { .serialize(gtfs_structures::Stop { id: stop.stop_id.clone(), code: Some(stop.code.clone()), - name: stop.name.clone().replace(" Stop ",""), + name: stop.name.clone().replace(" Stop ", ""), description: stop.description.clone(), location_type: gtfs_structures::LocationType::StopPoint, parent_station: None, @@ -306,20 +305,28 @@ async fn main() { segments_map.insert(segment_id.clone(), segment_polyline.clone()); - segment_polyline.coords().enumerate().for_each(|(i, coord)| - segments_polyline_debug.serialize(debugpolyline { - lat: coord.y, - lng: coord.x, - segment_id: segment_id.clone(), - number: i - }).unwrap()); - + segment_polyline + .coords() + .enumerate() + .for_each(|(i, coord)| { + segments_polyline_debug + .serialize(debugpolyline { + lat: coord.y, + lng: coord.x, + segment_id: segment_id.clone(), + number: i, + }) + .unwrap() + }); } - let segments_polyline_debug_csv = String::from_utf8(segments_polyline_debug.into_inner().unwrap()).unwrap(); + let segments_polyline_debug_csv = + String::from_utf8(segments_polyline_debug.into_inner().unwrap()).unwrap(); let mut segments_polyline_debug_file = File::create("segments_polyline_debug.csv").unwrap(); - segments_polyline_debug_file.write_all(segments_polyline_debug_csv.as_bytes()).unwrap(); + segments_polyline_debug_file + .write_all(segments_polyline_debug_csv.as_bytes()) + .unwrap(); println!("segments_map: {:?}", segments_map); @@ -331,11 +338,11 @@ async fn main() { for route in routes_array { // println!("Route: {:?}", route); - //make the schedule here + //make the schedule here - let data_to_use = manualhashmap.get(&route.short_name).unwrap(); + let data_to_use = manualhashmap.get(&route.short_name).unwrap(); - println!("data_to_use: {:?}", data_to_use); + println!("data_to_use: {:?}", data_to_use); let mut vec_of_trips: Vec = vec![]; let mut vec_of_stop_times: Vec = vec![]; @@ -360,17 +367,17 @@ async fn main() { }) .unwrap(); - let mut arrayofsegments: Vec = vec![]; + let mut arrayofsegments: Vec = vec![]; - let mut sourcedata = route.segments.clone(); + let mut sourcedata = route.segments.clone(); - if data_to_use.extrasegments.is_some() { - for x in data_to_use.extrasegments.clone().unwrap() { + if data_to_use.extrasegments.is_some() { + for x in data_to_use.extrasegments.clone().unwrap() { println!("Joining extra {:?} to route {}", x, route.route_id); - sourcedata.push(x.clone()); - } + sourcedata.push(x.clone()); } - + } + for segment_part in &sourcedata { let segment_id = segment_part[0].clone(); //can be "forward" or "backward" @@ -379,113 +386,140 @@ async fn main() { let mut segment = segments_map.get(&segment_id).unwrap().clone().into_inner(); if segment_direction == "backward" { - println!("reversing segment {} of route {}", segment_id, route.route_id); + println!( + "reversing segment {} of route {}", + segment_id, route.route_id + ); segment.reverse(); } - - let dataofthisseg = segment.clone().into_iter().collect::>(); + + let dataofthisseg = segment + .clone() + .into_iter() + .collect::>(); //Lazy o(n^2) algo arrayofsegments.push(Segmentinfo { segment_id: segment_id.clone(), data: dataofthisseg.clone(), length: geo::geometry::LineString::from_iter( - dataofthisseg.iter().map(|x| geo::geometry::Point::new(x.x, x.y)) + dataofthisseg + .iter() + .map(|x| geo::geometry::Point::new(x.x, x.y)), ) - .geodesic_length() + .geodesic_length(), }); - - } - //sort array - arrayofsegments.sort_by(|a, b| bool::cmp(&(a.length < b.length), &(b.length < a.length))); - - println!("segments {:?}", arrayofsegments.iter().map(|x| x.length).collect::>()); + //sort array + arrayofsegments + .sort_by(|a, b| bool::cmp(&(a.length < b.length), &(b.length < a.length))); - let mut segmentordered:LineString = LineString(vec![]); + println!( + "segments {:?}", + arrayofsegments + .iter() + .map(|x| x.length) + .collect::>() + ); - segmentordered = segmentordered.into_iter().chain(arrayofsegments[0].data.clone().into_iter()).collect::>(); + let mut segmentordered: LineString = LineString(vec![]); - println!("segmentordered {:?}", segmentordered); + segmentordered = segmentordered + .into_iter() + .chain(arrayofsegments[0].data.clone().into_iter()) + .collect::>(); - arrayofsegments.remove(0); + println!("segmentordered {:?}", segmentordered); - while arrayofsegments.len() > 0 { - - let mut closest_end_to_my_start: Option = None; - let mut closest_start_to_my_end: Option = None; + arrayofsegments.remove(0); - let coordsofmyself:Vec = segmentordered.clone().into_iter().map(|coord| coord).collect::>(); + while arrayofsegments.len() > 0 { + let mut closest_end_to_my_start: Option = None; + let mut closest_start_to_my_end: Option = None; - let my_start = coordsofmyself[0].clone(); - let my_end = segmentordered[coordsofmyself.len() - 1].clone(); + let coordsofmyself: Vec = segmentordered + .clone() + .into_iter() + .map(|coord| coord) + .collect::>(); - - // println!("my start {:?}", my_start); + let my_start = coordsofmyself[0].clone(); + let my_end = segmentordered[coordsofmyself.len() - 1].clone(); - for (index, segment) in arrayofsegments.iter().enumerate() { - let start_partner = segment.data[0].clone(); - let end_partner = segment.data[segment.data.len() - 1].clone(); + // println!("my start {:?}", my_start); - //println!("their end {:?}", end_partner); - let my_start_to_their_end_distance = vincenty_core::distance_from_coords( - &my_start, - &end_partner - ).unwrap(); + for (index, segment) in arrayofsegments.iter().enumerate() { + let start_partner = segment.data[0].clone(); + let end_partner = segment.data[segment.data.len() - 1].clone(); - let my_end_to_their_start_distance = vincenty_core::distance_from_coords( - &my_end, - &start_partner - ).unwrap(); + //println!("their end {:?}", end_partner); + let my_start_to_their_end_distance = + vincenty_core::distance_from_coords(&my_start, &end_partner).unwrap(); - - if (closest_end_to_my_start.is_none() || my_start_to_their_end_distance < closest_end_to_my_start.unwrap().distance) { - closest_end_to_my_start = Some(ComparisonOfSegments { - distance: my_start_to_their_end_distance, - index: index - }); - } - - if (closest_start_to_my_end.is_none() || my_end_to_their_start_distance < closest_start_to_my_end.unwrap().distance) { - closest_start_to_my_end = Some(ComparisonOfSegments { - distance: my_end_to_their_start_distance, - index: index - }); - } + let my_end_to_their_start_distance = + vincenty_core::distance_from_coords(&my_end, &start_partner).unwrap(); - - } - - let mut index_to_remove :Option = None; - - if closest_end_to_my_start.unwrap().distance < closest_start_to_my_end.unwrap().distance { - //join partner + me - segmentordered = arrayofsegments[closest_end_to_my_start.unwrap().index].data.clone().into_iter().chain(segmentordered.into_iter()).collect::>(); + if (closest_end_to_my_start.is_none() + || my_start_to_their_end_distance + < closest_end_to_my_start.unwrap().distance) + { + closest_end_to_my_start = Some(ComparisonOfSegments { + distance: my_start_to_their_end_distance, + index: index, + }); + } - //drop the segment - index_to_remove = Some(closest_end_to_my_start.unwrap().index); - } else { - //join me + partner + if (closest_start_to_my_end.is_none() + || my_end_to_their_start_distance + < closest_start_to_my_end.unwrap().distance) + { + closest_start_to_my_end = Some(ComparisonOfSegments { + distance: my_end_to_their_start_distance, + index: index, + }); + } + } - segmentordered = segmentordered.into_iter().chain(arrayofsegments[closest_start_to_my_end.unwrap().index].data.clone().into_iter()).collect::>(); + let mut index_to_remove: Option = None; - //drop the segment - index_to_remove = Some(closest_start_to_my_end.unwrap().index); - } - - if index_to_remove.is_some() { - arrayofsegments.remove(index_to_remove.unwrap()); - } - - } + if closest_end_to_my_start.unwrap().distance + < closest_start_to_my_end.unwrap().distance + { + //join partner + me + segmentordered = arrayofsegments[closest_end_to_my_start.unwrap().index] + .data + .clone() + .into_iter() + .chain(segmentordered.into_iter()) + .collect::>(); + + //drop the segment + index_to_remove = Some(closest_end_to_my_start.unwrap().index); + } else { + //join me + partner + + segmentordered = segmentordered + .into_iter() + .chain( + arrayofsegments[closest_start_to_my_end.unwrap().index] + .data + .clone() + .into_iter(), + ) + .collect::>(); + + //drop the segment + index_to_remove = Some(closest_start_to_my_end.unwrap().index); + } - + if index_to_remove.is_some() { + arrayofsegments.remove(index_to_remove.unwrap()); + } + } //now they have to be seperated and put into the shapes list if data_to_use.overrideshape.is_some() { - - let file = File::open(data_to_use.overrideshape.clone().unwrap()).unwrap(); let geojson = GeoJson::from_reader(file).unwrap(); @@ -511,7 +545,13 @@ async fn main() { }; if linestring.is_some() { - segmentordered = LineString::from(linestring.unwrap().into_iter().map(|x| geo_types::Point::new(x[0], x[1])).collect::>>()); + segmentordered = LineString::from( + linestring + .unwrap() + .into_iter() + .map(|x| geo_types::Point::new(x[0], x[1])) + .collect::>>(), + ); } } @@ -533,8 +573,6 @@ async fn main() { seqcount = seqcount + 1; } - - for file in data_to_use.files.iter() { // let scheduletimes = fs::read_to_string(format!("schedules/{}", file.name).as_str()).unwrap().as_str(); @@ -566,15 +604,13 @@ async fn main() { arrivals: Option, departures: Option, enabled: bool, - boardingsallowed: bool + boardingsallowed: bool, } let mut tripnumber = 1; //for each row for row in vecofrows { - - let mut scheduleforthistime: Vec = vec![]; for i in 2..row.len() { @@ -603,38 +639,42 @@ async fn main() { println!("repeat {:?} times", repeatnumberoftimes); - - /* - rowvec.push(Stoptimepre { - stop_id: stopcode_to_stopid - .get(&routelooppoint.clone()) - .unwrap() - .clone(), - stop_code: routelooppoint.clone(), - timed: data_to_use.timed.contains(&routelooppoint.clone()), - arrivals: None, - departures: None, - enabled: true, - }); */ - - let firsttimedindex = scheduleforthistime.iter().position(|x| x.contains(":")).unwrap(); - let initialtime = string_h_m_to_u32(scheduleforthistime[firsttimedindex].clone()); - let mut offset = 0; - - for eachtrip in 0..repeatnumberoftimes { + /* + rowvec.push(Stoptimepre { + stop_id: stopcode_to_stopid + .get(&routelooppoint.clone()) + .unwrap() + .clone(), + stop_code: routelooppoint.clone(), + timed: data_to_use.timed.contains(&routelooppoint.clone()), + arrivals: None, + departures: None, + enabled: true, + }); */ + + let firsttimedindex = scheduleforthistime + .iter() + .position(|x| x.contains(":")) + .unwrap(); + let initialtime = + string_h_m_to_u32(scheduleforthistime[firsttimedindex].clone()); + let mut offset = 0; + + for eachtrip in 0..repeatnumberoftimes { //inclusive, cancel everything from 0 until let mut cancelindexpre: Option = None; - let mut canceldeparturesindex:Option = None; + let mut canceldeparturesindex: Option = None; let mut rowvec: Vec = vec![]; //process each stop along this trip - let whichintervaltouse = repeatinterval[eachtrip as usize % repeatinterval.len() as usize]; + let whichintervaltouse = + repeatinterval[eachtrip as usize % repeatinterval.len() as usize]; let mut stopnumber = 0; - - - for (routeordercounter, routelooppoint) in data_to_use.routeorder.iter().enumerate() { + for (routeordercounter, routelooppoint) in + data_to_use.routeorder.iter().enumerate() + { let mut calcboardingsallowed = true; if routeordercounter == data_to_use.routeorder.len() - 1 { @@ -655,14 +695,17 @@ async fn main() { arrivals: None, departures: None, enabled: true, - boardingsallowed: calcboardingsallowed + boardingsallowed: calcboardingsallowed, }); //use scheduleforthistime to get the initial times let mut departuretime = None; if headervec.contains(&routelooppoint.clone()) { - let index = headervec.iter().position(|r| r.as_str() == routelooppoint.clone().as_str()).unwrap(); + let index = headervec + .iter() + .position(|r| r.as_str() == routelooppoint.clone().as_str()) + .unwrap(); let stringofdeparturetime = scheduleforthistime[index].clone(); @@ -670,15 +713,19 @@ async fn main() { departuretime = None; } else { if stringofdeparturetime.contains(":") { - departuretime = Some(string_h_m_to_u32( - stringofdeparturetime.clone(), - ) + offset); + departuretime = Some( + string_h_m_to_u32(stringofdeparturetime.clone()) + + offset, + ); } } if stringofdeparturetime.contains("*") { cancelindexpre = Some(stopnumber - 1); - println!("Cancelled all service 0 to {}", cancelindexpre.unwrap()) + println!( + "Cancelled all service 0 to {}", + cancelindexpre.unwrap() + ) } if stringofdeparturetime.contains("$") { @@ -706,11 +753,9 @@ async fn main() { rowvec[stopnumber].departures = departuretime; - - stopnumber = stopnumber + 1; } - + offset = offset + whichintervaltouse as u32; tripnumber = tripnumber + 1; @@ -722,8 +767,9 @@ async fn main() { true => "monthurs", false => "fri", }; - - let trip_id = format!("{}-{}-{}", route.short_name, tripnumber, schedulename); + + let trip_id = + format!("{}-{}-{}", route.short_name, tripnumber, schedulename); let rawtripgtfs = gtfs_structures::RawTrip { id: trip_id.clone(), @@ -735,7 +781,7 @@ async fn main() { trip_short_name: None, shape_id: Some(this_routes_shape_id.clone()), bikes_allowed: gtfs_structures::BikesAllowedType::AtLeastOneBike, - wheelchair_accessible: gtfs_structures::Availability::Available + wheelchair_accessible: gtfs_structures::Availability::Available, }; tripswriter.serialize(rawtripgtfs).unwrap(); @@ -752,7 +798,9 @@ async fn main() { stop_headsign: None, pickup_type: match stoptimefinal.boardingsallowed { true => gtfs_structures::PickupDropOffType::Regular, - false => gtfs_structures::PickupDropOffType::NotAvailable, + false => { + gtfs_structures::PickupDropOffType::NotAvailable + } }, drop_off_type: gtfs_structures::PickupDropOffType::Regular, shape_dist_traveled: None, @@ -760,17 +808,18 @@ async fn main() { true => gtfs_structures::TimepointType::Exact, false => gtfs_structures::TimepointType::Approximate, }, - continuous_pickup: gtfs_structures::ContinuousPickupDropOff::NotAvailable, - continuous_drop_off: gtfs_structures::ContinuousPickupDropOff::NotAvailable, + continuous_pickup: + gtfs_structures::ContinuousPickupDropOff::NotAvailable, + continuous_drop_off: + gtfs_structures::ContinuousPickupDropOff::NotAvailable, }; stoptimeswriter.serialize(rawstoptimegtfs).unwrap(); - - stopcounterfinal = stopcounterfinal + 1; - } + stopcounterfinal = stopcounterfinal + 1; + } } - } + } } } } @@ -799,31 +848,38 @@ async fn main() { let mut calendarwriter = Writer::from_writer(vec![]); - calendarwriter.serialize(gtfs_structures::Calendar { - id: String::from("monthurs"), - monday: true, - tuesday: true, - wednesday: true, - thursday: true, - friday: true, - saturday: true, - sunday: true, - start_date: chrono::naive::NaiveDate::from_ymd_opt(2023,09,25).unwrap(), - end_date: chrono::naive::NaiveDate::from_ymd_opt(2023,12,15).unwrap(), - }).unwrap(); - - calendarwriter.serialize(gtfs_structures::Calendar { - id: String::from("fri"), - monday: false, - tuesday: false, - wednesday: false, - thursday: false, - friday: true, - saturday: false, - sunday: false, - start_date: chrono::naive::NaiveDate::from_ymd_opt(2024,1,8).unwrap(), - end_date: chrono::naive::NaiveDate::from_ymd_opt(2024,3,22).unwrap(), - }).unwrap(); + let start_date = chrono::naive::NaiveDate::from_ymd_opt(2024, 1, 8).unwrap(); + let end_date = chrono::naive::NaiveDate::from_ymd_opt(2024, 3, 22).unwrap(); + + calendarwriter + .serialize(gtfs_structures::Calendar { + id: String::from("monthurs"), + monday: true, + tuesday: true, + wednesday: true, + thursday: true, + friday: true, + saturday: true, + sunday: true, + start_date: start_date.clone(), + end_date: end_date.clone(), + }) + .unwrap(); + + calendarwriter + .serialize(gtfs_structures::Calendar { + id: String::from("fri"), + monday: false, + tuesday: false, + wednesday: false, + thursday: false, + friday: true, + saturday: false, + sunday: false, + start_date: start_date.clone(), + end_date: end_date.clone(), + }) + .unwrap(); let calendar_csv = String::from_utf8(calendarwriter.into_inner().unwrap()).unwrap(); let mut calendarfile = File::create("anteater_gtfs/calendar.txt").unwrap(); @@ -834,17 +890,20 @@ async fn main() { let cancellations = [ //MLK JR DAY - ((2024,01,15), "monthurs"), + ((2024, 01, 15), "monthurs"), //President's day - ((2024,02,19), "monthurs") + ((2024, 02, 19), "monthurs"), ]; for cancel in cancellations { - calendardateswriter.serialize(gtfs_structures::CalendarDate { - service_id: String::from(cancel.1), - date: chrono::naive::NaiveDate::from_ymd_opt(cancel.0.0,cancel.0.1, cancel.0.2).unwrap(), - exception_type: gtfs_structures::Exception::Deleted, - }).unwrap(); + calendardateswriter + .serialize(gtfs_structures::CalendarDate { + service_id: String::from(cancel.1), + date: chrono::naive::NaiveDate::from_ymd_opt(cancel.0 .0, cancel.0 .1, cancel.0 .2) + .unwrap(), + exception_type: gtfs_structures::Exception::Deleted, + }) + .unwrap(); } //write now @@ -852,27 +911,29 @@ async fn main() { let calendardates_csv = String::from_utf8(calendardateswriter.into_inner().unwrap()).unwrap(); let mut calendardatesfile = File::create("anteater_gtfs/calendar_dates.txt").unwrap(); - calendardatesfile.write_all(calendardates_csv.as_bytes()).unwrap(); + calendardatesfile + .write_all(calendardates_csv.as_bytes()) + .unwrap(); //now validate it - let gtfs = gtfs_structures::GtfsReader::default() - .read("anteater_gtfs"); - - match gtfs { - Ok(gtfs) => { - println!("Valid"); - }, - Err(e) => { - println!("error: {:?}", e); - } - } + let gtfs = gtfs_structures::GtfsReader::default().read("anteater_gtfs"); + + match gtfs { + Ok(gtfs) => { + println!("Valid"); + } + Err(e) => { + println!("error: {:?}", e); + } + } } fn cleanupstring(x: String) -> String { - return x.replace("!","").replace("#", "") - .replace("*","").replace("$", "").replace(" ", ""); + return x + .replace("!", "") + .replace("#", "") + .replace("*", "") + .replace("$", "") + .replace(" ", ""); } - - - diff --git a/src/static/timeutil.rs b/src/static/timeutil.rs index b73dfa5..02b06e6 100644 --- a/src/static/timeutil.rs +++ b/src/static/timeutil.rs @@ -1,12 +1,17 @@ -pub fn string_h_m_to_u32(x:String) -> u32 { +pub fn string_h_m_to_u32(x: String) -> u32 { //split string into h and m based on : - let mut input = x.clone().replace("!","").replace("#", "") - .replace("*","").replace("$", "").replace(" ", ""); + let mut input = x + .clone() + .replace("!", "") + .replace("#", "") + .replace("*", "") + .replace("$", "") + .replace(" ", ""); //it's okay if it runs over 24, that's expected let mut h = input.split(":").nth(0).unwrap().parse::().unwrap(); let mut m = input.split(":").nth(1).unwrap().parse::().unwrap(); (h * 3600) + (m * 60) -} \ No newline at end of file +}