/// <summary> /// Determine where exactly the current trainpath node is on the track node /// </summary> /// <param name="startNode">The start node</param> /// <param name="nextNode">The next node (so also the direction can be understood)</param> /// <param name="tn">The tracknode connecting the startNode and nextNode</param> /// <param name="isForward">Output: whether going from startNode to nextNode is in the forward direction of the track</param> /// <param name="tvsiStart">Output: the track vector section index of where the startNode is</param> /// <param name="sectionOffsetStart">Output: the offset in the section (in the direction of the tracknode, not necessarily in the direction from startNode to nextNode)</param> private void DetermineSectionDetails(TrainpathNode startNode, TrainpathNode nextNode, TrackNode tn, out bool isForward, out int tvsiStart, out float sectionOffsetStart) { TrainpathVectorNode currentNodeAsVector = startNode as TrainpathVectorNode; TrainpathJunctionNode currentNodeAsJunction = startNode as TrainpathJunctionNode; if (currentNodeAsJunction != null) { // we start at a junction node isForward = (currentNodeAsJunction.JunctionIndex == tn.JunctionIndexAtStart()); if (isForward) { tvsiStart = 0; sectionOffsetStart = 0; } else { tvsiStart = tn.TrVectorNode.TrVectorSections.Count() - 1; sectionOffsetStart = SectionLengthAlongTrack(tn, tvsiStart); } } else { // we start at a vector node isForward = currentNodeAsVector.IsEarlierOnTrackThan(nextNode); tvsiStart = currentNodeAsVector.TrackVectorSectionIndex; sectionOffsetStart = currentNodeAsVector.TrackSectionOffset; } }
/// <summary> /// Update (or fully recalculate) the data for charting the path /// </summary> /// <param name="trainpath">The train path for which to store chart data</param> public void Update(Trainpath trainpath) { this.PathName = trainpath.PathName; var localPathChartPoints = new List <PathChartPoint>(); DistanceAlongPath = new Dictionary <TrainpathNode, double>(); ResetAllMinMax(); TrainpathNode node = trainpath.FirstNode; float lastDistance = 0; while (node != null) { DistanceAlongPath[node] = lastDistance; IEnumerable <PathChartPoint> additionalPoints = DetermineChartPoints(node); foreach (PathChartPoint relativePoint in additionalPoints) { PathChartPoint absolutePoint = new PathChartPoint(relativePoint, lastDistance); lastDistance += relativePoint.DistanceAlongNextSection; AddPoint(localPathChartPoints, absolutePoint); } node = node.NextMainNode; } //todo possibly we need to change the information on the last node, and copy e.g. the grade from the last-but-one node PathChartPoints = localPathChartPoints; StoreAllMinMax(); }
/// <summary> /// Constructor for a first point /// </summary> /// <param name="node">The node describing where the location of the point is</param> public PathChartPoint(TrainpathNode node) { HeightM = node.Location.Location.Y; DistanceAlongPath = 0; Curvature = 0; GradePercent = 0; DistanceAlongNextSection = 0; TrackItemText = String.Empty; TrackItemType = ChartableTrackItemType.None; }
private PathChartPoint CreateBrokenChartPoint(TrainpathNode thisNode, TrainpathNode nextNode) { float height = thisNode.Location.Location.Y; float distance = (float)Math.Sqrt(WorldLocation.GetDistanceSquared(thisNode.Location, nextNode.Location)); float heightOther = nextNode.Location.Location.Y; float grade = (heightOther - height) / distance; float curvature = 0; PathChartPoint brokenPoint = new PathChartPoint(height, curvature, grade, distance); return(brokenPoint); }
/// <summary> /// Determine if the path from currentNode to nextNode is in the forward direction of the track (along main path) /// </summary> private bool DetermineIfForward(TrainpathNode currentNode, TrainpathNode nextNode) { // It would be nice if we could separate this into different classes for vector and junction, but this would mean creating three additional classes for only a few methods TrainpathVectorNode currentNodeAsVector = currentNode as TrainpathVectorNode; if (currentNodeAsVector != null) { return(currentNodeAsVector.IsEarlierOnTrackThan(nextNode)); } else { TrainpathJunctionNode currentNodeAsJunction = currentNode as TrainpathJunctionNode; return(currentNodeAsJunction.JunctionIndex == trackDB.TrackNodes[currentNode.NextMainTvnIndex].JunctionIndexAtStart()); } }
/// <summary> /// Determine the index of the trackvectorsection of the node in the track defined by the track vector node /// </summary> /// <param name="node">The node for which to determine the track vector section index</param> /// <param name="tvn">Track vector index of which we want to find the section</param> /// <returns></returns> private int DetermineTrackVectorSection(TrainpathNode node, int tvn) { // It would be nice if we could separate this into different classes for vector and junction, but this would mean creating three additional classes for only a few methods TrainpathVectorNode nodeAsVector = node as TrainpathVectorNode; if (nodeAsVector != null) { return(nodeAsVector.TrackVectorSectionIndex); } else { TrainpathJunctionNode currentNodeAsJunction = node as TrainpathJunctionNode; if (currentNodeAsJunction.JunctionIndex == trackDB.TrackNodes[node.NextMainTvnIndex].JunctionIndexAtStart()) { return(0); } else { return(trackDB.TrackNodes[node.NextMainTvnIndex].TrVectorNode.TrVectorSections.Count() - 1); } } }
/// <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); }