예제 #1
0
        /// <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>();
            TrackVectorNode           vectorNode     = tn as TrackVectorNode;

            if (vectorNode?.TrackItemIndices == null)
            {
                return(tracknodeItems);
            }

            foreach (int trackItemIndex in vectorNode.TrackItemIndices)
            {
                TrackItem trItem = trackDB.TrackItems[trackItemIndex];
                if (trItem is PlatformItem || trItem is SpeedPostItem)
                {
                    var travellerAtItem = new Traveller(tsectionDat, trackDB.TrackNodes, vectorNode, trItem.Location, Traveller.TravellerDirection.Forward);

                    if (travellerAtItem != null)
                    {
                        tracknodeItems.Add(new ChartableTrackItem(trItem, travellerAtItem));
                    }
                }
            }
            tracknodeItems.Sort(new AlongTrackComparer());
            cachedItems[tn] = tracknodeItems;
            return(tracknodeItems);
        }
예제 #2
0
        /// <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
                {
                    TrackVectorNode tvn = tn as TrackVectorNode;
                    tvsiStart          = tvn.TrackVectorSections.Length - 1;
                    sectionOffsetStart = SectionLengthAlongTrack(tvn, tvsiStart);
                }
            }
            else
            {   // we start at a vector node
                isForward          = currentNodeAsVector.IsEarlierOnTrackThan(nextNode);
                tvsiStart          = currentNodeAsVector.TrackVectorSectionIndex;
                sectionOffsetStart = currentNodeAsVector.TrackSectionOffset;
            }
        }
예제 #3
0
        /// <summary>
        /// Draw (possibly part of) the track of a MSTS vectorNode (from track database)
        /// </summary>
        /// <param name="drawArea">Area to draw upon</param>
        /// <param name="trackVectorNode">The tracknode from track database (assumed to be a vector node)</param>
        /// <param name="colors">Colorscheme to use</param>
        /// <param name="tvsiStart">Index of first track vector section to draw (at least partially)</param>
        /// <param name="tvsiStop">Index of last track vector section to draw (at least partially)</param>
        /// <param name="sectionOffsetStart">start-offset in the first track section to draw</param>
        /// <param name="sectionOffsetStop">stop-offset in the last track section to draw</param>
        /// <remarks>Very similar to DrawVectorNode in class DrawTrackDB, but this one allows to draw partial vector nodes.</remarks>
        private void DrawVectorNode(DrawArea drawArea, TrackVectorNode trackVectorNode, ColorScheme colors, int tvsiStart, int tvsiStop,
                                    float sectionOffsetStart, float sectionOffsetStop)
        {
            TrackVectorSection tvs;

            if (tvsiStart == tvsiStop)
            {
                tvs = trackVectorNode.TrackVectorSections[tvsiStart];
                DrawTrackSection(drawArea, tvs, colors, sectionOffsetStart, sectionOffsetStop);
            }
            else
            {
                // first section
                tvs = trackVectorNode.TrackVectorSections[tvsiStart];
                DrawTrackSection(drawArea, tvs, colors, sectionOffsetStart, -1);

                // all intermediate sections
                for (int tvsi = tvsiStart + 1; tvsi <= tvsiStop - 1; tvsi++)
                {
                    tvs = trackVectorNode.TrackVectorSections[tvsi];
                    DrawTrackSection(drawArea, tvs, colors, 0, -1);
                }

                // last section
                tvs = trackVectorNode.TrackVectorSections[tvsiStop];
                DrawTrackSection(drawArea, tvs, colors, 0, sectionOffsetStop);
            }
        }
예제 #4
0
        /// <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="sectionOffsetEnd">Offset of the end of this section (in forward direction of track, not of path)</param>
        private void AddPointAndTrackItems(List <PathChartPoint> newPoints, TrackVectorNode 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.TrackVectorSections[tvsi].Direction.X * (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);
        }
예제 #5
0
        /// <summary>
        /// Find the angle that the signal needs to be drawn at
        /// </summary>
        /// <param name="tsectionDat">Database with track sections</param>
        /// <param name="trackDB">Database with tracks</param>
        /// <param name="tn">TrackNode on which the signal actually is</param>
        public void FindAngle(TrackSectionsFile tsectionDat, TrackDB trackDB, TrackVectorNode tn)
        {
            this.angle = 0;
            try
            {
                Traveller signalTraveller = new Traveller(tsectionDat, trackDB.TrackNodes, tn, WorldLocation, this.direction);
                this.angle = signalTraveller.RotY;

                // Shift signal a little bit to be able to distinguish backfacing from normal facing
                Microsoft.Xna.Framework.Vector3 shiftedLocation = this.WorldLocation.Location +
                                                                  0.0001f * new Microsoft.Xna.Framework.Vector3((float)Math.Cos(this.angle), 0f, -(float)Math.Sin(this.angle));
                this.WorldLocation = new WorldLocation(this.WorldLocation.TileX, this.WorldLocation.TileZ, shiftedLocation);
            }
            catch { }
        }
예제 #6
0
        /// <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);
        }
예제 #7
0
        /// <summary>
        /// constructor based on a nodeCandidate: a TrainpathVectorNode based on mouse location, does not contain all information
        /// </summary>
        /// <param name="nodeCandidate"></param>
        public TrainpathVectorNode(TrainpathVectorNode nodeCandidate)
            : base(nodeCandidate)
        {
            TvnIndex = nodeCandidate.TvnIndex;
            TrackVectorSectionIndex = nodeCandidate.TrackVectorSectionIndex;
            TrackSectionOffset      = nodeCandidate.TrackSectionOffset;
            NextMainTvnIndex        = nodeCandidate.TvnIndex;
            Location = nodeCandidate.Location;

            ForwardOriented = true; // only initial setting

            TrackVectorNode tn        = TrackDB.TrackNodes[TvnIndex] as TrackVectorNode;
            Traveller       traveller = new Traveller(TsectionDat, TrackDB.TrackNodes, tn, Location, Traveller.TravellerDirection.Forward);

            CopyDataFromTraveller(traveller);
            trackAngleForward = traveller.RotY; // traveller also has TvnIndex, tvs, offset, etc, but we are not using that (should be consistent though)
        }
예제 #8
0
        /// <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);
        }
예제 #9
0
 /// <summary>
 /// Place a traveller at the junction node location, but on a track leaving it.
 /// </summary>
 /// <param name="linkingTvnIndex">The index of the track leaving it</param>
 /// <returns>The traveller, with direction leaving this node.</returns>
 public Traveller PlaceTravellerAfterJunction(int linkingTvnIndex)
 {
     // it is a junction. Place a traveller onto the tracknode and find the orientation from it.
     try
     {   //for broken paths the tracknode doesn't exit or the traveller cannot be placed.
         TrackVectorNode linkingTN = TrackDB.TrackNodes[linkingTvnIndex] as TrackVectorNode;
         Traveller       traveller = new Traveller(TsectionDat, TrackDB.TrackNodes, linkingTN, Location, Traveller.TravellerDirection.Forward);
         if (linkingTN.JunctionIndexAtStart() != this.JunctionIndex)
         {   // the tracknode is oriented in the other direction.
             traveller.ReverseDirection();
         }
         return(traveller);
     }
     catch
     {
         return(null);
     }
 }
예제 #10
0
        private List <string> StationNamesBetweenNodes(TrainpathNode firstNode, TrainpathNode secondNode)
        {
            var stationNames = new List <string>();
            int tvnIndex     = firstNode.NextMainTvnIndex;

            if (tvnIndex < 0)
            {
                return(stationNames);
            }

            TrackVectorNode tvn = trackDB.TrackNodes[tvnIndex] as TrackVectorNode;

            if (tvn == null)
            {
                return(stationNames);
            }
            if (tvn.TrackItemIndices == null)
            {
                return(stationNames);
            }

            foreach (int trackItemIndex in tvn.TrackItemIndices)
            {
                TrackItem trItem = trackDB.TrackItems[trackItemIndex];
                if (trItem is PlatformItem)
                {
                    var traveller = new Traveller(tsectionDat, trackDB.TrackNodes, tvn, trItem.Location, 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);
        }
예제 #11
0
        /// <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);
        }
예제 #12
0
        //check TDB for long curves and determine each section's position/elev in the curve
        public SuperElevation(Simulator simulator)
        {
            if (null == simulator)
            {
                throw new ArgumentNullException(nameof(simulator));
            }

            Curves   = new List <List <TrackVectorSection> >();
            Sections = new Dictionary <int, List <TrackVectorSection> >();

            MaximumAllowedM = 0.07f + simulator.Settings.UseSuperElevation / 100f;//max allowed elevation controlled by user setting

            List <TrackVectorSection> SectionList = new List <TrackVectorSection>();

            foreach (TrackNode node in simulator.TrackDatabase.TrackDB.TrackNodes)
            {
                TrackVectorNode trackVectorNode = node as TrackVectorNode;
                if (trackVectorNode == null)
                {
                    continue;
                }
                bool  StartCurve = false;
                int   CurveDir   = 0;
                float Len        = 0.0f;
                SectionList.Clear();
                int i     = 0;
                int count = trackVectorNode.TrackVectorSections.Length;
                foreach (TrackVectorSection section in trackVectorNode.TrackVectorSections)//loop all curves
                {
                    i++;
                    TrackSection sec = simulator.TSectionDat.TrackSections.Get(section.SectionIndex);
                    if (sec == null)
                    {
                        continue;
                    }
                    if (Math.Abs(sec.Width - (simulator.Settings.SuperElevationGauge / 1000f)) > 0.2)
                    {
                        continue;//the main route has a gauge different than mine
                    }
                    float angle = sec.Angle;
                    if (sec.Curved && !angle.AlmostEqual(0f, 0.01f)) //a good curve
                    {
                        if (i == 1 || i == count)
                        {
                            //if (theCurve.Radius * (float)Math.Abs(theCurve.Angle * 0.0174) < 15f) continue;
                        } //do not want the first and last piece of short curved track to be in the curve (they connected to switches)
                        if (!StartCurve) //we are beginning a curve
                        {
                            StartCurve = true;
                            CurveDir   = Math.Sign(sec.Angle);
                            Len        = 0f;
                        }
                        else if (CurveDir != Math.Sign(sec.Angle))     //we are in curve, but bending different dir
                        {
                            MarkSections(simulator, SectionList, Len); //treat the sections encountered so far, then restart with other dir
                            CurveDir = Math.Sign(sec.Angle);
                            SectionList.Clear();
                            Len = 0f; //StartCurve remains true as we are still in a curve
                        }
                        Len += sec.Radius * (float)Math.Abs(MathHelper.ToRadians(sec.Angle));
                        SectionList.Add(section);
                    }
                    else //meet a straight line
                    {
                        if (StartCurve) //we are in a curve, need to finish
                        {
                            MarkSections(simulator, SectionList, Len);
                            Len = 0f;
                            SectionList.Clear();
                        }
                        StartCurve = false;
                    }
                }
                if (StartCurve) // we are in a curve after looking at every section
                {
                    MarkSections(simulator, SectionList, Len);
                }
                SectionList.Clear();
            }
        }
예제 #13
0
 public TrackEndSegment(TrackEndNode trackEndNode, TrackVectorNode connectedVectorNode, TrackSections sections)
 {
     ref readonly WorldLocation location = ref trackEndNode.UiD.Location;
예제 #14
0
        /// <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];

            TrackVectorNode vectorNode            = tn as TrackVectorNode;
            var             trackItemsInTracknode = trackItems.GetItemsInTracknode(tn);


            DetermineSectionDetails(thisNode, nextNode, tn, out bool isForward, out int tvsiStart, out float sectionOffsetStart);
            DetermineSectionDetails(nextNode, thisNode, tn, out bool isReverse, out int tvsiStop, out float 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.TrackVectorSections[tvsi].Location.Location.Y;
                    AddPointAndTrackItems(newPoints, vectorNode, trackItemsInTracknode, isForward, height, tvsi, 0, sectionOffsetNext);

                    sectionOffsetNext = SectionLengthAlongTrack(vectorNode, 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.TrackVectorSections[tvsi + 1].Location.Location.Y;
                    AddPointAndTrackItems(newPoints, vectorNode, trackItemsInTracknode, isForward, height, tvsi, sectionOffsetNext, SectionLengthAlongTrack(vectorNode, 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);
        }
예제 #15
0
        /// <summary>
        /// Draw a path on a vector node, meaning that the vector node will be drawn (possibly partly), in path colors
        /// </summary>
        /// <param name="drawArea">Area to draw upon</param>
        /// <param name="colors">Colorscheme to use</param>
        /// <param name="currentNode">Current path node</param>
        /// <param name="nextNode">Next path Node</param>
        /// <param name="TvnIndex">The index of the track vector node that is between the two path nodes</param>
        /// <remarks>Note that it is not clear yet whether the direction of current to next is the same as the
        /// direction of the vector node</remarks>
        private void DrawPathOnVectorNode(DrawArea drawArea, ColorScheme colors, TrainpathNode currentNode, TrainpathNode nextNode, int TvnIndex)
        {
            if (currentNode.IsBrokenOffTrack || nextNode.IsBrokenOffTrack || (TvnIndex == -1))
            {
                DrawPathBrokenNode(drawArea, colors, currentNode, nextNode);
                return;
            }
            TrackVectorNode tvn = trackDB.TrackNodes[TvnIndex] as TrackVectorNode;

            TrainpathJunctionNode nextJunctionNode = nextNode as TrainpathJunctionNode;
            TrainpathVectorNode   nextVectorNode   = nextNode as TrainpathVectorNode;

            //Default situation (and most occuring) is to draw the complete vector node
            int   tvsiStart          = 0;
            int   tvsiStop           = tvn.TrackVectorSections.Length - 1;
            float sectionOffsetStart = 0;
            float sectionOffsetStop  = -1;

            if (currentNode is TrainpathJunctionNode)
            {
                // If both ends are junctions, just draw the full track. Otherwise:
                if (nextVectorNode != null)
                {
                    // Draw from the current junction node to the next mid-point node
                    if (nextVectorNode.IsEarlierOnTrackThan(currentNode))
                    {   // trackvectornode is oriented the other way as path
                        tvsiStart          = nextVectorNode.TrackVectorSectionIndex;
                        sectionOffsetStart = nextVectorNode.TrackSectionOffset;
                    }
                    else
                    {
                        // trackvectornode is oriented in the same way as path
                        tvsiStop          = nextVectorNode.TrackVectorSectionIndex;
                        sectionOffsetStop = nextVectorNode.TrackSectionOffset;
                    }
                }
            }
            else
            {
                TrainpathVectorNode currentVectorNode = currentNode as TrainpathVectorNode;
                if (nextJunctionNode != null)
                {
                    // Draw from current mid-point node to next junction node
                    if (currentVectorNode.IsEarlierOnTrackThan(nextNode))
                    {   // trackvectornode is oriented in the same way as path
                        tvsiStart          = currentVectorNode.TrackVectorSectionIndex;
                        sectionOffsetStart = currentVectorNode.TrackSectionOffset;
                    }
                    else
                    {   // trackvectornode is oriented the other way around.
                        tvsiStop          = currentVectorNode.TrackVectorSectionIndex;
                        sectionOffsetStop = currentVectorNode.TrackSectionOffset;
                    }
                }
                if (nextVectorNode != null)
                {
                    // Draw from a current vector node to the next vector node, e.g. for multiple wait points
                    if (currentVectorNode.IsEarlierOnTrackThan(nextVectorNode))
                    {   // from current to next is in the direction of the vector node
                        tvsiStart          = currentVectorNode.TrackVectorSectionIndex;
                        tvsiStop           = nextVectorNode.TrackVectorSectionIndex;
                        sectionOffsetStart = currentVectorNode.TrackSectionOffset;
                        sectionOffsetStop  = nextVectorNode.TrackSectionOffset;
                    }
                    else
                    {   // from next to current is in the direction of the vector node
                        tvsiStart          = nextVectorNode.TrackVectorSectionIndex;
                        tvsiStop           = currentVectorNode.TrackVectorSectionIndex;
                        sectionOffsetStart = nextVectorNode.TrackSectionOffset;
                        sectionOffsetStop  = currentVectorNode.TrackSectionOffset;
                    }
                }
            }
            DrawVectorNode(drawArea, tvn, colors, tvsiStart, tvsiStop, sectionOffsetStart, sectionOffsetStop);
        }
예제 #16
0
        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));
        }