Datastructure for ASTAR and OSM_Regions
This commit is contained in:
commit
12398ca09e
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
/packages/
|
||||||
|
riderModule.iml
|
||||||
|
/_ReSharper.Caches/
|
13
.idea/.idea.OSM_Graph/.idea/.gitignore
vendored
Normal file
13
.idea/.idea.OSM_Graph/.idea/.gitignore
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Rider ignored files
|
||||||
|
/projectSettingsUpdater.xml
|
||||||
|
/.idea.OSM_Graph.iml
|
||||||
|
/modules.xml
|
||||||
|
/contentModel.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
4
.idea/.idea.OSM_Graph/.idea/encodings.xml
Normal file
4
.idea/.idea.OSM_Graph/.idea/encodings.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||||
|
</project>
|
8
.idea/.idea.OSM_Graph/.idea/indexLayout.xml
Normal file
8
.idea/.idea.OSM_Graph/.idea/indexLayout.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="UserContentModel">
|
||||||
|
<attachedFolders />
|
||||||
|
<explicitIncludes />
|
||||||
|
<explicitExcludes />
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/.idea.OSM_Graph/.idea/vcs.xml
Normal file
6
.idea/.idea.OSM_Graph/.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
45
Graph/Graph.cs
Normal file
45
Graph/Graph.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
namespace Graph;
|
||||||
|
|
||||||
|
public class Graph
|
||||||
|
{
|
||||||
|
public readonly Dictionary<ulong, Node> Nodes = new();
|
||||||
|
public readonly Dictionary<ulong, Way> Ways = new ();
|
||||||
|
|
||||||
|
public void ConcatGraph(Graph graph)
|
||||||
|
{
|
||||||
|
foreach ((ulong id, Node n) in graph.Nodes)
|
||||||
|
this.Nodes.TryAdd(id, n);
|
||||||
|
foreach ((ulong id, Way w) in graph.Ways)
|
||||||
|
this.Ways.TryAdd(id, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ContainsNode(Node node)
|
||||||
|
{
|
||||||
|
return Nodes.ContainsValue(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ContainsNode(ulong nodeId)
|
||||||
|
{
|
||||||
|
return Nodes.ContainsKey(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ContainsWay(Way way)
|
||||||
|
{
|
||||||
|
return Ways.ContainsValue(way);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ContainsWay(ulong wayId)
|
||||||
|
{
|
||||||
|
return Ways.ContainsKey(wayId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyValuePair<ulong, Node> ClosestNodeToCoordinates(float lat, float lon)
|
||||||
|
{
|
||||||
|
return Nodes.MinBy(n => n.Value.DistanceTo(lat, lon));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"Graph {Nodes.Count} Nodes {Ways.Count} Ways.";
|
||||||
|
}
|
||||||
|
}
|
9
Graph/Graph.csproj
Normal file
9
Graph/Graph.csproj
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
16
Graph/Node.cs
Normal file
16
Graph/Node.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
namespace Graph;
|
||||||
|
|
||||||
|
public class Node(float lat, float lon, Dictionary<ulong, ulong>? neighbors = null)
|
||||||
|
{
|
||||||
|
public readonly Dictionary<ulong, ulong> Neighbors = neighbors??new(); //nodeId, wayId
|
||||||
|
public readonly float Lat = lat, Lon = lon;
|
||||||
|
|
||||||
|
public double DistanceTo(Node n2) => Utils.NodeUtils.DistanceBetween(this, n2);
|
||||||
|
public double DistanceTo(float latitude, float longitude) => Utils.NodeUtils.DistanceBetween(this, latitude, longitude);
|
||||||
|
public bool HasEdgeTo(ulong neighbor) => this.Neighbors.ContainsKey(neighbor);
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"Node {Lat:00.000000} {Lon:000.000000}";
|
||||||
|
}
|
||||||
|
}
|
49
Graph/Utils/NodeUtils.cs
Normal file
49
Graph/Utils/NodeUtils.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
namespace Graph.Utils;
|
||||||
|
|
||||||
|
public static class NodeUtils
|
||||||
|
{
|
||||||
|
public const int EarthRadius = 6371000;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Close enough
|
||||||
|
*/
|
||||||
|
public static double DistanceBetween(float lat1, float lon1, float lat2, float lon2)
|
||||||
|
{
|
||||||
|
double radiansLat1 = DegreesToRadians(lat1);
|
||||||
|
double radiansLat2 = DegreesToRadians(lat2);
|
||||||
|
double deltaRadiansLon = DegreesToRadians(lon2 - lon1);
|
||||||
|
|
||||||
|
double distance = Math.Acos(Math.Sin(radiansLat1) * Math.Sin(radiansLat2) + Math.Cos(radiansLat1) * Math.Cos(radiansLat2) * Math.Cos(deltaRadiansLon)) * EarthRadius;
|
||||||
|
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double DistanceBetween(Node n1, Node n2) => DistanceBetween(n1.Lat, n1.Lon, n2.Lat, n2.Lon);
|
||||||
|
public static double DistanceBetween(Node n1, float lat2, float lon2) => DistanceBetween(n1.Lat, n1.Lon, lat2, lon2);
|
||||||
|
public static double DistanceBetween(float lat1, float lon1, Node n2) => DistanceBetween(n2, lat1, lon1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* From https://www.movable-type.co.uk/scripts/latlong.html
|
||||||
|
*/
|
||||||
|
public static double DistanceBetweenHaversine(float lat1, float lon1, float lat2, float lon2)
|
||||||
|
{
|
||||||
|
double radiansLat1 = DegreesToRadians(lat1);
|
||||||
|
double radiansLat2 = DegreesToRadians(lat2);
|
||||||
|
double deltaRadiansLat = DegreesToRadians(lat2 - lat1);
|
||||||
|
double deltaRadiansLon = DegreesToRadians(lon2 - lon1);
|
||||||
|
double a = Math.Sin(deltaRadiansLat / 2) * Math.Sin(deltaRadiansLat / 2) + Math.Cos(radiansLat1) * Math.Cos(radiansLat2) * Math.Sin(deltaRadiansLon / 2) * Math.Sin(deltaRadiansLon / 2);
|
||||||
|
double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
|
||||||
|
double d = EarthRadius * c;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double DegreesToRadians(float deg)
|
||||||
|
{
|
||||||
|
return deg * Math.PI /180;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double RadiansToDegrees(float rad)
|
||||||
|
{
|
||||||
|
return rad * 180 / Math.PI;
|
||||||
|
}
|
||||||
|
}
|
12
Graph/Way.cs
Normal file
12
Graph/Way.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace Graph;
|
||||||
|
|
||||||
|
public class Way(Dictionary<string, string> tags)
|
||||||
|
{
|
||||||
|
public readonly Dictionary<string, string> Tags = tags;
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"Way\n" +
|
||||||
|
$"Tags:\t{string.Join("\n\t", Tags.Select(t => $"{t.Key,10}={t.Value,30}"))}";
|
||||||
|
}
|
||||||
|
}
|
22
OSM_Graph.sln
Normal file
22
OSM_Graph.sln
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OSM_Graph", "OSM_Graph\OSM_Graph.csproj", "{82A1033D-89AD-4C05-9771-4CE48ABD006A}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Graph", "Graph\Graph.csproj", "{6B699841-C159-4A29-9574-3FAD6F364BCF}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{82A1033D-89AD-4C05-9771-4CE48ABD006A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{82A1033D-89AD-4C05-9771-4CE48ABD006A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{82A1033D-89AD-4C05-9771-4CE48ABD006A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{82A1033D-89AD-4C05-9771-4CE48ABD006A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6B699841-C159-4A29-9574-3FAD6F364BCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6B699841-C159-4A29-9574-3FAD6F364BCF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6B699841-C159-4A29-9574-3FAD6F364BCF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6B699841-C159-4A29-9574-3FAD6F364BCF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
7
OSM_Graph/IOSMSerializable.cs
Normal file
7
OSM_Graph/IOSMSerializable.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace OSM_Graph;
|
||||||
|
|
||||||
|
public interface IOSMSerializable<out T>
|
||||||
|
{
|
||||||
|
public abstract string Serialize();
|
||||||
|
public static abstract T Deserialize(string serialized);
|
||||||
|
}
|
37
OSM_Graph/Node.cs
Normal file
37
OSM_Graph/Node.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace OSM_Graph;
|
||||||
|
|
||||||
|
public class Node(ulong id, float lat, float lon, Dictionary<ulong, ulong>? neighbors = null) : Graph.Node(lat, lon, neighbors), IOSMSerializable<Node>
|
||||||
|
{
|
||||||
|
public readonly ulong ID = id;
|
||||||
|
|
||||||
|
public string Serialize()
|
||||||
|
{
|
||||||
|
return $"{this.ID}#{this.Lat.ToString(CultureInfo.InvariantCulture)}#{this.Lon.ToString(CultureInfo.InvariantCulture)}#{string.Join(',', this.Neighbors.Select(n => $"{n.Key}-{n.Value}"))}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Node Deserialize(string serialized)
|
||||||
|
{
|
||||||
|
string[] parts = serialized.Split('#');
|
||||||
|
if (parts.Length != 4)
|
||||||
|
throw new SerializationException($"Can not deserialize String ({serialized}) to object of type ");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ulong id = ulong.Parse(parts[0]);
|
||||||
|
float lat = float.Parse(parts[1], NumberStyles.Float, CultureInfo.InvariantCulture);
|
||||||
|
float lon = float.Parse(parts[2], NumberStyles.Float, CultureInfo.InvariantCulture);
|
||||||
|
Dictionary<ulong, ulong> neighbors = parts[3].Length > 3
|
||||||
|
? parts[3].Split(',').ToDictionary(str => ulong.Parse(str.Split('-')[0]), str => ulong.Parse(str.Split('-')[1]))
|
||||||
|
: new();
|
||||||
|
|
||||||
|
return new Node(id, lat, lon, neighbors);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new SerializationException($"Exception during Deserialization of OSM_Graph.Node ({serialized}):", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
13
OSM_Graph/OSM_Graph.csproj
Normal file
13
OSM_Graph/OSM_Graph.csproj
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Graph\Graph.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
39
OSM_Graph/Way.cs
Normal file
39
OSM_Graph/Way.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace OSM_Graph;
|
||||||
|
|
||||||
|
public class Way(ulong id, Dictionary<string, string> tags, List<ulong> nodeIds) : Graph.Way(tags), IOSMSerializable<Way>
|
||||||
|
{
|
||||||
|
public readonly ulong ID = id;
|
||||||
|
public readonly List<ulong> NodeIds = nodeIds;
|
||||||
|
|
||||||
|
public string Serialize()
|
||||||
|
{
|
||||||
|
string tags = string.Join(',', Tags.Select(t =>
|
||||||
|
$"{t.Key.Replace("$", "Dollar")}${t.Value.Replace("$", "Dollar")}"
|
||||||
|
.Replace(',', '.')
|
||||||
|
.Replace("#", "No.")));
|
||||||
|
return $"{ID}#{string.Join(',', NodeIds)}#{Regex.Replace(tags, @"[^a-zA-Z0-9!%-\/:-@\[-_\{-\~$]", "")}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Way Deserialize(string serialized)
|
||||||
|
{
|
||||||
|
string[] parts = serialized.Split('#');
|
||||||
|
if (parts.Length != 3)
|
||||||
|
throw new SerializationException($"Can not deserialize String ({serialized}) to OSM_Graph.Way");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ulong id = ulong.Parse(parts[0]);
|
||||||
|
List<ulong> nodes = parts[1].Split(',').Select(ulong.Parse).ToList();
|
||||||
|
Dictionary<string, string> t = parts[2].Length > 0
|
||||||
|
? parts[2].Split(',') .ToDictionary(str => str.Split('$')[0].Replace("Dollar", "$"), str => str.Split('$')[1].Replace("Dollar", "$"))
|
||||||
|
: new();
|
||||||
|
return new Way(id, t, nodes);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new SerializationException($"Exception during Deserialization of OSM_Graph.Way ({serialized}):", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user