public static bool UseSuperElevationDyn(Viewer viewer, List <DynamicTrackViewer> dTrackList, DyntrackObj dTrackObj, WorldPosition worldMatrixInput) { bool withCurves = false; for (int iTkSection = 0; iTkSection < dTrackObj.trackSections.Count; iTkSection++) { float length = 0; length = dTrackObj.trackSections[iTkSection].param1; // meters if straight; radians if curved if (length == 0.0) { continue; // Consider zero-length subsections vacuous } // Create new DT object copy; has only one meaningful subsection DyntrackObj subsection = new DyntrackObj(dTrackObj, iTkSection); // Straight or curved subsection? if (subsection.trackSections[0].isCurved == 0) // Straight section { // Heading stays the same; translation changes in the direction oriented } else // Curved section { // Both heading and translation change //if (Math.Abs(radius * length) < Program.Simulator.SuperElevationMinLen) return false; withCurves = true; } } return(withCurves); //if no curve, will not draw using super elevation }
/// <summary> /// Decompose and add a SuperElevation on top of MSTS track section /// </summary> /// <param name="viewer">Viewer reference.</param> /// <param name="dTrackList">DynamicTrackViewer list.</param> /// <param name="dTrackObj">Dynamic track section to decompose.</param> /// <param name="worldMatrixInput">Position matrix.</param> public static void DecomposeDynamicSuperElevation(Viewer viewer, List <DynamicTrackViewer> dTrackList, DyntrackObj dTrackObj, WorldPosition worldMatrixInput) { // DYNAMIC TRACK // ============= // Objectives: // 1-Decompose multi-subsection DT into individual sections. // 2-Create updated transformation objects (instances of WorldPosition) to reflect // root of next subsection. // 3-Distribute elevation change for total section through subsections. (ABANDONED) // 4-For each meaningful subsection of dtrack, build a separate SuperElevationPrimitive. // // Method: Iterate through each subsection, updating WorldPosition for the root of // each subsection. The rotation component changes only in heading. The translation // component steps along the path to reflect the root of each subsection. // The following vectors represent local positioning relative to root of original (5-part) section: Vector3 localV = Vector3.Zero; // Local position (in x-z plane) Vector3 localProjectedV; // Local next position (in x-z plane) Vector3 displacement; // Local displacement (from y=0 plane) Vector3 heading = Vector3.Forward; // Local heading (unit vector) WorldPosition worldMatrix = new WorldPosition(worldMatrixInput); // Make a copy so it will not be messed WorldPosition nextRoot = new WorldPosition(worldMatrix); // Will become initial root Vector3 sectionOrigin = worldMatrix.XNAMatrix.Translation; // Save root position worldMatrix.XNAMatrix.Translation = Vector3.Zero; // worldMatrix now rotation-only // Iterate through all subsections int count = -1; for (int iTkSection = 0; iTkSection < dTrackObj.trackSections.Count; iTkSection++) { count++; float length = 0, radius = -1; length = dTrackObj.trackSections[iTkSection].param1; // meters if straight; radians if curved if (length == 0.0) { continue; // Consider zero-length subsections vacuous } // Create new DT object copy; has only one meaningful subsection DyntrackObj subsection = new DyntrackObj(dTrackObj, iTkSection); // Create a new WorldPosition for this subsection, initialized to nextRoot, // which is the WorldPosition for the end of the last subsection. // In other words, beginning of present subsection is end of previous subsection. WorldPosition root = new WorldPosition(nextRoot); // Now we need to compute the position of the end (nextRoot) of this subsection, // which will become root for the next subsection. // Clear nextRoot's translation vector so that nextRoot matrix contains rotation only nextRoot.XNAMatrix.Translation = Vector3.Zero; // Straight or curved subsection? if (subsection.trackSections[0].isCurved == 0) // Straight section { // Heading stays the same; translation changes in the direction oriented // Rotate Vector3.Forward to orient the displacement vector localProjectedV = localV + length * heading; displacement = Traveller.MSTSInterpolateAlongStraight(localV, heading, length, worldMatrix.XNAMatrix, out localProjectedV); } else // Curved section { // Both heading and translation change // nextRoot is found by moving from Point-of-Curve (PC) to // center (O)to Point-of-Tangent (PT). radius = subsection.trackSections[0].param2; // meters Vector3 left = radius * Vector3.Cross(Vector3.Up, heading) * Math.Sign(-subsection.trackSections[0].param1); // Vector from PC to O Matrix rot = Matrix.CreateRotationY(-length); // Heading change (rotation about O) // Shared method returns displacement from present world position and, by reference, // local position in x-z plane of end of this section displacement = Traveller.MSTSInterpolateAlongCurve(localV, left, rot, worldMatrix.XNAMatrix, out localProjectedV); heading = Vector3.Transform(heading, rot); // Heading change nextRoot.XNAMatrix = rot * nextRoot.XNAMatrix; // Store heading change } // Update nextRoot with new translation component nextRoot.XNAMatrix.Translation = sectionOrigin + displacement; sv = ev = mv = 0f; // if (section.SectionCurve != null) FindSectionValue(shape, root, nextRoot, viewer.Simulator, section, TileX, TileZ, dTrackObj.UID); //nextRoot.XNAMatrix.Translation += Vector3.Transform(trackLoc, worldMatrix.XNAMatrix); dTrackList.Add(new SuperElevationViewer(viewer, root, nextRoot, radius, length, sv, ev, mv, dir)); localV = localProjectedV; // Next subsection } }