/// <summary> /// Draw (part of) a tracksection (either curved or straight) /// </summary> /// <param name="drawArea">Area to draw upon</param> /// <param name="tvs">The vectorSection itself that needs to be drawn</param> /// <param name="colors">Colorscheme to use</param> /// <param name="startOffset">Do not draw the first startOffset meters in the section</param> /// <param name="stopOffset">Do not draw past stopOffset meters (draw all if stopOffset less than 0)</param> /// <remarks>Note that his is very similar to DrawTrackSection in class DrawTrackDB, but this one allows to draw partial sections</remarks> private void DrawTrackSection(DrawArea drawArea, TrackVectorSection tvs, ColorScheme colors, float startOffset, float stopOffset) { TrackSection trackSection = tsectionDat.TrackSections.Get(tvs.SectionIndex); if (trackSection == null) { return; } ref readonly WorldLocation thisLocation = ref tvs.Location;
protected TravellerInitializationException(Exception innerException, int tileX, int tileZ, float x, float y, float z, TrackVectorSection tvs, float errorLimit, string format, params object[] args) : base(string.Format(CultureInfo.CurrentCulture, format, args), innerException) { TileX = tileX; TileZ = tileZ; X = x; Y = y; Z = z; TrackVectorSection = tvs; ErrorLimit = errorLimit; }
/// <summary> /// Find the exact distance of the start of the current tracksection (from the beginning of the vector node) /// </summary> /// <returns></returns> private float GetSectionStartDistance() { float distanceFromStart = 0; TrackVectorNode tn = TrackDB.TrackNodes[TvnIndex] as TrackVectorNode; for (int tvsi = 0; tvsi < TrackVectorSectionIndex; tvsi++) { TrackVectorSection tvs = tn.TrackVectorSections[tvsi]; TrackSection trackSection = TsectionDat.TrackSections.Get(tvs.SectionIndex); if (trackSection != null) // if trackSection is missing somehow, well, do without. { distanceFromStart += DrawTrackDB.GetLength(trackSection); } } return(distanceFromStart); }
/// <summary> /// Get the curvature for the current section index in a vector track node. /// </summary> /// <param name="vectorNode">The vector track node</param> /// <param name="tvsi">The tracknode vector section index in the given verctor track node</param> /// <param name="isForward">Is the path in the same direction as the vector track node?</param> private float GetCurvature(TrackVectorNode vectorNode, int tvsi, bool isForward) { TrackVectorSection tvs = vectorNode.TrackVectorSections[tvsi]; TrackSection trackSection = tsectionDat.TrackSections.Get(tvs.SectionIndex); float curvature = 0; if (trackSection?.Curved ?? false) // if it is null, something is wrong but we do not want to crash { curvature = Math.Sign(trackSection.Angle) / trackSection.Radius; if (!isForward) { curvature *= -1; } } return(curvature); }
/// <summary> /// Determine the length of the section along the track. /// </summary> /// <param name="tn">The current tracknode, which needs to be a vector node</param> /// <param name="tvsi">The track vector section index</param> private float SectionLengthAlongTrack(TrackVectorNode tn, int tvsi) { float fullSectionLength; TrackVectorSection tvs = tn.TrackVectorSections[tvsi]; TrackSection trackSection = tsectionDat.TrackSections.Get(tvs.SectionIndex); if (trackSection == null) { return(100); // need to return something. Not easy to recover } if (trackSection.Curved) { fullSectionLength = trackSection.Radius * Math.Abs(Microsoft.Xna.Framework.MathHelper.ToRadians(trackSection.Angle)); } else { fullSectionLength = trackSection.Length; } return(fullSectionLength); }
public TravellerOutsideBoundingAreaException(int tileX, int tileZ, float x, float y, float z, TrackVectorSection tvs, float errorLimit, float dx, float dz) : base(null, tileX, tileZ, x, y, z, tvs, errorLimit, "{0} is ({3} > {2} or {4} > {2}) outside the bounding area of track vector section {1}", new WorldLocation(tileX, tileZ, x, y, z), tvs, errorLimit, dx, dz) { DistanceX = dx; DistanceZ = dz; }
public TravellerBeyondTrackLengthException(int tileX, int tileZ, float x, float y, float z, TrackVectorSection tvs, float errorLimit, float length, float distance) : base(null, tileX, tileZ, x, y, z, tvs, errorLimit, "{0} is ({2} < {3} or {2} > {4}) beyond the extents of track vector section {1}", new WorldLocation(tileX, tileZ, x, y, z), tvs, distance, -errorLimit, length + errorLimit) { Length = length; Distance = distance; }
public TravellerOutsideCenterlineException(int tileX, int tileZ, float x, float y, float z, TrackVectorSection tvs, float errorLimit, float distance) : base(null, tileX, tileZ, x, y, z, tvs, errorLimit, "{0} is ({2} > {3}) from the centerline of track vector section {1}", new WorldLocation(tileX, tileZ, x, y, z), tvs, distance, errorLimit) { Distance = distance; }
public TrackSegment(TrackVectorSection trackVectorSection, TrackSection trackSection, uint trackNodeIndex) { ref readonly WorldLocation location = ref trackVectorSection.Location;
private void AddTrackSegments() { double minX = double.MaxValue, minY = double.MaxValue, maxX = double.MinValue, maxY = double.MinValue; List <TrackSegment> trackSegments = new List <TrackSegment>(); List <TrackEndSegment> endSegments = new List <TrackEndSegment>(); List <JunctionSegment> junctionSegments = new List <JunctionSegment>(); List <TrackSegment> roadSegments = new List <TrackSegment>(); List <TrackEndSegment> roadEndSegments = new List <TrackEndSegment>(); foreach (TrackNode trackNode in trackDB?.TrackNodes ?? Enumerable.Empty <TrackNode>()) { switch (trackNode) { case TrackEndNode trackEndNode: TrackVectorNode connectedVectorNode = trackDB.TrackNodes[trackEndNode.TrackPins[0].Link] as TrackVectorNode; endSegments.Add(new TrackEndSegment(trackEndNode, connectedVectorNode, trackSectionsFile.TrackSections)); break; case TrackVectorNode trackVectorNode: foreach (TrackVectorSection trackVectorSection in trackVectorNode.TrackVectorSections) { TrackSection trackSection = trackSectionsFile.TrackSections.Get(trackVectorSection.SectionIndex); if (trackSection != null) { trackSegments.Add(new TrackSegment(trackVectorSection, trackSection, trackVectorNode.Index)); } } break; case TrackJunctionNode trackJunctionNode: foreach (TrackPin pin in trackJunctionNode.TrackPins) { if (trackDB.TrackNodes[pin.Link] is TrackVectorNode vectorNode && vectorNode.TrackVectorSections.Length > 0) { TrackVectorSection item = pin.Direction == Common.TrackDirection.Reverse ? vectorNode.TrackVectorSections.First() : vectorNode.TrackVectorSections.Last(); } } junctionSegments.Add(new JunctionSegment(trackJunctionNode)); break; } } TrackSegments = new TileIndexedList <TrackSegment, Tile>(trackSegments); JunctionSegments = new TileIndexedList <JunctionSegment, Tile>(junctionSegments); TrackEndSegments = new TileIndexedList <TrackEndSegment, Tile>(endSegments); TrackNodeSegments = trackSegments.GroupBy(t => t.TrackNodeIndex).ToDictionary(i => i.Key, i => i.ToList()); foreach (TrackNode trackNode in roadTrackDB?.TrackNodes ?? Enumerable.Empty <TrackNode>()) { switch (trackNode) { case TrackEndNode trackEndNode: TrackVectorNode connectedVectorNode = roadTrackDB.TrackNodes[trackEndNode.TrackPins[0].Link] as TrackVectorNode; roadEndSegments.Add(new RoadEndSegment(trackEndNode, connectedVectorNode, trackSectionsFile.TrackSections)); break; case TrackVectorNode trackVectorNode: foreach (TrackVectorSection trackVectorSection in trackVectorNode.TrackVectorSections) { TrackSection trackSection = trackSectionsFile.TrackSections.Get(trackVectorSection.SectionIndex); if (trackSection != null) { roadSegments.Add(new RoadSegment(trackVectorSection, trackSection, trackVectorNode.Index)); } } break; } } RoadSegments = new TileIndexedList <RoadSegment, Tile>(roadSegments); RoadEndSegments = new TileIndexedList <RoadEndSegment, Tile>(roadEndSegments); RoadTrackNodeSegments = roadSegments.GroupBy(t => t.TrackNodeIndex).ToDictionary(i => i.Key, i => i.ToList()); Tiles = new TileIndexedList <GridTile, Tile>( TrackSegments.Select(d => d.Tile as ITile).Distinct() .Union(TrackEndSegments.Select(d => d.Tile as ITile).Distinct()) .Union(RoadSegments.Select(d => d.Tile as ITile).Distinct()) .Union(RoadEndSegments.Select(d => d.Tile as ITile).Distinct()) .Select(t => new GridTile(t))); if (Tiles.Count == 1) { foreach (TrackEndSegment trackEndSegment in TrackEndSegments) { minX = Math.Min(minX, trackEndSegment.Location.X); minY = Math.Min(minY, trackEndSegment.Location.Y); maxX = Math.Max(maxX, trackEndSegment.Location.X); maxY = Math.Max(maxY, trackEndSegment.Location.Y); } } else { minX = Math.Min(minX, Tiles[0][0].Tile.X); maxX = Math.Max(maxX, Tiles[Tiles.Count - 1][0].Tile.X); foreach (GridTile tile in Tiles) { minY = Math.Min(minY, tile.Tile.Z); maxY = Math.Max(maxY, tile.Tile.Z); } minX = minX * WorldLocation.TileSize - WorldLocation.TileSize / 2; maxX = maxX * WorldLocation.TileSize + WorldLocation.TileSize / 2; minY = minY * WorldLocation.TileSize - WorldLocation.TileSize / 2; maxY = maxY * WorldLocation.TileSize + WorldLocation.TileSize / 2; } Bounds = new Rectangle((int)minX, (int)minY, (int)(maxX - minX), (int)(maxY - minY)); }