/// <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> /// Translate a curvature to a deviation in the chart. For now, basically we use sign /// </summary> /// <param name="pathPoint">The single point for which to determine the deviation from 0</param> private float CurvatureDeviation(PathChartPoint pathPoint) { float deviation = 10 * Math.Sign(pathPoint.Curvature); //deviation = pathPoint.Curvature; return(deviation); }
/// <summary> /// Constructor from another PathChartPoint, only shifted in distance along the path /// </summary> /// <param name="sourcePoint">The point to copy from</param> /// <param name="distanceShift">Extra distance along the path</param> public PathChartPoint(PathChartPoint sourcePoint, float distanceShift) { HeightM = sourcePoint.HeightM; DistanceAlongPath = sourcePoint.DistanceAlongPath + distanceShift; Curvature = sourcePoint.Curvature; DistanceAlongNextSection = sourcePoint.DistanceAlongNextSection; GradePercent = sourcePoint.GradePercent; TrackItemText = sourcePoint.TrackItemText; TrackItemType = sourcePoint.TrackItemType; }
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> /// Add a point to the list and update all Min/Max values /// </summary> private void AddPoint(List <PathChartPoint> localPathChartPoints, PathChartPoint newPoint) { this.MinDistanceAlongPath = Math.Min(this.MinDistanceAlongPath, newPoint.DistanceAlongPath); this.MaxDistanceAlongPath = Math.Max(this.MaxDistanceAlongPath, newPoint.DistanceAlongPath); this.MinHeightM = Math.Min(this.MinHeightM, newPoint.HeightM); this.MaxHeightM = Math.Max(this.MaxHeightM, newPoint.HeightM); this.MinGradePercent = Math.Min(this.MinGradePercent, newPoint.GradePercent); this.MaxGradePercent = Math.Max(this.MaxGradePercent, newPoint.GradePercent); this.MinCurvature = Math.Min(this.MinCurvature, newPoint.Curvature); this.MaxCurvature = Math.Max(this.MaxCurvature, newPoint.Curvature); localPathChartPoints.Add(newPoint); }
/// <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); }
/// <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); }
/// <summary> /// Return whether the source point is within the zoomrange /// </summary> /// <param name="sourcePoint">The point for which to determine whether it is in the zoomRange</param> /// <returns></returns> protected bool InZoomRange(PathChartPoint sourcePoint) { return(sourcePoint.DistanceAlongPath >= this.zoomedMinX && sourcePoint.DistanceAlongPath <= this.zoomedMaxX); }