diff --git a/.editorconfig b/.editorconfig index 485226cd783482f910d0c62349727a80d4aefb5a..510ffa0f17955cecc5ba18ec179ffbca079e82dd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -22,6 +22,15 @@ csharp_space_around_binary_operators = ignore # CS8604: Possible null reference argument. dotnet_diagnostic.CS8604.severity = silent +# CS8602: Dereference of a possibly null reference. +dotnet_diagnostic.CS8602.severity = silent + +# CS8603: Possible null reference return. +dotnet_diagnostic.CS8603.severity = silent + +# CS8620: Argument cannot be used for parameter due to differences in the nullability of reference types. +dotnet_diagnostic.CS8620.severity = silent + [*.{cs,vb}] #### Naming styles #### diff --git a/ZeroMQTest/Code/KV1.cs b/ZeroMQTest/Code/KV1.cs index 2f337708c3c6be7a6b4b5c7bf1569b60961eeb34..1d4ca0c0b7f395cbeb3883a583ec09f4566f4cbd 100644 --- a/ZeroMQTest/Code/KV1.cs +++ b/ZeroMQTest/Code/KV1.cs @@ -4,9 +4,63 @@ using System.Reflection; namespace WanderOV { - public class KV1 + public class KV1 { - OV ov; + internal enum TransportType + { + Bus, + Tram, + Ferry, + Train, + Unknown + } + + internal class Line + { + internal string Id; + internal string publicNumber; // What is shown on display front Bus/Tram. String because might C11. + internal string fromName; + internal string toName; + internal TransportType transportType; + } + + internal class Destination + { + internal string Id; + internal string mainDest; + internal string destDetail; + } + + internal class Stop + { + internal string Id; // This is equivalent to UserStopCode (highly confusing..). + internal float x; + internal float y; + internal string name; + internal string city; + } + + internal class Link + { + internal string fromId; + internal string toId; + internal List<(float rdx, float rdy)> points; // list of rdx, rdy points. + } + + internal class Journey + { + internal string Id; + internal Line line; + internal Destination dest; + internal List<Stop> stops; + } + + internal Dictionary<string, Stop> stops = new Dictionary<string, Stop>(); + internal Dictionary<string, Line> lines = new Dictionary<string, Line>(); + internal Dictionary<string, Destination> destinations = new Dictionary<string, Destination>(); + internal Dictionary<string, Link> links = new Dictionary<string, Link>(); + internal Dictionary<string, Journey> journeys = new Dictionary<string, Journey>(); + string curZipPath; string curEntry; @@ -20,11 +74,10 @@ namespace WanderOV void LoadLine( CsvDataReader csv ) { var key = MakeKey( csv, out var owner, out var code ); - if (!ov.lines.ContainsKey( key )) + if (!lines.ContainsKey( key )) { var line = new Line(); - line.owner = owner; - line.linePlanningNumber = code; + line.Id = code; line.publicNumber = csv.GetString( 5 ); string lineName = csv.GetString( 6 ); string [] fromTo = lineName.Split( '-' ); @@ -44,7 +97,7 @@ namespace WanderOV _ => TransportType.Unknown }; - ov.lines.Add( key, line ); + lines.Add( key, line ); } else { @@ -55,14 +108,13 @@ namespace WanderOV void LoadDest( CsvDataReader csv ) { var key = MakeKey( csv, out var owner, out var code ); - if (!ov.destinations.ContainsKey( key )) + if (!destinations.ContainsKey( key )) { var dest = new Destination(); - dest.owner = owner; - dest.destCode = code; + dest.Id = code; dest.mainDest = csv.GetString( 6 ); dest.destDetail = csv.GetString( 7 ); - ov.destinations.Add( key, dest ); + destinations.Add( key, dest ); } else { @@ -74,13 +126,12 @@ namespace WanderOV void LoadStop( CsvDataReader csv ) { var key = MakeKey( csv, out var owner, out var code ); - if (!ov.stops.ContainsKey( key )) + if (!stops.ContainsKey( key )) { var stop = new Stop(); - stop.owner = owner; - stop.pointCode = code; - stop.rdx = csv.GetInt32( 8 ); - stop.rdy = csv.GetInt32( 9 ); + stop.Id = code; + stop.x = csv.GetInt32( 8 ); + stop.y = csv.GetInt32( 9 ); var desc = csv.GetString( 11 ); string[] cityStop = desc.Split( ',' ); if ( cityStop.Length > 1 ) @@ -92,7 +143,7 @@ namespace WanderOV { stop.name = cityStop[0]; } - ov.stops.Add( key, stop ); + stops.Add( key, stop ); } else { @@ -106,28 +157,26 @@ namespace WanderOV var fromPoint = csv.GetString(4); var toPoint = csv.GetString(5); var key = string.Join(':', fromPoint, toPoint ); - if (!ov.links.ContainsKey( key )) + if (!links.ContainsKey( key )) { var link = new Link(); - link.owner = owner; - ov.links.Add( key, link ); + links.Add( key, link ); } } void LoadJourney( CsvDataReader csv ) { var key = MakeKey( csv, out var owner, out var code ); - if (!ov.journeys.TryGetValue( key, out var journey )) + if (!journeys.TryGetValue( key, out var journey )) { journey = new Journey(); - journey.owner = owner; - journey.journeyCode = code; - ov.destinations.TryGetValue( csv.GetString( 10 ), out journey.dest ); - ov.lines.TryGetValue( csv.GetString( 4 ), out journey.line ); + journey.Id = code; + destinations.TryGetValue( csv.GetString( 10 ), out journey.dest ); + lines.TryGetValue( csv.GetString( 4 ), out journey.line ); journey.stops = new List<Stop>(); - ov.journeys.Add( key , journey ); + journeys.Add( key , journey ); } - ov.stops.TryGetValue( csv.GetString( 8 ), out var stop ); + stops.TryGetValue( csv.GetString( 8 ), out var stop ); journey.stops.Add( stop ); } @@ -142,7 +191,7 @@ namespace WanderOV } } - public OV LoadAll(string folder) + public void LoadAll(string folder) { string strExeFilePath = Assembly.GetExecutingAssembly().Location; string strWorkPath = Path.GetDirectoryName(strExeFilePath); @@ -151,11 +200,10 @@ namespace WanderOV if (!Directory.Exists( searchPath )) { Console.WriteLine( searchPath + " does not exist, nothing loaded." ); - return null; + return; } // Load TMI files - ov = new OV(); var zippedTmiArchives = Directory.GetFiles( searchPath, "*.zip", SearchOption.AllDirectories ); foreach ( var zipPath in zippedTmiArchives) @@ -181,8 +229,6 @@ namespace WanderOV Console.WriteLine( "TMI Loaded " + Path.GetFileName( zipPath ) ); } - - return ov; } } diff --git a/ZeroMQTest/Code/Netex.cs b/ZeroMQTest/Code/Netex.cs index b1d3c5d453f81021ec729dee44a5c83d1c3fc49f..245b757cbb15c262f8d2b0642088f14e0a161563 100644 --- a/ZeroMQTest/Code/Netex.cs +++ b/ZeroMQTest/Code/Netex.cs @@ -1,92 +1,307 @@ -using System.IO.Compression; + +using System.Diagnostics; +using System.IO.Compression; using System.Reflection; -using System.Text; using System.Xml; +using System.Xml.Linq; +using static WanderOV.KV1; namespace WanderOV { + public static class XmlUtils + { + public static XmlElement GetChild( this XmlElement elem, string name ) + { + for (int i = 0;i <elem.ChildNodes.Count;i++) + { + var child = elem.ChildNodes[i]; + if (child.Name==name) + return child as XmlElement; + } + return null; + } + } + public class Netex - { - OV ov; - string curZipPath; + { + class RoutePoint + { + internal float rdx, rdy; + } + + class RouteLink + { + internal List<(float rdx, float rdy)> points; + internal RoutePoint from; + internal RoutePoint to; + } + + class Route + { + internal string line; + internal Line lineRef; + internal List<(RoutePoint, RouteLink)> routePoints; + } + + class Line + { + internal string name; + internal string displayNumber; + internal string transportType; + } + + class Destination + { + internal string frontText; + internal string sideText; + internal List<string> vias; + } + + class Stop + { + internal string name; + internal float rdx, rdy; + } + + class Journey // Omloop + { + internal Line line; + internal Route route; + internal Destination destination; + internal List<(Stop, Destination)> stops; + } + + + Dictionary<string, RoutePoint> routePoints = new Dictionary<string, RoutePoint>(); + Dictionary<string, RouteLink> routeLinks = new Dictionary<string, RouteLink>(); + Dictionary<string, Route> routes = new Dictionary<string, Route>(); + Dictionary<string, Line> lines = new Dictionary<string, Line>(); + Dictionary<string, Destination> destinations = new Dictionary<string, Destination>(); + Dictionary<string, Stop> stops = new Dictionary<string, Stop>(); + Dictionary<string, Journey> journeys = new Dictionary<string, Journey>(); + + public void PrintStats() + { + Console.WriteLine( $"Num routePoints {routePoints.Count}" ); + Console.WriteLine( $"Num routeLinks {routeLinks.Count}" ); + Console.WriteLine( $"Num routes {routes.Count}" ); + Console.WriteLine( $"Num lines {lines.Count}" ); + Console.WriteLine( $"Num destinations {destinations.Count}" ); + Console.WriteLine( $"Num stops {stops.Count}" ); + Console.WriteLine( $"Num journeys {journeys.Count}" ); + } + + void ParseElementList( XmlDocument doc, string name, Action<XmlElement> cb ) + { + var elemList = doc.GetElementsByTagName( name ); + foreach( var elem in elemList ) + { + cb( elem as XmlElement ); + } + } void LoadNetexFile( string xml ) { - // string owner = string.Empty; - string fromCode = string.Empty; - string toCode = string.Empty; - bool isPosList = false; - using var reader = XmlReader.Create(new MemoryStream(Encoding.UTF8.GetBytes(xml))); + var doc = new XmlDocument(); + doc.LoadXml( xml ); + ParseElementList( doc, "RoutePoint", LoadRoutePoint ); + ParseElementList( doc, "RouteLink", LoadRouteLink ); + ParseElementList( doc, "Route", LoadRoute ); + ParseElementList( doc, "Line", LoadLine ); + ParseElementList( doc, "DestinationDisplay", LoadDestination ); + ParseElementList( doc, "ScheduledStopPoint", LoadStop ); + ParseElementList( doc, "ServiceJourneyPattern", LoadJourney ); + } + + void LoadRoutePoint( XmlElement elem ) + { + var id = elem.GetAttribute( "id" ); + if (id != null && !routePoints.TryGetValue( id, out _ )) { - while (reader.Read()) + // try // Only add if everything can be filled in. { - switch (reader.NodeType) + var rp = new RoutePoint(); + var pos = elem.GetChild( "Location" ).GetChild( "gml:pos" ).InnerText.Split(' '); + if (pos.Length >= 2) // Sometimes nothing is encoded.. { - case XmlNodeType.Element: - if (reader.Name.StartsWith( "gml:LineString" )) - { - var attrib = reader.GetAttribute( "gml:id" ); - var words = attrib.Split( '_' ); - if (words.Length <= 1) - { - words = attrib.Split( '-' ); - // owner = words[0]; - fromCode = words[2]; - toCode = words[3]; - } - else - { - // owner = words[0]; - var fromTo = words[2].Split( '-' ); - fromCode = fromTo[0]; - toCode = fromTo[1]; - } - } - else if (reader.Name.StartsWith( "gml:posList" )) + rp.rdx = float.Parse( pos[0] ); + rp.rdy = float.Parse( pos[1] ); + } + routePoints.Add( id, rp ); + } + // catch { } + } + } + + void LoadRouteLink( XmlElement elem ) + { + var id = elem.GetAttribute( "id" ); + if (id != null && !routeLinks.TryGetValue( id, out _ )) + { + // try // Only add if everything can be filled in. + { + var link = new RouteLink(); + link.points = new List<(float rdx, float rdy)>(); + var posList = elem.GetChild( "gml:LineString" ).GetChild("gml:posList"); + if (posList != null) + { + var pos = posList.InnerText.Split( ' ', StringSplitOptions.RemoveEmptyEntries ); + if ((pos.Length >= 2) && (pos.Length % 2) == 0) // Sometimes nothing is encoded.. + { + for (int i = 0;i < pos.Length;i+= 2) { - isPosList = true; + link.points.Add( (float.Parse( pos[i] ), float.Parse( pos[i+1] )) ); } - break; + } + } + link.from = routePoints[elem.GetChild( "FromPointRef" ).GetAttribute("ref")]; + link.to = routePoints[elem.GetChild( "ToPointRef" ).GetAttribute("ref")]; + routeLinks.Add( id, link ); + } + // catch { } + } + } - case XmlNodeType.Text: - if (isPosList) - { - // 40000046:40000026 - if (fromCode == "40000046") - { - int jt = 0; - } + void LoadRoute( XmlElement elem ) + { + var id = elem.GetAttribute( "id" ); + if (id != null && !routes.TryGetValue( id, out _ )) + { + // try // Only add if everything can be filled in. + { + var route = new Route(); + route.line = elem.GetChild( "LineRef" ).GetAttribute( "ref" ); + route.routePoints = new List<(RoutePoint, RouteLink)>(); + var rp = elem.GetChild( "pointsInSequence" ).GetChild("PointOnRoute"); + while (rp != null) + { + var routePoint = routePoints[rp.GetChild( "RoutePointRef" ).GetAttribute( "ref" )]; + var linkToNext = rp.GetChild( "OnwardRouteLinkRef" ); + RouteLink link = null; + if (linkToNext != null) + { + link = routeLinks[linkToNext.GetAttribute("ref")]; + } + route.routePoints.Add((routePoint, link) ); + rp = rp.NextSibling as XmlElement; + } + routes.Add( id, route ); + } + // catch { } + } + } - var key = string.Join(':', fromCode, toCode ); - if (ov.links.TryGetValue( key, out var link )) + void LoadLine( XmlElement elem ) + { + var id = elem.GetAttribute( "id" ); + if (!lines.TryGetValue( id, out _ )) + { + // try // Only add if everything can be filled in. + { + var line = new Line(); + line.name = elem.GetChild( "Name" ).InnerText; + line.displayNumber = elem.GetChild( "PublicCode" ).InnerText; + line.transportType = elem.GetChild( "TransportMode" ).InnerText; + lines.Add( id, line ); + } + // catch { } + } + } + + void LoadDestination( XmlElement elem ) + { + var id = elem.GetAttribute( "id" ); + if (!destinations.TryGetValue( id, out _ )) + { + // try // Only add if everything can be filled in. + { + var dest = new Destination(); + dest.frontText = elem.GetChild( "FrontText" ).InnerText; + var sideTextNode = elem.GetChild( "SideText" ); + if( sideTextNode != null) + { + dest.sideText = sideTextNode.InnerText; + } + dest.vias = new List<string>(); + var vias = elem.GetChild("vias"); + if (vias != null) + { + var via = vias.GetChild( "Via" ); + while(via != null) + { + var name = via.GetChild( "Name" ).InnerText; + dest.vias.Add( name ); + via = via.NextSibling as XmlElement; + } + } + destinations.Add( id, dest ); + } + // catch { } + } + } + + void LoadStop( XmlElement elem ) + { + var id = elem.GetAttribute( "id" ); + if (!stops.TryGetValue( id, out _ )) + { + // try // Only add if everything can be filled in. + { + var stop = new Stop(); + stop.name = elem.GetChild( "Name" ).InnerText; + var cnt = elem.GetChild("Location").GetChild("gml:pos").InnerText; + var pos = cnt.Split( ' ' ); + if (pos.Length >= 2) + { + stop.rdx = float.Parse( pos[0] ); + stop.rdy = float.Parse( pos[1] ); + stops.Add( id, stop ); + } + } + // catch { } + } + } + + void LoadJourney( XmlElement elem ) + { + var id = elem.GetAttribute( "id" ); + if (!journeys.TryGetValue( id, out _ )) + { + // try // Only add if everything can be filled in. + { + var journey = new Journey(); + journey.route = routes[elem.GetChild("RouteRef").GetAttribute( "ref" )]; + journey.destination = destinations[elem.GetChild( "DestinationDisplayRef" ).GetAttribute( "ref" )]; + journey.line = lines[journey.route.line]; + journey.stops = new List<(Stop, Destination)>(); + var point = elem.GetChild("pointsInSequence").GetChild( "StopPointInJourneyPattern" ); + while (point != null ) + { + var scheduledStop = point.GetChild( "ScheduledStopPointRef" ); + if (scheduledStop != null) + { + if (stops.TryGetValue( scheduledStop.GetAttribute( "ref" ), out var stop )) + { + var destinationDisplay = point.GetChild( "DestinationDisplayRef" ); + Destination destination = null; // Can null at all times when destination text does not change after a stop. + if (destinationDisplay != null) { - link.points = new List<(float rdx, float rdy)>(); - var positions = reader.Value.Split( ' ', StringSplitOptions.RemoveEmptyEntries ); - for (int i = 0;i < positions.Length;i += 2) + if (destinations.TryGetValue( destinationDisplay.GetAttribute( "ref" ), out var newdest )) { - // try - { // If a point fails, just ignore, might not need to discard whole nework. - int rdx = int.Parse(positions[i]); - int rdy = int.Parse(positions[i+1]); - link.points.Add( (rdx, rdy) ); - } - // catch { } + destination = newdest; } } - else - { - // Console.WriteLine( $"Cannot find link: {key}" ); - } - isPosList = false; + journey.stops.Add( (stop, destination) ); } - break; - + } + point = point.NextSibling as XmlElement; } } + // catch { } } } - public void LoadAll(string folder) + public void LoadAll( string folder ) { string strExeFilePath = Assembly.GetExecutingAssembly().Location; string strWorkPath = Path.GetDirectoryName(strExeFilePath); @@ -98,7 +313,6 @@ namespace WanderOV return; } - // Load Netex file for route net/navigation. var gzFiles = Directory.GetFiles( searchPath, "*.gz", SearchOption.AllDirectories ); foreach (var gzPath in gzFiles) @@ -114,9 +328,15 @@ namespace WanderOV var netexXML = sr.ReadToEnd(); LoadNetexFile( netexXML ); - Console.WriteLine( "NETEX Loaded " + Path.GetFileName( gzPath ) ); } + + // Fix up Line references (they come after the Route). + foreach (var kvp in routes) + { + kvp.Value.lineRef = lines[kvp.Value.line]; + kvp.Value.line = string.Empty; + } } } diff --git a/ZeroMQTest/Code/OV.cs b/ZeroMQTest/Code/OV.cs deleted file mode 100644 index 29a44fdad0149848cf20442e662a23a5da9aca97..0000000000000000000000000000000000000000 --- a/ZeroMQTest/Code/OV.cs +++ /dev/null @@ -1,76 +0,0 @@ - -namespace WanderOV -{ - public enum TransportType - { - Bus, - Tram, - Ferry, - Train, - Unknown - } - - public class Line - { - public string owner; - public string linePlanningNumber; - public string publicNumber; // What is shown on display front Bus/Tram. String because might C11. - public string fromName; - public string toName; - public TransportType transportType; - } - - public class Destination - { - public string owner; - public string destCode; - public string mainDest; - public string destDetail; - } - - public class Stop - { - public string owner; - public string pointCode; // This is equivalent to UserStopCode (highly confusing..). - public float rdx; - public float rdy; - public string name; - public string city; - } - - public class Link - { - public string owner; - public int stopCodeBegin; - public int stopCodeEnd; - public List<(float rdx, float rdy)> points; // list of rdx, rdy points. - } - - public class Journey - { - public string owner; - public string journeyCode; - public Line line; - public Destination dest; - public List<Stop> stops; - } - - public class OV - { - // Some codes appear to start with a character, therefore we use strings instead of ints. - internal Dictionary<string, Stop> stops = new Dictionary<string, Stop>(); - internal Dictionary<string, Line> lines = new Dictionary<string, Line>(); - internal Dictionary<string, Destination> destinations = new Dictionary<string, Destination>(); - internal Dictionary<string, Link> links = new Dictionary<string, Link>(); - internal Dictionary<string, Journey> journeys = new Dictionary<string, Journey>(); - - public void PrintStats() - { - Console.WriteLine( $"Stops {stops.Count}" ); - Console.WriteLine( $"Lines {lines.Count}" ); - Console.WriteLine( $"Destinations {destinations.Count}" ); - Console.WriteLine( $"Links {links.Count}" ); - Console.WriteLine( $"Journeys {journeys.Count}" ); - } - } -} diff --git a/ZeroMQTest/Code/Program.cs b/ZeroMQTest/Code/Program.cs index 6b23ddf566de6a2e1a7ff0e02f6a6ba26cdf9274..2a7209a84356d0f6d2612858c180cdab153d13a7 100644 --- a/ZeroMQTest/Code/Program.cs +++ b/ZeroMQTest/Code/Program.cs @@ -6,17 +6,19 @@ p.Run(); class App { - OV ov; - //GTFS gtfs; ActiveOV activeOV; Broker broker; OVRequester requester; public App() { - KV1 kV1 = new KV1(); - ov = kV1.LoadAll( "_database" ); - ov.PrintStats(); + //KV1 kV1 = new KV1(); + //ov = kV1.LoadAll( "_database" ); + //ov.PrintStats(); + + Netex netex = new Netex(); + netex.LoadAll("_database"); + netex.PrintStats(); activeOV = new ActiveOV(); broker = new Broker(9999);