From 9daf1b8cb42765cd5891b13f9f1d2856b3db8fe7 Mon Sep 17 00:00:00 2001 From: Rodrigo Moya Date: Sat, 3 Feb 2024 12:43:28 +0100 Subject: [PATCH 1/3] Add downhill ski type --- src/Itinero/Osm/Vehicles/Ski/Downhill.cs | 64 ++++++++++++++++++++++++ src/Itinero/Osm/Vehicles/Vehicle.cs | 12 +++++ 2 files changed, 76 insertions(+) create mode 100644 src/Itinero/Osm/Vehicles/Ski/Downhill.cs diff --git a/src/Itinero/Osm/Vehicles/Ski/Downhill.cs b/src/Itinero/Osm/Vehicles/Ski/Downhill.cs new file mode 100644 index 00000000..cd8c1a36 --- /dev/null +++ b/src/Itinero/Osm/Vehicles/Ski/Downhill.cs @@ -0,0 +1,64 @@ +using Itinero.Attributes; +using Itinero.Profiles; + +namespace Itinero.Osm.Vehicles.Ski +{ + /// + public class Downhill : Itinero.Profiles.Vehicle + { + /// + /// Creates a new instance of the class. + /// + public Downhill() + { + base.MetaWhiteList.Add("name"); + + base.ProfileWhiteList.Add("piste:type"); + base.ProfileWhiteList.Add("aerialway"); + + Register(new Profile("shortest", ProfileMetric.DistanceInMeters, VehicleTypes, null, this)); + Register(new Profile(string.Empty, ProfileMetric.TimeInSeconds, VehicleTypes, null, this)); + } + + /// + public override string Name => "downhill"; + + /// + public override string[] VehicleTypes { get; } = [ "ski", "foot" ]; + + /// + public override FactorAndSpeed FactorAndSpeed(IAttributeCollection attributes, Whitelist whitelist) + { + short direction = 0; + float speedFactor = 0f, value = 0f; + + if (attributes is null) return Itinero.Profiles.FactorAndSpeed.NoFactor; + + if (attributes.TryGetValue("piste:type", out var piste_type) && piste_type == "downhill") { + direction = 1; // always follow piste direction + if (attributes.TryGetValue("piste:difficulty", out var piste_difficulty)) { + value = speedFactor = piste_difficulty switch + { + "easy" => 1 / (30f / 3.6f), + "intermediate" => 1 / (50f / 3.6f), + "advanced" => 1 / (30f / 3.6f), + _ => 1 / (20f / 3.6f), + }; + } else { + value = speedFactor = 1 / (20f / 3.6f); + } + } else if (attributes.TryGetValue("aerialway", out var aerialway)) { + direction = 1; // forward the edge + value = speedFactor = 1 / (10f / 3.6f); + } else { + return Itinero.Profiles.FactorAndSpeed.NoFactor; + } + + return new FactorAndSpeed { + SpeedFactor = speedFactor, + Value = value, + Direction = direction + }; + } + } +} \ No newline at end of file diff --git a/src/Itinero/Osm/Vehicles/Vehicle.cs b/src/Itinero/Osm/Vehicles/Vehicle.cs index 476d8a92..ab64221e 100644 --- a/src/Itinero/Osm/Vehicles/Vehicle.cs +++ b/src/Itinero/Osm/Vehicles/Vehicle.cs @@ -22,6 +22,7 @@ using Itinero.Profiles.Lua; using System.Collections.Generic; using System.Linq; +using Itinero.Osm.Vehicles.Ski; namespace Itinero.Osm.Vehicles { @@ -70,6 +71,17 @@ public static class Vehicle /// public static readonly Profiles.Vehicle Bus = new DynamicVehicle(VehicleExtensions.LoadEmbeddedResource("Itinero.Osm.Vehicles.bus.lua")); + /// + /// Ski vehicle types. + /// + public static class Ski + { + /// + /// Downhill skiing. + /// + public static readonly Profiles.Vehicle Downhill = new Downhill(); + } + /// /// Registers all default vehicles. /// From f0e8172c41520c2102f48b2f0e99f23f29a75b19 Mon Sep 17 00:00:00 2001 From: Rodrigo Moya Date: Sat, 3 Feb 2024 12:44:26 +0100 Subject: [PATCH 2/3] Register downhill ski vehicle --- src/Itinero/Osm/Vehicles/Vehicle.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Itinero/Osm/Vehicles/Vehicle.cs b/src/Itinero/Osm/Vehicles/Vehicle.cs index ab64221e..73e91dc0 100644 --- a/src/Itinero/Osm/Vehicles/Vehicle.cs +++ b/src/Itinero/Osm/Vehicles/Vehicle.cs @@ -96,6 +96,8 @@ public static void RegisterVehicles() SmallTruck.Register(); BigTruck.Register(); Bus.Register(); + + Ski.Downhill.Register(); } private static Dictionary _accessValues = null; From 17baf5cc6cecafb7489b374a7abf67df612111f7 Mon Sep 17 00:00:00 2001 From: Rodrigo Moya Date: Sat, 3 Feb 2024 12:53:56 +0100 Subject: [PATCH 3/3] Add downhill skiing routing test --- .../Staging/Download.cs | 16 +++++++++---- .../Tests/RoutingTests.cs | 24 +++++++++++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/test/Itinero.Test.Functional/Staging/Download.cs b/test/Itinero.Test.Functional/Staging/Download.cs index 19bad6f9..58588098 100644 --- a/test/Itinero.Test.Functional/Staging/Download.cs +++ b/test/Itinero.Test.Functional/Staging/Download.cs @@ -37,13 +37,19 @@ public static class Download /// /// Downloads the luxembourg data. /// - public static void DownloadLuxembourgAll() + public static void DownloadLuxembourgAll() => DownloadPBF(Download.LuxembourgPBF, Download.LuxembourgLocal); + + /// + /// Download the given PBF url into a local file. + /// + /// URL for the PBF file. + /// Local path. + public static void DownloadPBF(string url, string localPath) { - if (!File.Exists(Download.LuxembourgLocal)) + if (!File.Exists(localPath)) { - var client = new WebClient(); - client.DownloadFile(Download.LuxembourgPBF, - Download.LuxembourgLocal); + using var client = new WebClient(); + client.DownloadFile(url, localPath); } } diff --git a/test/Itinero.Test.Functional/Tests/RoutingTests.cs b/test/Itinero.Test.Functional/Tests/RoutingTests.cs index a5e15aeb..9e6e5ff5 100644 --- a/test/Itinero.Test.Functional/Tests/RoutingTests.cs +++ b/test/Itinero.Test.Functional/Tests/RoutingTests.cs @@ -59,6 +59,8 @@ public static void Run(RouterDb routerDb) // one-to-many & many-to-many. GetTestOneToManyRoutes(router, profile, 200).TestPerf($"{profile.FullName} one-to-many routes"); GetTestManyToManyRoutes(router, profile, 20).TestPerf($"{profile.FullName} many-to-many routes"); + + RunDownhillSki(); } /// @@ -358,5 +360,27 @@ public static Func>> GetTestManyToManyRo return () => new PerformanceTestResult>( router.TryCalculate(profile, resolvedPoints, resolvedPoints)); } + + /// + /// Runs ski resort routing tests. + /// + public static void RunDownhillSki() + { + var localPath = Path.Combine(Path.GetTempPath(), "aragon-latest.osm.pbf"); + Download.DownloadPBF("https://download.geofabrik.de/europe/spain/aragon-latest.osm.pbf", localPath); + + using var stream = new FileInfo(localPath).OpenRead(); + var routerDb = new RouterDb(); + routerDb.LoadOsmData(stream, Itinero.Osm.Vehicles.Vehicle.Ski.Downhill, Itinero.Osm.Vehicles.Vehicle.Pedestrian); + var router = new Router(routerDb); + + using var routingCancellation = new CancellationTokenSource(); + routingCancellation.CancelAfter(TimeSpan.FromMinutes(5)); + var source = new Coordinate(42.58698f, 0.54023f); // El Molino chair lift in Cerler, Spain + var target = new Coordinate(42.55933f, 0.56834f); // Ampriu chair lift in Cerler, Spain + + Assert.IsNotNull(router.Calculate(Itinero.Osm.Vehicles.Vehicle.Ski.Downhill.Shortest(), + source.Latitude, source.Longitude, target.Latitude, target.Longitude, routingCancellation.Token)); + } } } \ No newline at end of file