/// <summary> /// Determine the trackItems and their location in the given tracknode. /// </summary> /// <param name="tn">The tracknode in which to search for track items</param> /// <returns>The list/set of track itemss together with their position information</returns> public IEnumerable <ChartableTrackItem> GetItemsInTracknode(TrackNode tn) { if (cachedItems.ContainsKey(tn)) { return(cachedItems[tn]); } List <ChartableTrackItem> tracknodeItems = new List <ChartableTrackItem>(); TrVectorNode vectorNode = tn.TrVectorNode; if (vectorNode.TrItemRefs == null) { return(tracknodeItems); } foreach (int trackItemIndex in vectorNode.TrItemRefs) { TrItem trItem = trackDB.TrItemTable[trackItemIndex]; if (supportedTrackTypes.Contains(trItem.ItemType)) { var travellerAtItem = new Traveller(tsectionDat, trackDB.TrackNodes, tn, trItem.TileX, trItem.TileZ, trItem.X, trItem.Z, Traveller.TravellerDirection.Forward); if (travellerAtItem != null) { tracknodeItems.Add(new ChartableTrackItem(trItem, travellerAtItem)); } } } tracknodeItems.Sort(new AlongTrackComparer()); cachedItems[tn] = tracknodeItems; return(tracknodeItems); }
/// <summary> /// From section information create a point for charting the path, and add it to newPoints. /// In case there are track items in this particular section, add those also (starting with the last item as seen from the direction of the path) /// </summary> /// <param name="newPoints">The list to which to add the point</param> /// <param name="vectorNode">The vectorNode to use for curvature and grade</param> /// <param name="trackItems">A list of track items in this vector tracknode</param> /// <param name="isForward">Is the path in the same direction as the tracknode</param> /// <param name="height">Height to store in the point</param> /// <param name="tvsi">The section index in the track vector node</param> /// <param name="sectionOffsetStart">Offset of the start of this section (in forward direction of track, not of path)</param> /// <param name="sectionOffsetStart">Offset of the end of this section (in forward direction of track, not of path)</param> private void AddPointAndTrackItems(List <PathChartPoint> newPoints, TrVectorNode vectorNode, IEnumerable <ChartableTrackItem> trackItems, bool isForward, float height, int tvsi, float sectionOffsetStart, float sectionOffsetEnd) { //Note, we are adding points in in reverse direction var additionalPoints = new List <PathChartPoint>(); // not a percentage. We can safely assume the pitch is small enough so we do not to take tan(pitch) float gradeFromPitch = -vectorNode.TrVectorSections[tvsi].AX * (isForward ? 1 : -1); float curvature = GetCurvature(vectorNode, tvsi, isForward); List <ChartableTrackItem> items_local = trackItems.ToList(); if (isForward) { items_local.Reverse(); } PathChartPoint newPoint; foreach (ChartableTrackItem chartableItem in items_local) { if (chartableItem.TrackVectorSectionIndex == tvsi && sectionOffsetStart <= chartableItem.TrackVectorSectionOffset && chartableItem.TrackVectorSectionOffset < sectionOffsetEnd) { if (isForward) { //For forward, we start at the last item in the track newPoint = new PathChartPoint(chartableItem.Height, curvature, gradeFromPitch, sectionOffsetEnd - chartableItem.TrackVectorSectionOffset, chartableItem.ItemText, chartableItem.ItemType); sectionOffsetEnd = chartableItem.TrackVectorSectionOffset; } else { //For reverse, we have to swap forward and reverse speed limits ChartableTrackItemType itemType = chartableItem.ItemType == ChartableTrackItemType.SpeedLimitForward ? ChartableTrackItemType.SpeedLimitReverse : chartableItem.ItemType == ChartableTrackItemType.SpeedLimitReverse ? ChartableTrackItemType.SpeedLimitForward : chartableItem.ItemType; //For reverse, we start at the first item in the track newPoint = new PathChartPoint(chartableItem.Height, curvature, gradeFromPitch, chartableItem.TrackVectorSectionOffset - sectionOffsetStart, chartableItem.ItemText, itemType); sectionOffsetStart = chartableItem.TrackVectorSectionOffset; } additionalPoints.Add(newPoint); } } newPoint = new PathChartPoint(height, curvature, gradeFromPitch, sectionOffsetEnd - sectionOffsetStart); additionalPoints.Add(newPoint); newPoints.AddRange(additionalPoints); }
public static int searchIdx(this TrackNode node, TrVectorSection currentSection) { TrVectorNode nodes = node.TrVectorNode; if (nodes == null || nodes.TrVectorSections == null) { return(0); } for (int cnt = 0; cnt < nodes.TrVectorSections.Count(); cnt++) { if (nodes.TrVectorSections[cnt].SectionIndex == currentSection.SectionIndex && nodes.TrVectorSections[cnt].WorldFileUiD == currentSection.WorldFileUiD) { return(cnt); } } return(0); }
private List <string> StationNamesBetweenNodes(TrainpathNode firstNode, TrainpathNode secondNode) { var stationNames = new List <string>(); int tvnIndex = firstNode.NextMainTvnIndex; if (tvnIndex < 0) { return(stationNames); } TrackNode tn = trackDB.TrackNodes[tvnIndex]; TrVectorNode tvn = tn.TrVectorNode; if (tvn == null) { return(stationNames); } if (tvn.TrItemRefs == null) { return(stationNames); } foreach (int trackItemIndex in tvn.TrItemRefs) { TrItem trItem = trackDB.TrItemTable[trackItemIndex]; if (trItem.ItemType == TrItem.trItemType.trPLATFORM) { var traveller = new Traveller(tsectionDat, trackDB.TrackNodes, tn, trItem.TileX, trItem.TileZ, trItem.X, trItem.Z, Traveller.TravellerDirection.Forward); if (traveller != null) { var platformNode = new TrainpathVectorNode(firstNode, traveller); if (platformNode.IsBetween(firstNode, secondNode)) { PlatformItem platform = trItem as PlatformItem; stationNames.Add(platform.Station); } } } } return(stationNames); }
/// <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(TrVectorNode vectorNode, int tvsi, bool isForward) { TrVectorSection tvs = vectorNode.TrVectorSections[tvsi]; TrackSection trackSection = tsectionDat.TrackSections.Get(tvs.SectionIndex); float curvature = 0; if (trackSection != null) // if it is null, something is wrong but we do not want to crash { SectionCurve thisCurve = trackSection.SectionCurve; if (thisCurve != null) { curvature = Math.Sign(thisCurve.Angle) / thisCurve.Radius; if (!isForward) { curvature *= -1; } } } return(curvature); }
/// <summary> /// Determine the ChartPoints from the startNode (included) until but not including the endNode=startNode.NextMainNode /// Each tracksection-begin should be a new point /// </summary> /// <param name="thisNode">The node to start with</param> /// <remarks>The assumption is that the two trainpath nodes only have a single tracknode connecting them</remarks> /// <returns>At least one new chart point</returns> private IEnumerable <PathChartPoint> DetermineChartPoints(TrainpathNode thisNode) { // The track consists of a number of sections. These sections might be along the direction we are going in (isForward) or not // The first point (belonging to currentNode) is the first we return, and possibly the only one. // Any new points we are going to add are all at the boundaries of sections // From the track database we get the (height) data only at start of a section. // If we are moving forward the height at the section boundary is coming from the section just after the boundary // If we are moving reverse the height at the section boundary is coming from the section just before the boundary; var newPoints = new List <PathChartPoint>(); TrainpathNode nextNode = thisNode.NextMainNode; if (nextNode == null) { PathChartPoint singlePoint = new PathChartPoint(thisNode); newPoints.Add(singlePoint); return(newPoints); } if (thisNode.IsBroken || nextNode.IsBroken || thisNode.NextMainTvnIndex == -1) { PathChartPoint singlePoint = CreateBrokenChartPoint(thisNode, nextNode); newPoints.Add(singlePoint); return(newPoints); } TrackNode tn = trackDB.TrackNodes[thisNode.NextMainTvnIndex]; TrVectorNode vectorNode = tn.TrVectorNode; var trackItemsInTracknode = trackItems.GetItemsInTracknode(tn); bool isForward; bool isReverse; // only dummy out argument int tvsiStart; int tvsiStop; float sectionOffsetStart; float sectionOffsetStop; DetermineSectionDetails(thisNode, nextNode, tn, out isForward, out tvsiStart, out sectionOffsetStart); DetermineSectionDetails(nextNode, thisNode, tn, out isReverse, out tvsiStop, out sectionOffsetStop); float height; if (isForward) { // We add points in reverse order, so starting at the last section and its index float sectionOffsetNext = sectionOffsetStop; for (int tvsi = tvsiStop; tvsi > tvsiStart; tvsi--) { height = vectorNode.TrVectorSections[tvsi].Y; AddPointAndTrackItems(newPoints, vectorNode, trackItemsInTracknode, isForward, height, tvsi, 0, sectionOffsetNext); sectionOffsetNext = SectionLengthAlongTrack(tn, tvsi - 1); } //Also works in case this is the only point we are adding height = thisNode.Location.Location.Y; AddPointAndTrackItems(newPoints, vectorNode, trackItemsInTracknode, isForward, height, tvsiStart, sectionOffsetStart, sectionOffsetNext); } else { //reverse // We add points in reverse order, so starting at the first section and its index float sectionOffsetNext = sectionOffsetStop; for (int tvsi = tvsiStop; tvsi < tvsiStart; tvsi++) { // The height needs to come from the end of the section, so the where the next section starts. And we only know the height at the start. height = vectorNode.TrVectorSections[tvsi + 1].Y; AddPointAndTrackItems(newPoints, vectorNode, trackItemsInTracknode, isForward, height, tvsi, sectionOffsetNext, SectionLengthAlongTrack(tn, tvsi)); sectionOffsetNext = 0; } //Also works in case this is the only point we are adding height = thisNode.Location.Location.Y; AddPointAndTrackItems(newPoints, vectorNode, trackItemsInTracknode, isForward, height, tvsiStart, sectionOffsetNext, sectionOffsetStart); } newPoints.Reverse(); return(newPoints); }