public override void Trigger(int direction, TrackFollower trackFollower) { AbstractTrain train = trackFollower.Train; EventTriggerType triggerType = trackFollower.TriggerType; if (triggerType == EventTriggerType.FrontCarFrontAxle && train.IsPlayerTrain || triggerType == EventTriggerType.Camera && currentHost.Application == HostApplication.RouteViewer) { if (message != null && train != null) { if (direction < 0) { message.QueueForRemoval = true; } else if (direction > 0) { if (message.Trains != null && !message.Trains.Contains(new System.IO.DirectoryInfo(train.TrainFolder).Name)) { //Our train is NOT in the list of trains which this message triggers for return; } currentHost.AddMessage(message); } } } }
// check events private static void CheckEvents(ref TrackFollower Follower, int ElementIndex, int Direction, double OldDelta, double NewDelta) { if (Direction < 0) { for (int j = 0; j < CurrentTrack.Elements[ElementIndex].Events.Length; j++) { dynamic e = CurrentTrack.Elements[ElementIndex].Events[j]; if (OldDelta > e.TrackPositionDelta & NewDelta <= e.TrackPositionDelta) { e.TryTrigger(-1, Follower.TriggerType, Follower.Train, Follower.CarIndex); } } } else if (Direction > 0) { for (int j = 0; j < CurrentTrack.Elements[ElementIndex].Events.Length; j++) { dynamic e = CurrentTrack.Elements[ElementIndex].Events[j]; if (OldDelta < e.TrackPositionDelta & NewDelta >= e.TrackPositionDelta) { e.TryTrigger(1, Follower.TriggerType, Follower.Train, Follower.CarIndex); } } } }
public override void Trigger(int direction, TrackFollower trackFollower) { if (trackFollower.TriggerType == EventTriggerType.FrontCarFrontAxle) { RequestStop stop; //Temp probability value if (early.Time != -1 && currentRoute.SecondsSinceMidnight < early.Time) { stop = early; } else if (early.Time != -1 && currentRoute.SecondsSinceMidnight > early.Time && late.Time != -1 && currentRoute.SecondsSinceMidnight < late.Time) { stop = onTime; } else if (late.Time != -1 && currentRoute.SecondsSinceMidnight > late.Time) { stop = late; } else { stop = onTime; } stop.MaxCars = maxCars; stop.StationIndex = stationIndex; stop.FullSpeed = fullSpeed; if (direction > 0) { trackFollower.Train.RequestStop(stop); } } }
/// <summary>Triggers a change in run and flange sounds</summary> /// <param name="direction">The direction of travel- 1 for forwards, and -1 for backwards</param> /// <param name="trackFollower">The TrackFollower</param> public override void Trigger(int direction, TrackFollower trackFollower) { AbstractCar car = trackFollower.Car; switch (trackFollower.TriggerType) { case EventTriggerType.FrontCarFrontAxle: case EventTriggerType.OtherCarFrontAxle: if (direction < 0) { car.FrontAxle.RunIndex = PreviousRunIndex; car.FrontAxle.FlangeIndex = PreviousFlangeIndex; } else if (direction > 0) { car.FrontAxle.RunIndex = NextRunIndex; car.FrontAxle.FlangeIndex = NextFlangeIndex; } break; case EventTriggerType.RearCarRearAxle: case EventTriggerType.OtherCarRearAxle: if (direction < 0) { car.RearAxle.RunIndex = PreviousRunIndex; car.RearAxle.FlangeIndex = PreviousFlangeIndex; } else if (direction > 0) { car.RearAxle.RunIndex = NextRunIndex; car.RearAxle.FlangeIndex = NextFlangeIndex; } break; } }
/// <summary>This method is called to attempt to trigger an event</summary> /// <param name="direction">The direction: /// 1 - Forwards /// -1 - Reverse</param> /// <param name="trackFollower">The TrackFollower</param> public void TryTrigger(int direction, TrackFollower trackFollower) { if (!DontTriggerAnymore) { Trigger(direction, trackFollower); } }
private void PushConsistSpeedLimit(TrainCar loco) { var length = loco.trainset.OverallLength(); var lastCar = TrainsetUtils.CarAtEnd(loco, loco.GetComponent <LocoControllerBase>().reverser < 0); var bogie = lastCar.Bogies[0]; if (bogie.track == null) { return; } var startLimit = TrackFollower.GetSpeedLimit(bogie.track, bogie.traveller.Span, bogie.trackDirection >= 0) ?? 0f; var intraTrainLimits = TrackFollower.FollowTrack(bogie.track, bogie.traveller.Span, bogie.trackDirection * length) .ResolveJunctionSpeedLimits() .TakeWhile(ev => ev.span < length) .OfType <SpeedLimitEvent>() .Select(ev => ev.limit); var limits = (startLimit > 0f ? intraTrainLimits.Prepend((int)startLimit) : intraTrainLimits).ToArray(); Main.DebugLog($"limits affecting train: {string.Join(",", limits)}"); if (limits.Length > 0) { tablet !.SetSpeedMax(limits.Last()); tablet !.SetSpeedLimitConsist(limits.Min()); } }
/// <summary>Creates a new axle</summary> public Axle(Hosts.HostInterface currentHost, AbstractTrain Train, AbstractCar Car, double CoefficientOfFriction = 0.35, double CoefficentOfRollingResistance = 0.0025, double AerodynamicDragCoefficient = 1.1) { Follower = new TrackFollower(currentHost, Train, Car); baseCar = Car; coefficientOfFriction = CoefficientOfFriction; coefficientOfRollingResistance = CoefficentOfRollingResistance; aerodynamicDragCoefficient = AerodynamicDragCoefficient; }
public override void Trigger(int direction, TrackFollower trackFollower) { trackFollower.EnterStation(StationIndex, direction); if (trackFollower.TriggerType == EventTriggerType.TrainFront) { trackFollower.Train.EnterStation(StationIndex, direction); } }
private void PushEvents(TrainCar loco) { var bogie = loco.Bogies[1]; if (bogie.track == null) { return; } var direction = bogie.trackDirection; if (loco.GetComponent <LocoControllerBase>().reverser < 0) { direction *= -1; } var prevGradeEvent = TrackFollower.GetGrade(bogie.track, bogie.traveller.Span, direction >= 0); var events = TrackFollower.FollowTrack(bogie.track, bogie.traveller.Span, direction * double.PositiveInfinity) .ResolveJunctionSpeedLimits() .FilterRedundantSpeedLimits() .FilterGradeEvents(prevGradeEvent?.grade ?? 0f) .TakeWhile(ev => ev.span < Main.settings.trackInfoSettings.maxEventSpan) .ToArray(); var speedEvents = events.OfType <SpeedLimitEvent>().Select(ev => ((float)ev.span, (float)ev.limit)).ToArray(); tablet !.SetTrackSpeedItems(speedEvents); var gradeEvents = prevGradeEvent != null ? events.OfType <GradeEvent>().Prepend(new GradeEvent(-prevGradeEvent.span, true, prevGradeEvent.grade)) : events.OfType <GradeEvent>(); Main.DebugLog($"relevant grade events: {string.Join(",", gradeEvents)}"); var gradeItems = gradeEvents .Zip( gradeEvents.Skip(1), (a, b) => ((float)a.span, a.grade * 10, (float)(b.span - a.span))) .Where(item => (int)item.Item2 != 0); Main.DebugLog($"setting grade items: {string.Join(",", gradeItems)}"); tablet.SetTrackGradeItems(gradeItems); var nextJunction = events.OfType <JunctionEvent>().Select(ev => ev.junction).FirstOrDefault(); if (nextJunction != default) { tablet.SetNextJunction(nextJunction); tablet.SetNextWyeDir(nextJunction.selectedBranch == 0 ? 1 : -1); } else { tablet.SetNextWyeDir(0); } }
public override void Trigger(int direction, TrackFollower trackFollower) { if (trackFollower.TriggerType == EventTriggerType.FrontCarFrontAxle) { if (direction > 0) //FIXME: This only works for routes written in the forwards direction { dynamic t = trackFollower.Train; t.SafetySystems.PassAlarm.Trigger(); DontTriggerAnymore = true; } } }
/// <summary>Triggers the playback of a sound</summary> /// <param name="direction">The direction of travel- 1 for forwards, and -1 for backwards</param> /// <param name="trackFollower">The TrackFollower</param> public override void Trigger(int direction, TrackFollower trackFollower) { if (SoundsBase.SuppressSoundEvents) { return; } EventTriggerType triggerType = trackFollower.TriggerType; if (triggerType == EventTriggerType.FrontCarFrontAxle | triggerType == EventTriggerType.OtherCarFrontAxle | triggerType == EventTriggerType.OtherCarRearAxle | triggerType == EventTriggerType.RearCarRearAxle) { if (!PlayerTrainOnly | trackFollower.Train.IsPlayerTrain) { if (AllCars && triggerType == EventTriggerType.OtherCarRearAxle) { /* * For a multi-car announce, we only want the front axles to trigger * However, we also want the rear car, rear axle to run the final processing of DontTriggerAnymore */ return; } double pitch = 1.0; double gain = 1.0; //In order to play for all cars, we need to create a clone of the buffer, as 1 buffer can only be playing in a single location SoundBuffer buffer = this.AllCars ? SoundBuffer.Clone() : SoundBuffer; if (buffer != null) { if (this.Dynamic) { double spd = Math.Abs(trackFollower.Train.CurrentSpeed); pitch = spd / this.Speed; gain = pitch < 0.5 ? 2.0 * pitch : 1.0; if (pitch < 0.2 | gain < 0.2) { buffer = null; } } if (buffer != null) { if (AllCars || triggerType != EventTriggerType.RearCarRearAxle) { currentHost.PlaySound(buffer, pitch, gain, Position, trackFollower.Car, false); } } } if (!AllCars || triggerType == EventTriggerType.RearCarRearAxle) { this.DontTriggerAnymore = this.Once; } } } }
/// <summary>Clones the TrackFollower</summary> public TrackFollower Clone() { // TrackFollower t = new TrackFollower(currentHost, Train, Car); TrackFollower t = new TrackFollower(); t.LastTrackElement = LastTrackElement; t.TrackPosition = TrackPosition; t.WorldPosition = new Vector3(WorldPosition); t.WorldDirection = new Vector3(WorldDirection); t.WorldUp = new Vector3(WorldUp); t.WorldSide = new Vector3(WorldSide); // t.TriggerType = TriggerType; t.TrackIndex = TrackIndex; return(t); }
public override void Trigger(int direction, TrackFollower trackFollower) { if (trackFollower.TriggerType == EventTriggerType.Camera) { if (direction < 0) { currentRoute.TargetBackground = previousBackground; currentRoute.TargetBackground.Countdown = 0; } else if (direction > 0) { currentRoute.TargetBackground = nextBackground; currentRoute.TargetBackground.Countdown = 0; } } }
public override void Trigger(int direction, TrackFollower trackFollower) { if (trackFollower.TriggerType == EventTriggerType.Camera) { if (direction < 0) { currentRoute.PreviousFog = PreviousFog; currentRoute.NextFog = CurrentFog; } else if (direction > 0) { currentRoute.PreviousFog = CurrentFog; currentRoute.NextFog = NextFog; } } }
private static void DrawConsistSpeedLimit() { if (Instance == null) { return; } if (sortedTrainSet == null) { return; } scanCar = scanDir > 0 ? sortedTrainSet.cars.Last().trainCar : sortedTrainSet.cars.First().trainCar; scanBogie = scanCar.Bogies[(sortedTrainSet[scanCar].forward == (scanDir > 0)) ? 0 : scanCar.Bogies.Length - 1]; var track = scanBogie.track; if (track == null) { return; } var startSpan = scanBogie.traveller.Span; var direction = !(sortedTrainSet[scanCar].forward == (scanDir > 0)) ^ (scanBogie.trackDirection > 0); var currentGrade = TrackIndexer.Grade(scanBogie.point1) * (direction ? 1 : -1); var events = TrackFollower.FollowTrack( track, startSpan, direction ? trainLength : -trainLength); var eventDescriptions = events .ExceptUnnamedTracks() .ResolveJunctionSpeedLimits() .FilterRedundantSpeedLimits() .FilterGradeEvents(currentGrade) .Take(Main.settings.maxEventCount) .TakeWhile(ev => ev.span < trainLength); var speeds = eventDescriptions.Where(e => e is SpeedLimitEvent).Cast <SpeedLimitEvent>().Select(s => ((float)s.span, (float)s.limit)); var limit = (speeds.Count() > 0) ? speeds.Min(s => s.Item2) : 200; limit = Mathf.Min(limit, TrackFollower.GetSpeedLimit(track, startSpan, direction) ?? 0f); Instance.SetSpeedLimitConsist(speedLimitConsist = limit); }
public override void Trigger(int direction, TrackFollower trackFollower) { AbstractTrain train = trackFollower.Train; if (train == null || Type == -1 && train.IsPlayerTrain || Type == 1 && !train.IsPlayerTrain) { return; } if (DontTriggerAnymore) { return; } if (trackFollower.TriggerType == EventTriggerType.TrainFront) { if (direction > 0) { if (NextDestination != -1) { train.Destination = NextDestination; } if (TriggerOnce) { DontTriggerAnymore = true; } } else { if (PreviousDestination != -1) { train.Destination = PreviousDestination; } if (TriggerOnce) { DontTriggerAnymore = true; } } } }
public override void Trigger(int direction, TrackFollower trackFollower) { if (trackFollower.TriggerType == EventTriggerType.TrainFront) { int s = SectionIndex; if (ClipToFirstRedSection) { if (s >= 0) { while (true) { if (currentRoute.Sections[s].Exists(trackFollower.Train)) { s = SectionIndex; break; } int a = currentRoute.Sections[s].CurrentAspect; if (a >= 0) { if (currentRoute.Sections[s].Aspects[a].Number == 0) { break; } } s = Array.IndexOf(currentRoute.Sections, currentRoute.Sections[s].PreviousSection); if (s >= 0) { s = SectionIndex; break; } } } } trackFollower.Train.UpdateBeacon(Type, s, Data); } }
public override void Trigger(int direction, TrackFollower trackFollower) { AbstractTrain train = trackFollower.Train; if (train != null) { switch (trackFollower.TriggerType) { case EventTriggerType.FrontCarFrontAxle: if (direction < 0) { if (NextSectionIndex >= 0) { currentRoute.Sections[NextSectionIndex].TrainReachedStopPoint = false; } UpdateFrontBackward(train); } else if (direction > 0) { UpdateFrontForward(train); } break; case EventTriggerType.RearCarRearAxle: if (direction < 0) { UpdateRearBackward(train); } else if (direction > 0) { if (PreviousSectionIndex >= 0) { currentRoute.Sections[PreviousSectionIndex].TrainReachedStopPoint = false; } UpdateRearForward(train); } break; } } }
public override void Trigger(int direction, TrackFollower trackFollower) { trackFollower.LeaveStation(StationIndex, direction); switch (trackFollower.TriggerType) { case EventTriggerType.FrontCarFrontAxle: if (direction > 0) { if (trackFollower.Train.IsPlayerTrain) { currentHost.UpdateCustomTimetable(currentRoute.Stations[StationIndex].TimetableDaytimeTexture, currentRoute.Stations[StationIndex].TimetableNighttimeTexture); } } break; case EventTriggerType.RearCarRearAxle: trackFollower.Train.LeaveStation(StationIndex, direction); break; } }
public override void Trigger(int direction, TrackFollower trackFollower) { if (trackFollower.TriggerType == EventTriggerType.Camera) { if (direction < 0) { if (previousLightDefinitions != null) { currentRoute.LightDefinitions = previousLightDefinitions; currentRoute.DynamicLighting = true; } else { currentRoute.Atmosphere.AmbientLightColor = previousLightDefinition.AmbientColor; currentRoute.Atmosphere.DiffuseLightColor = previousLightDefinition.DiffuseColor; currentRoute.Atmosphere.LightPosition = previousLightDefinition.LightPosition; currentRoute.UpdateLighting(); currentRoute.DynamicLighting = false; } } else if (direction > 0) { if (nextLightDefinitions != null) { currentRoute.LightDefinitions = nextLightDefinitions; currentRoute.DynamicLighting = true; } else { currentRoute.Atmosphere.AmbientLightColor = nextLightDefinition.AmbientColor; currentRoute.Atmosphere.DiffuseLightColor = nextLightDefinition.DiffuseColor; currentRoute.Atmosphere.LightPosition = nextLightDefinition.LightPosition; currentRoute.UpdateLighting(); currentRoute.DynamicLighting = false; } } } }
public override void Trigger(int direction, TrackFollower trackFollower) { AbstractTrain train = trackFollower.Train; if (train == null) { return; } if (trackFollower.TriggerType == EventTriggerType.RearCarRearAxle & !train.IsPlayerTrain) { train.Dispose(); } else if (train.IsPlayerTrain) { train.Derail(trackFollower.Car, 0.0); } if (trackFollower.TriggerType == EventTriggerType.Camera) { currentHost.CameraAtWorldEnd(); } }
/// <summary>Triggers the playback of a sound</summary> /// <param name="direction">The direction of travel- 1 for forwards, and -1 for backwards</param> /// <param name="trackFollower">The TrackFollower</param> public override void Trigger(int direction, TrackFollower trackFollower) { if (SoundsBase.SuppressSoundEvents) { return; } AbstractCar car = trackFollower.Car; switch (trackFollower.TriggerType) { case EventTriggerType.FrontCarFrontAxle: case EventTriggerType.OtherCarFrontAxle: car.FrontAxle.PointSoundTriggered = true; DontTriggerAnymore = false; break; case EventTriggerType.OtherCarRearAxle: case EventTriggerType.RearCarRearAxle: car.RearAxle.PointSoundTriggered = true; DontTriggerAnymore = false; break; } }
public override void Trigger(int direction, TrackFollower trackFollower) { EventTriggerType triggerType = trackFollower.TriggerType; if (triggerType == EventTriggerType.FrontCarFrontAxle | triggerType == EventTriggerType.OtherCarFrontAxle) { AbstractCar car = trackFollower.Car; if (direction < 0) { car.Brightness.NextBrightness = CurrentBrightness; car.Brightness.NextTrackPosition = car.TrackPosition; car.Brightness.PreviousBrightness = PreviousBrightness; car.Brightness.PreviousTrackPosition = car.TrackPosition - PreviousDistance; } else if (direction > 0) { car.Brightness.PreviousBrightness = CurrentBrightness; car.Brightness.PreviousTrackPosition = car.TrackPosition; car.Brightness.NextBrightness = NextBrightness; car.Brightness.NextTrackPosition = car.TrackPosition + NextDistance; } } }
public override void Trigger(int direction, TrackFollower trackFollower) { EventTriggerType triggerType = trackFollower.TriggerType; if (triggerType == EventTriggerType.FrontCarFrontAxle || triggerType == EventTriggerType.OtherCarFrontAxle) { AbstractCar car = trackFollower.Car; if (DontTriggerAnymore || car == null) { return; } if (car.Index == trackFollower.Train.DriverCar) { dynamic dynamicCar = car; dynamicCar.Horns[(int)Type].Play(); dynamicCar.Horns[(int)Type].Stop(); if (TriggerOnce) { DontTriggerAnymore = true; } } } }
internal static void UpdateTrackFollower(ref TrackFollower Follower, double NewTrackPosition, bool UpdateWorldCoordinates, bool AddTrackInaccurary) { }
private void RenderEvents() { if (Program.CurrentRoute.Tracks[0].Elements == null) { return; } GL.Enable(EnableCap.CullFace); GL.Enable(EnableCap.DepthTest); GL.DepthMask(true); OptionLighting = false; double da = -Camera.BackwardViewingDistance - Camera.ExtraViewingDistance; double db = Camera.ForwardViewingDistance + Camera.ExtraViewingDistance; bool[] sta = new bool[Program.CurrentRoute.Stations.Length]; // events for (int i = 0; i < Program.CurrentRoute.Tracks[0].Elements.Length; i++) { double p = Program.CurrentRoute.Tracks[0].Elements[i].StartingTrackPosition; double d = p - CameraTrackFollower.TrackPosition; if (d >= da & d <= db) { foreach (GeneralEvent e in Program.CurrentRoute.Tracks[0].Elements[i].Events) { double dy, dx = 0.0, dz = 0.0; double s; Texture t; if (e is BrightnessChangeEvent) { s = 0.15; dy = 4.0; t = BrightnessChangeTexture; } else if (e is BackgroundChangeEvent) { s = 0.25; dy = 3.5; t = BackgroundChangeTexture; } else if (e is StationStartEvent) { s = 0.25; dy = 1.6; t = StationStartTexture; StationStartEvent f = (StationStartEvent)e; sta[f.StationIndex] = true; } else if (e is StationEndEvent) { s = 0.25; dy = 1.6; t = StationEndTexture; StationEndEvent f = (StationEndEvent)e; sta[f.StationIndex] = true; } else if (e is LimitChangeEvent) { s = 0.2; dy = 1.1; t = LimitTexture; } else if (e is SectionChangeEvent) { s = 0.2; dy = 0.8; t = SectionTexture; } else if (e is TransponderEvent) { s = 0.15; dy = 0.4; t = TransponderTexture; } else if (e is SoundEvent) { SoundEvent f = (SoundEvent)e; s = 0.2; dx = f.Position.X; dy = f.Position.Y < 0.1 ? 0.1 : f.Position.Y; dz = f.Position.Z; t = f.SoundBuffer == null ? PointSoundTexture : SoundTexture; } else if (e is RailSoundsChangeEvent) { s = 0.2; dy = 0.8; t = RunSoundTexture; } else { s = 0.2; dy = 1.0; t = null; } if (t != null) { TrackFollower f = new TrackFollower(Program.CurrentHost) { TriggerType = EventTriggerType.None, TrackPosition = p }; f.UpdateAbsolute(p + e.TrackPositionDelta, true, false); f.WorldPosition.X += dx * f.WorldSide.X + dy * f.WorldUp.X + dz * f.WorldDirection.X; f.WorldPosition.Y += dx * f.WorldSide.Y + dy * f.WorldUp.Y + dz * f.WorldDirection.Y; f.WorldPosition.Z += dx * f.WorldSide.Z + dy * f.WorldUp.Z + dz * f.WorldDirection.Z; Cube.Draw(f.WorldPosition, f.WorldDirection, f.WorldUp, f.WorldSide, s, Camera.AbsolutePosition, t); } } } } // stops for (int i = 0; i < sta.Length; i++) { if (sta[i]) { for (int j = 0; j < Program.CurrentRoute.Stations[i].Stops.Length; j++) { const double dy = 1.4; const double s = 0.2; double p = Program.CurrentRoute.Stations[i].Stops[j].TrackPosition; TrackFollower f = new TrackFollower(Program.CurrentHost) { TriggerType = EventTriggerType.None, TrackPosition = p }; f.UpdateAbsolute(p, true, false); f.WorldPosition.X += dy * f.WorldUp.X; f.WorldPosition.Y += dy * f.WorldUp.Y; f.WorldPosition.Z += dy * f.WorldUp.Z; Cube.Draw(f.WorldPosition, f.WorldDirection, f.WorldUp, f.WorldSide, s, Camera.AbsolutePosition, StopTexture); } } } // buffers foreach (double p in Program.CurrentRoute.BufferTrackPositions) { double d = p - CameraTrackFollower.TrackPosition; if (d >= da & d <= db) { const double dy = 2.5; const double s = 0.25; TrackFollower f = new TrackFollower(Program.CurrentHost) { TriggerType = EventTriggerType.None, TrackPosition = p }; f.UpdateAbsolute(p, true, false); f.WorldPosition.X += dy * f.WorldUp.X; f.WorldPosition.Y += dy * f.WorldUp.Y; f.WorldPosition.Z += dy * f.WorldUp.Z; Cube.Draw(f.WorldPosition, f.WorldDirection, f.WorldUp, f.WorldSide, s, Camera.AbsolutePosition, BufferTexture); } } OptionLighting = true; }
protected override void TriggerEnterAction(Collider otherCollider) { TrackFollower trackFollower = otherCollider.GetComponent <TrackFollower>(); trackFollower.ChangeSpline(targetSpline); }
// check events private static void CheckEvents(ref TrackFollower Follower, int ElementIndex, int Direction, double OldDelta, double NewDelta) { if (Follower.TriggerType != EventTriggerType.None) { if (Direction < 0) { for (int j = CurrentTrack.Elements[ElementIndex].Events.Length - 1; j >= 0; j--) { if (OldDelta > CurrentTrack.Elements[ElementIndex].Events[j].TrackPositionDelta & NewDelta <= CurrentTrack.Elements[ElementIndex].Events[j].TrackPositionDelta) { TryTriggerEvent(CurrentTrack.Elements[ElementIndex].Events[j], -1, Follower.TriggerType, Follower.Train, Follower.CarIndex); } } } else if (Direction > 0) { for (int j = 0; j < CurrentTrack.Elements[ElementIndex].Events.Length; j++) { if (OldDelta < CurrentTrack.Elements[ElementIndex].Events[j].TrackPositionDelta & NewDelta >= CurrentTrack.Elements[ElementIndex].Events[j].TrackPositionDelta) { TryTriggerEvent(CurrentTrack.Elements[ElementIndex].Events[j], 1, Follower.TriggerType, Follower.Train, Follower.CarIndex); } } } } }
private static void DrawUpcomingEvents() { if (Instance == null) { return; } if (sortedTrainSet == null) { return; } scanCar = scanDir > 0 ? sortedTrainSet.cars.First().trainCar : sortedTrainSet.cars.Last().trainCar; scanBogie = scanCar.Bogies[(sortedTrainSet[scanCar].forward == (scanDir > 0)) ? scanCar.Bogies.Length - 1 : 0]; var track = scanBogie.track; if (track == null) { return; } var startSpan = scanBogie.traveller.Span; var direction = !(sortedTrainSet[scanCar].forward == (scanDir > 0)) ^ (scanBogie.trackDirection > 0); // !(scanDir >= 0f) ^ (scanBogie.trackDirection > 0); var currentGrade = TrackIndexer.Grade(scanBogie.point1) * (direction ? 1 : -1); var scanDistance = Instance.TrackPlannerDisplayDistance + 100; var events = TrackFollower.FollowTrack( track, startSpan, direction ? scanDistance : -scanDistance); var eventDescriptions = events .ExceptUnnamedTracks() .ResolveJunctionSpeedLimits() .FilterRedundantSpeedLimits() .FilterGradeEvents(currentGrade) .Take(Main.settings.maxEventCount) .TakeWhile(ev => ev.span < Main.settings.maxEventSpan); IEnumerable <(float span, float limit)> trackSpeedEvents = eventDescriptions.Where(e => e is SpeedLimitEvent).Cast <SpeedLimitEvent>().Select(s => ((float)s.span, (float)s.limit)); var nextSpeedEvents = trackSpeedEvents.Where(e => e.span < 250); (float span, float limit)nextForSpan = trackSpeedEvents.Aggregate((a, b) => a.span < b.span ? a : b); (float span, float limit)nextForLimit = trackSpeedEvents.Aggregate((a, b) => a.limit < b.limit ? a : b); float lerpVal = Mathf.Clamp01(nextForLimit.span * 0.002f); float maxSpeed = Mathf.Min(Mathf.Lerp(nextForLimit.limit, speedLimitConsist, lerpVal), speedLimitConsist); Instance.SetSpeedMax(maxSpeed); if (nextForSpan.span <= 0.1f) { Instance.SetSpeedLimitNext(currentSpeedLimitNext = nextForSpan.limit); } if (currentSpeedLimitNext > nextForLimit.limit) { Instance.SetSpeedLimitNext(currentSpeedLimitNext = nextForLimit.limit); } Instance.SetTrackSpeedItems(trackSpeedEvents.ToArray()); Instance.SetTrackGradeItems(eventDescriptions.Where(e => e is GradeEvent).Cast <GradeEvent>().Select(s => ((float)s.span, (float)s.grade * 10, -1f)).ToArray()); var junctionEvents = eventDescriptions.Where(e => e is JunctionEvent); Junction?nextJunction = null; if (junctionEvents.Any()) { nextJunction = ((JunctionEvent)junctionEvents.Aggregate((a, b) => a.span < b.span ? a : b)).junction; Instance.SetTrackJunctionItems(junctionEvents.Cast <JunctionEvent>().Select(s => ((float)(s.span - 1.3), (float)0)).ToArray()); } Instance.NextJunction = nextJunction; Instance.SetNextWyeDir((nextJunction == null) ? WyeDirection.NA : (nextJunction.selectedBranch == 0) ? WyeDirection.Left : WyeDirection.Right); }
#pragma warning restore 0649, 1591 /// <summary>Creates a new Track Following Object</summary> /// <param name="Host">The host application</param> public TrackFollowingObject(HostInterface Host) { currentHost = Host; FrontAxleFollower = new TrackFollower(currentHost); RearAxleFollower = new TrackFollower(currentHost); }
// update absolute camera internal static void UpdateAbsoluteCamera(double TimeElapsed) { // zoom double zm = Program.Renderer.Camera.Alignment.Zoom; Program.Renderer.Camera.AdjustAlignment(ref Program.Renderer.Camera.Alignment.Zoom, Program.Renderer.Camera.AlignmentDirection.Zoom, ref Program.Renderer.Camera.AlignmentSpeed.Zoom, TimeElapsed, true, TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].CameraRestriction); if (zm != Program.Renderer.Camera.Alignment.Zoom) { Program.Renderer.Camera.ApplyZoom(); } if (Program.Renderer.Camera.CurrentMode == CameraViewMode.FlyBy | Program.Renderer.Camera.CurrentMode == CameraViewMode.FlyByZooming) { // fly-by Program.Renderer.Camera.AdjustAlignment(ref Program.Renderer.Camera.Alignment.Position.X, Program.Renderer.Camera.AlignmentDirection.Position.X, ref Program.Renderer.Camera.AlignmentSpeed.Position.X, TimeElapsed, false, TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].CameraRestriction); Program.Renderer.Camera.AdjustAlignment(ref Program.Renderer.Camera.Alignment.Position.Y, Program.Renderer.Camera.AlignmentDirection.Position.Y, ref Program.Renderer.Camera.AlignmentSpeed.Position.Y, TimeElapsed, false, TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].CameraRestriction); double tr = Program.Renderer.Camera.Alignment.TrackPosition; Program.Renderer.Camera.AdjustAlignment(ref Program.Renderer.Camera.Alignment.TrackPosition, Program.Renderer.Camera.AlignmentDirection.TrackPosition, ref Program.Renderer.Camera.AlignmentSpeed.TrackPosition, TimeElapsed, false, TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].CameraRestriction); if (tr != Program.Renderer.Camera.Alignment.TrackPosition) { Program.Renderer.CameraTrackFollower.UpdateAbsolute(Program.Renderer.Camera.Alignment.TrackPosition, true, false); Program.Renderer.UpdateViewingDistances(Program.CurrentRoute.CurrentBackground.BackgroundImageDistance); } // position to focus on Vector3 focusPosition = Vector3.Zero; double zoomMultiplier; { const double heightFactor = 0.75; TrainBase bestTrain = null; double bestDistanceSquared = double.MaxValue; TrainBase secondBestTrain = null; double secondBestDistanceSquared = double.MaxValue; foreach (TrainBase train in Program.TrainManager.Trains) { if (train.State == TrainState.Available) { double x = 0.5 * (train.Cars[0].FrontAxle.Follower.WorldPosition.X + train.Cars[0].RearAxle.Follower.WorldPosition.X); double y = 0.5 * (train.Cars[0].FrontAxle.Follower.WorldPosition.Y + train.Cars[0].RearAxle.Follower.WorldPosition.Y) + heightFactor * train.Cars[0].Height; double z = 0.5 * (train.Cars[0].FrontAxle.Follower.WorldPosition.Z + train.Cars[0].RearAxle.Follower.WorldPosition.Z); double dx = x - Program.Renderer.CameraTrackFollower.WorldPosition.X; double dy = y - Program.Renderer.CameraTrackFollower.WorldPosition.Y; double dz = z - Program.Renderer.CameraTrackFollower.WorldPosition.Z; double d = dx * dx + dy * dy + dz * dz; if (d < bestDistanceSquared) { secondBestTrain = bestTrain; secondBestDistanceSquared = bestDistanceSquared; bestTrain = train; bestDistanceSquared = d; } else if (d < secondBestDistanceSquared) { secondBestTrain = train; secondBestDistanceSquared = d; } } } if (bestTrain != null) { const double maxDistance = 100.0; double bestDistance = Math.Sqrt(bestDistanceSquared); double secondBestDistance = Math.Sqrt(secondBestDistanceSquared); if (secondBestTrain != null && secondBestDistance - bestDistance <= maxDistance) { double x1 = 0.5 * (bestTrain.Cars[0].FrontAxle.Follower.WorldPosition.X + bestTrain.Cars[0].RearAxle.Follower.WorldPosition.X); double y1 = 0.5 * (bestTrain.Cars[0].FrontAxle.Follower.WorldPosition.Y + bestTrain.Cars[0].RearAxle.Follower.WorldPosition.Y) + heightFactor * bestTrain.Cars[0].Height; double z1 = 0.5 * (bestTrain.Cars[0].FrontAxle.Follower.WorldPosition.Z + bestTrain.Cars[0].RearAxle.Follower.WorldPosition.Z); double x2 = 0.5 * (secondBestTrain.Cars[0].FrontAxle.Follower.WorldPosition.X + secondBestTrain.Cars[0].RearAxle.Follower.WorldPosition.X); double y2 = 0.5 * (secondBestTrain.Cars[0].FrontAxle.Follower.WorldPosition.Y + secondBestTrain.Cars[0].RearAxle.Follower.WorldPosition.Y) + heightFactor * secondBestTrain.Cars[0].Height; double z2 = 0.5 * (secondBestTrain.Cars[0].FrontAxle.Follower.WorldPosition.Z + secondBestTrain.Cars[0].RearAxle.Follower.WorldPosition.Z); double t = 0.5 - (secondBestDistance - bestDistance) / (2.0 * maxDistance); if (t < 0.0) { t = 0.0; } t = 2.0 * t * t; /* in order to change the shape of the interpolation curve */ focusPosition.X = (1.0 - t) * x1 + t * x2; focusPosition.Y = (1.0 - t) * y1 + t * y2; focusPosition.Z = (1.0 - t) * z1 + t * z2; zoomMultiplier = 1.0 - 2.0 * t; } else { focusPosition.X = 0.5 * (bestTrain.Cars[0].FrontAxle.Follower.WorldPosition.X + bestTrain.Cars[0].RearAxle.Follower.WorldPosition.X); focusPosition.Y = 0.5 * (bestTrain.Cars[0].FrontAxle.Follower.WorldPosition.Y + bestTrain.Cars[0].RearAxle.Follower.WorldPosition.Y) + heightFactor * bestTrain.Cars[0].Height; focusPosition.Z = 0.5 * (bestTrain.Cars[0].FrontAxle.Follower.WorldPosition.Z + bestTrain.Cars[0].RearAxle.Follower.WorldPosition.Z); zoomMultiplier = 1.0; } } else { zoomMultiplier = 1.0; } } // camera { Program.Renderer.Camera.AbsoluteDirection = new Vector3(Program.Renderer.CameraTrackFollower.WorldDirection); Program.Renderer.Camera.AbsolutePosition = Program.Renderer.CameraTrackFollower.WorldPosition + Program.Renderer.CameraTrackFollower.WorldSide * Program.Renderer.Camera.Alignment.Position.X + Program.Renderer.CameraTrackFollower.WorldUp * Program.Renderer.Camera.Alignment.Position.Y + Program.Renderer.Camera.AbsoluteDirection * Program.Renderer.Camera.Alignment.Position.Z; Program.Renderer.Camera.AbsoluteDirection = focusPosition - Program.Renderer.Camera.AbsolutePosition; double t = Program.Renderer.Camera.AbsoluteDirection.Norm(); double ti = 1.0 / t; Program.Renderer.Camera.AbsoluteDirection *= ti; Program.Renderer.Camera.AbsoluteSide = new Vector3(Program.Renderer.Camera.AbsoluteDirection.Z, 0.0, -Program.Renderer.Camera.AbsoluteDirection.X); Program.Renderer.Camera.AbsoluteSide.Normalize(); Program.Renderer.Camera.AbsoluteUp = Vector3.Cross(Program.Renderer.Camera.AbsoluteDirection, Program.Renderer.Camera.AbsoluteSide); Program.Renderer.UpdateViewingDistances(Program.CurrentRoute.CurrentBackground.BackgroundImageDistance); if (Program.Renderer.Camera.CurrentMode == CameraViewMode.FlyByZooming) { // zoom const double fadeOutDistance = 600.0; /* the distance with the highest zoom factor is half the fade-out distance */ const double maxZoomFactor = 7.0; /* the zoom factor at half the fade-out distance */ const double factor = 256.0 / (fadeOutDistance * fadeOutDistance * fadeOutDistance * fadeOutDistance * fadeOutDistance * fadeOutDistance * fadeOutDistance * fadeOutDistance); double zoom; if (t < fadeOutDistance) { double tdist4 = fadeOutDistance - t; tdist4 *= tdist4; tdist4 *= tdist4; double t4 = t * t; t4 *= t4; zoom = 1.0 + factor * zoomMultiplier * (maxZoomFactor - 1.0) * tdist4 * t4; } else { zoom = 1.0; } Program.Renderer.Camera.VerticalViewingAngle = Program.Renderer.Camera.OriginalVerticalViewingAngle / zoom; Program.Renderer.UpdateViewport(ViewportChangeMode.NoChange); } } } else { // non-fly-by { // current alignment Program.Renderer.Camera.AdjustAlignment(ref Program.Renderer.Camera.Alignment.Position.X, Program.Renderer.Camera.AlignmentDirection.Position.X, ref Program.Renderer.Camera.AlignmentSpeed.Position.X, TimeElapsed, false, TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].CameraRestriction); Program.Renderer.Camera.AdjustAlignment(ref Program.Renderer.Camera.Alignment.Position.Y, Program.Renderer.Camera.AlignmentDirection.Position.Y, ref Program.Renderer.Camera.AlignmentSpeed.Position.Y, TimeElapsed, false, TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].CameraRestriction); Program.Renderer.Camera.AdjustAlignment(ref Program.Renderer.Camera.Alignment.Position.Z, Program.Renderer.Camera.AlignmentDirection.Position.Z, ref Program.Renderer.Camera.AlignmentSpeed.Position.Z, TimeElapsed, false, TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].CameraRestriction); if ((Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior | Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead) & Program.Renderer.Camera.CurrentRestriction == CameraRestrictionMode.On) { if (Program.Renderer.Camera.Alignment.Position.Z > 0.75) { Program.Renderer.Camera.Alignment.Position.Z = 0.75; } } bool q = Program.Renderer.Camera.AlignmentSpeed.Yaw != 0.0 | Program.Renderer.Camera.AlignmentSpeed.Pitch != 0.0 | Program.Renderer.Camera.AlignmentSpeed.Roll != 0.0; Program.Renderer.Camera.AdjustAlignment(ref Program.Renderer.Camera.Alignment.Yaw, Program.Renderer.Camera.AlignmentDirection.Yaw, ref Program.Renderer.Camera.AlignmentSpeed.Yaw, TimeElapsed, false, TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].CameraRestriction); Program.Renderer.Camera.AdjustAlignment(ref Program.Renderer.Camera.Alignment.Pitch, Program.Renderer.Camera.AlignmentDirection.Pitch, ref Program.Renderer.Camera.AlignmentSpeed.Pitch, TimeElapsed, false, TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].CameraRestriction); Program.Renderer.Camera.AdjustAlignment(ref Program.Renderer.Camera.Alignment.Roll, Program.Renderer.Camera.AlignmentDirection.Roll, ref Program.Renderer.Camera.AlignmentSpeed.Roll, TimeElapsed, false, TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].CameraRestriction); double tr = Program.Renderer.Camera.Alignment.TrackPosition; Program.Renderer.Camera.AdjustAlignment(ref Program.Renderer.Camera.Alignment.TrackPosition, Program.Renderer.Camera.AlignmentDirection.TrackPosition, ref Program.Renderer.Camera.AlignmentSpeed.TrackPosition, TimeElapsed, false, TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].CameraRestriction); if (tr != Program.Renderer.Camera.Alignment.TrackPosition) { Program.Renderer.CameraTrackFollower.UpdateAbsolute(Program.Renderer.Camera.Alignment.TrackPosition, true, false); q = true; } if (q) { Program.Renderer.UpdateViewingDistances(Program.CurrentRoute.CurrentBackground.BackgroundImageDistance); } } // camera Vector3 cF = new Vector3(Program.Renderer.CameraTrackFollower.WorldPosition); Vector3 dF = new Vector3(Program.Renderer.CameraTrackFollower.WorldDirection); Vector3 uF = new Vector3(Program.Renderer.CameraTrackFollower.WorldUp); Vector3 sF = new Vector3(Program.Renderer.CameraTrackFollower.WorldSide); double lookaheadYaw; double lookaheadPitch; if (Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead) { // look-ahead double d = 20.0; if (TrainManager.PlayerTrain.CurrentSpeed > 0.0) { d += 3.0 * (Math.Sqrt(TrainManager.PlayerTrain.CurrentSpeed * TrainManager.PlayerTrain.CurrentSpeed + 1.0) - 1.0); } d -= TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].FrontAxle.Position; TrackFollower f = TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].FrontAxle.Follower.Clone(); f.TriggerType = EventTriggerType.None; f.UpdateRelative(d, true, false); Vector3 r = new Vector3(f.WorldPosition - cF + Program.Renderer.CameraTrackFollower.WorldSide * TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].Driver.X + Program.Renderer.CameraTrackFollower.WorldUp * TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].Driver.Y + Program.Renderer.CameraTrackFollower.WorldDirection * TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].Driver.Z); r.Normalize(); double t = dF.Z * (sF.Y * uF.X - sF.X * uF.Y) + dF.Y * (-sF.Z * uF.X + sF.X * uF.Z) + dF.X * (sF.Z * uF.Y - sF.Y * uF.Z); if (t != 0.0) { t = 1.0 / t; double tx = (r.Z * (-dF.Y * uF.X + dF.X * uF.Y) + r.Y * (dF.Z * uF.X - dF.X * uF.Z) + r.X * (-dF.Z * uF.Y + dF.Y * uF.Z)) * t; double ty = (r.Z * (dF.Y * sF.X - dF.X * sF.Y) + r.Y * (-dF.Z * sF.X + dF.X * sF.Z) + r.X * (dF.Z * sF.Y - dF.Y * sF.Z)) * t; double tz = (r.Z * (sF.Y * uF.X - sF.X * uF.Y) + r.Y * (-sF.Z * uF.X + sF.X * uF.Z) + r.X * (sF.Z * uF.Y - sF.Y * uF.Z)) * t; lookaheadYaw = tx * tz != 0.0 ? Math.Atan2(tx, tz) : 0.0; if (ty < -1.0) { lookaheadPitch = -0.5 * Math.PI; } else if (ty > 1.0) { lookaheadPitch = 0.5 * Math.PI; } else { lookaheadPitch = Math.Asin(ty); } } else { lookaheadYaw = 0.0; lookaheadPitch = 0.0; } } else { lookaheadYaw = 0.0; lookaheadPitch = 0.0; } { // cab pitch and yaw Vector3 d2 = new Vector3(dF); Vector3 u2 = new Vector3(uF); if ((Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior | Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead) & TrainManager.PlayerTrain != null) { int c = TrainManager.PlayerTrain.DriverCar; if (c >= 0) { if (TrainManager.PlayerTrain.Cars[c].CarSections.Length == 0 || TrainManager.PlayerTrain.Cars[c].CarSections[0].Groups[0].Type != ObjectType.Overlay) { d2.Rotate(sF, -TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].DriverPitch); u2.Rotate(sF, -TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].DriverPitch); } } } cF += sF * Program.Renderer.Camera.Alignment.Position.X + u2 * Program.Renderer.Camera.Alignment.Position + d2 * Program.Renderer.Camera.Alignment.Position.Z; } // yaw, pitch, roll double headYaw = Program.Renderer.Camera.Alignment.Yaw + lookaheadYaw; if ((Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior | Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead) & TrainManager.PlayerTrain != null) { if (TrainManager.PlayerTrain.DriverCar >= 0) { headYaw += TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].DriverYaw; } } double headPitch = Program.Renderer.Camera.Alignment.Pitch + lookaheadPitch; if ((Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior | Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead) & TrainManager.PlayerTrain != null) { if (TrainManager.PlayerTrain.DriverCar >= 0) { headPitch += TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].DriverPitch; } } double bodyPitch = 0.0; double bodyRoll = 0.0; double headRoll = Program.Renderer.Camera.Alignment.Roll; // rotation if ((Program.Renderer.Camera.CurrentRestriction == CameraRestrictionMode.NotAvailable || Program.Renderer.Camera.CurrentRestriction == CameraRestrictionMode.Restricted3D) & (Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior | Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead)) { // with body and head bodyPitch += TrainManager.PlayerTrain.DriverBody.Pitch; headPitch -= 0.2 * TrainManager.PlayerTrain.DriverBody.Pitch; bodyRoll += TrainManager.PlayerTrain.DriverBody.Roll; headRoll += 0.2 * TrainManager.PlayerTrain.DriverBody.Roll; const double bodyHeight = 0.6; const double headHeight = 0.1; { // body pitch double ry = (Math.Cos(-bodyPitch) - 1.0) * bodyHeight; double rz = Math.Sin(-bodyPitch) * bodyHeight; cF += dF * rz + uF * ry; if (bodyPitch != 0.0) { dF.Rotate(sF, -bodyPitch); uF.Rotate(sF, -bodyPitch); } } { // body roll double rx = Math.Sin(bodyRoll) * bodyHeight; double ry = (Math.Cos(bodyRoll) - 1.0) * bodyHeight; cF += sF * rx + uF * ry; if (bodyRoll != 0.0) { uF.Rotate(dF, -bodyRoll); sF.Rotate(dF, -bodyRoll); } } { // head yaw double rx = Math.Sin(headYaw) * headHeight; double rz = (Math.Cos(headYaw) - 1.0) * headHeight; cF += sF * rx + dF * rz; if (headYaw != 0.0) { dF.Rotate(uF, headYaw); sF.Rotate(uF, headYaw); } } { // head pitch double ry = (Math.Cos(-headPitch) - 1.0) * headHeight; double rz = Math.Sin(-headPitch) * headHeight; cF += dF * rz + uF * ry; if (headPitch != 0.0) { dF.Rotate(sF, -headPitch); uF.Rotate(sF, -headPitch); } } { // head roll double rx = Math.Sin(headRoll) * headHeight; double ry = (Math.Cos(headRoll) - 1.0) * headHeight; cF += sF * rx + uF * ry; if (headRoll != 0.0) { uF.Rotate(dF, -headRoll); sF.Rotate(dF, -headRoll); } } } else { // without body or head double totalYaw = headYaw; double totalPitch = headPitch + bodyPitch; double totalRoll = bodyRoll + headRoll; if (totalYaw != 0.0) { dF.Rotate(uF, totalYaw); sF.Rotate(uF, totalYaw); } if (totalPitch != 0.0) { dF.Rotate(sF, -totalPitch); uF.Rotate(sF, -totalPitch); } if (totalRoll != 0.0) { uF.Rotate(dF, -totalRoll); sF.Rotate(dF, -totalRoll); } } // finish Program.Renderer.Camera.AbsolutePosition = cF; Program.Renderer.Camera.AbsoluteDirection = dF; Program.Renderer.Camera.AbsoluteUp = uF; Program.Renderer.Camera.AbsoluteSide = sF; } }
internal static void UpdateTrackFollower(ref TrackFollower Follower, double NewTrackPosition, bool UpdateWorldCoordinates, bool AddTrackInaccurary) { if (CurrentTrack.Elements.Length == 0) return; int i = Follower.LastTrackElement; while (i >= 0 && NewTrackPosition < CurrentTrack.Elements[i].StartingTrackPosition) { double ta = Follower.TrackPosition - CurrentTrack.Elements[i].StartingTrackPosition; double tb = -0.01; CheckEvents(ref Follower, i, -1, ta, tb); i--; } if (i >= 0) { while (i < CurrentTrack.Elements.Length - 1) { if (NewTrackPosition < CurrentTrack.Elements[i + 1].StartingTrackPosition) break; double ta = Follower.TrackPosition - CurrentTrack.Elements[i].StartingTrackPosition; double tb = CurrentTrack.Elements[i + 1].StartingTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition + 0.01; CheckEvents(ref Follower, i, 1, ta, tb); i++; } } else { i = 0; } double da = Follower.TrackPosition - CurrentTrack.Elements[i].StartingTrackPosition; double db = NewTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition; // track if (UpdateWorldCoordinates) { if (db != 0.0) { if (CurrentTrack.Elements[i].CurveRadius != 0.0) { // curve double r = CurrentTrack.Elements[i].CurveRadius; double p = CurrentTrack.Elements[i].WorldDirection.Y / Math.Sqrt(CurrentTrack.Elements[i].WorldDirection.X * CurrentTrack.Elements[i].WorldDirection.X + CurrentTrack.Elements[i].WorldDirection.Z * CurrentTrack.Elements[i].WorldDirection.Z); double s = db / Math.Sqrt(1.0 + p * p); double h = s * p; double b = s / Math.Abs(r); double f = 2.0 * r * r * (1.0 - Math.Cos(b)); double c = (double)Math.Sign(db) * Math.Sqrt(f >= 0.0 ? f : 0.0); double a = 0.5 * (double)Math.Sign(r) * b; Vector3 D = new Vector3(CurrentTrack.Elements[i].WorldDirection.X, 0.0, CurrentTrack.Elements[i].WorldDirection.Z); World.Normalize(ref D.X, ref D.Y, ref D.Z); double cosa = Math.Cos(a); double sina = Math.Sin(a); World.Rotate(ref D.X, ref D.Y, ref D.Z, 0.0, 1.0, 0.0, cosa, sina); Follower.WorldPosition.X = CurrentTrack.Elements[i].WorldPosition.X + c * D.X; Follower.WorldPosition.Y = CurrentTrack.Elements[i].WorldPosition.Y + h; Follower.WorldPosition.Z = CurrentTrack.Elements[i].WorldPosition.Z + c * D.Z; World.Rotate(ref D.X, ref D.Y, ref D.Z, 0.0, 1.0, 0.0, cosa, sina); Follower.WorldDirection.X = D.X; Follower.WorldDirection.Y = p; Follower.WorldDirection.Z = D.Z; World.Normalize(ref Follower.WorldDirection.X, ref Follower.WorldDirection.Y, ref Follower.WorldDirection.Z); double cos2a = Math.Cos(2.0 * a); double sin2a = Math.Sin(2.0 * a); Follower.WorldSide = CurrentTrack.Elements[i].WorldSide; World.Rotate(ref Follower.WorldSide.X, ref Follower.WorldSide.Y, ref Follower.WorldSide.Z, 0.0, 1.0, 0.0, cos2a, sin2a); World.Cross(Follower.WorldDirection.X, Follower.WorldDirection.Y, Follower.WorldDirection.Z, Follower.WorldSide.X, Follower.WorldSide.Y, Follower.WorldSide.Z, out Follower.WorldUp.X, out Follower.WorldUp.Y, out Follower.WorldUp.Z); Follower.CurveRadius = CurrentTrack.Elements[i].CurveRadius; } else { // straight Follower.WorldPosition.X = CurrentTrack.Elements[i].WorldPosition.X + db * CurrentTrack.Elements[i].WorldDirection.X; Follower.WorldPosition.Y = CurrentTrack.Elements[i].WorldPosition.Y + db * CurrentTrack.Elements[i].WorldDirection.Y; Follower.WorldPosition.Z = CurrentTrack.Elements[i].WorldPosition.Z + db * CurrentTrack.Elements[i].WorldDirection.Z; Follower.WorldDirection = CurrentTrack.Elements[i].WorldDirection; Follower.WorldUp = CurrentTrack.Elements[i].WorldUp; Follower.WorldSide = CurrentTrack.Elements[i].WorldSide; Follower.CurveRadius = 0.0; } // cant if (i < CurrentTrack.Elements.Length - 1) { double t = db / (CurrentTrack.Elements[i + 1].StartingTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition); if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } double t2 = t * t; double t3 = t2 * t; Follower.CurveCant = (2.0 * t3 - 3.0 * t2 + 1.0) * CurrentTrack.Elements[i].CurveCant + (t3 - 2.0 * t2 + t) * CurrentTrack.Elements[i].CurveCantTangent + (-2.0 * t3 + 3.0 * t2) * CurrentTrack.Elements[i + 1].CurveCant + (t3 - t2) * CurrentTrack.Elements[i + 1].CurveCantTangent; } else { Follower.CurveCant = CurrentTrack.Elements[i].CurveCant; } } else { Follower.WorldPosition = CurrentTrack.Elements[i].WorldPosition; Follower.WorldDirection = CurrentTrack.Elements[i].WorldDirection; Follower.WorldUp = CurrentTrack.Elements[i].WorldUp; Follower.WorldSide = CurrentTrack.Elements[i].WorldSide; Follower.CurveRadius = CurrentTrack.Elements[i].CurveRadius; Follower.CurveCant = CurrentTrack.Elements[i].CurveCant; } } else { if (db != 0.0) { if (CurrentTrack.Elements[i].CurveRadius != 0.0) { Follower.CurveRadius = CurrentTrack.Elements[i].CurveRadius; } else { Follower.CurveRadius = 0.0; } if (i < CurrentTrack.Elements.Length - 1) { double t = db / (CurrentTrack.Elements[i + 1].StartingTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition); if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } double t2 = t * t; double t3 = t2 * t; Follower.CurveCant = (2.0 * t3 - 3.0 * t2 + 1.0) * CurrentTrack.Elements[i].CurveCant + (t3 - 2.0 * t2 + t) * CurrentTrack.Elements[i].CurveCantTangent + (-2.0 * t3 + 3.0 * t2) * CurrentTrack.Elements[i + 1].CurveCant + (t3 - t2) * CurrentTrack.Elements[i + 1].CurveCantTangent; } else { Follower.CurveCant = CurrentTrack.Elements[i].CurveCant; } } else { Follower.CurveRadius = CurrentTrack.Elements[i].CurveRadius; Follower.CurveCant = CurrentTrack.Elements[i].CurveCant; } } Follower.AdhesionMultiplier = CurrentTrack.Elements[i].AdhesionMultiplier; // inaccuracy if (AddTrackInaccurary) { double x, y, c; if (i < CurrentTrack.Elements.Length - 1) { double t = db / (CurrentTrack.Elements[i + 1].StartingTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition); if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } double x1, y1, c1; double x2, y2, c2; GetInaccuracies(NewTrackPosition, CurrentTrack.Elements[i].CsvRwAccuracyLevel, out x1, out y1, out c1); GetInaccuracies(NewTrackPosition, CurrentTrack.Elements[i + 1].CsvRwAccuracyLevel, out x2, out y2, out c2); x = (1.0 - t) * x1 + t * x2; y = (1.0 - t) * y1 + t * y2; c = (1.0 - t) * c1 + t * c2; } else { GetInaccuracies(NewTrackPosition, CurrentTrack.Elements[i].CsvRwAccuracyLevel, out x, out y, out c); } Follower.WorldPosition.X += x * Follower.WorldSide.X + y * Follower.WorldUp.X; Follower.WorldPosition.Y += x * Follower.WorldSide.Y + y * Follower.WorldUp.Y; Follower.WorldPosition.Z += x * Follower.WorldSide.Z + y * Follower.WorldUp.Z; Follower.CurveCant += c; Follower.CantDueToInaccuracy = c; } else { Follower.CantDueToInaccuracy = 0.0; } // events CheckEvents(ref Follower, i, Math.Sign(db - da), da, db); // finish Follower.TrackPosition = NewTrackPosition; Follower.LastTrackElement = i; }
internal static void UpdateTrackFollower(ref TrackFollower Follower, double NewTrackPosition, bool UpdateWorldCoordinates, bool AddTrackInaccurary) { if (CurrentTrack.Elements == null) return; if (CurrentTrack.Elements.Length == 0) return; int i = Follower.LastTrackElement; while (i >= 0 && NewTrackPosition < CurrentTrack.Elements[i].StartingTrackPosition) { double ta = Follower.TrackPosition - CurrentTrack.Elements[i].StartingTrackPosition; double tb = -0.01; CheckEvents(ref Follower, i, -1, ta, tb); i--; } if (i >= 0) { while (i < CurrentTrack.Elements.Length - 1) { if (NewTrackPosition < CurrentTrack.Elements[i + 1].StartingTrackPosition) break; double ta = Follower.TrackPosition - CurrentTrack.Elements[i].StartingTrackPosition; double tb = CurrentTrack.Elements[i + 1].StartingTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition + 0.01; CheckEvents(ref Follower, i, 1, ta, tb); i++; } } else i = 0; double da = Follower.TrackPosition - CurrentTrack.Elements[i].StartingTrackPosition; double db = NewTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition; // track if (UpdateWorldCoordinates) { if (db != 0.0) { if (CurrentTrack.Elements[i].CurveRadius != 0.0) { // side curve double r = CurrentTrack.Elements[i].CurveRadius; double p = CurrentTrack.Elements[i].WorldDirection.Y / Math.Sqrt(CurrentTrack.Elements[i].WorldDirection.X * CurrentTrack.Elements[i].WorldDirection.X + CurrentTrack.Elements[i].WorldDirection.Z * CurrentTrack.Elements[i].WorldDirection.Z); double s = db / Math.Sqrt(1.0 + p * p); double h = s * p; double b = s / Math.Abs(r); double f = 2.0 * r * r * (1.0 - Math.Cos(b)); double c = (double)Math.Sign(db) * Math.Sqrt(f >= 0.0 ? f : 0.0); double a = 0.5 * (double)Math.Sign(r) * b; World.Vector3D D = new World.Vector3D(CurrentTrack.Elements[i].WorldDirection.X, 0.0, CurrentTrack.Elements[i].WorldDirection.Z); World.Normalize(ref D.X, ref D.Y, ref D.Z); double cosa = Math.Cos(a); double sina = Math.Sin(a); World.Rotate(ref D.X, ref D.Y, ref D.Z, 0.0, 1.0, 0.0, cosa, sina); Follower.WorldPosition.X = CurrentTrack.Elements[i].WorldPosition.X + c * D.X; Follower.WorldPosition.Y = CurrentTrack.Elements[i].WorldPosition.Y + h; Follower.WorldPosition.Z = CurrentTrack.Elements[i].WorldPosition.Z + c * D.Z; World.Rotate(ref D.X, ref D.Y, ref D.Z, 0.0, 1.0, 0.0, cosa, sina); Follower.WorldDirection.X = D.X; Follower.WorldDirection.Y = p; Follower.WorldDirection.Z = D.Z; World.Normalize(ref Follower.WorldDirection.X, ref Follower.WorldDirection.Y, ref Follower.WorldDirection.Z); double cos2a = Math.Cos(2.0 * a); double sin2a = Math.Sin(2.0 * a); Follower.WorldSide = CurrentTrack.Elements[i].WorldSide; World.Rotate(ref Follower.WorldSide.X, ref Follower.WorldSide.Y, ref Follower.WorldSide.Z, 0.0, 1.0, 0.0, cos2a, sin2a); World.Cross(Follower.WorldDirection.X, Follower.WorldDirection.Y, Follower.WorldDirection.Z, Follower.WorldSide.X, Follower.WorldSide.Y, Follower.WorldSide.Z, out Follower.WorldUp.X, out Follower.WorldUp.Y, out Follower.WorldUp.Z); Follower.CurveRadius = CurrentTrack.Elements[i].CurveRadius; } else { // straight Follower.WorldPosition.X = CurrentTrack.Elements[i].WorldPosition.X + db * CurrentTrack.Elements[i].WorldDirection.X; Follower.WorldPosition.Y = CurrentTrack.Elements[i].WorldPosition.Y + db * CurrentTrack.Elements[i].WorldDirection.Y; Follower.WorldPosition.Z = CurrentTrack.Elements[i].WorldPosition.Z + db * CurrentTrack.Elements[i].WorldDirection.Z; Follower.WorldDirection = CurrentTrack.Elements[i].WorldDirection; Follower.WorldUp = CurrentTrack.Elements[i].WorldUp; Follower.WorldSide = CurrentTrack.Elements[i].WorldSide; Follower.CurveRadius = 0.0; } // cant if (i < CurrentTrack.Elements.Length - 1) { double t = db / (CurrentTrack.Elements[i + 1].StartingTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition); switch (CurrentTrack.Elements[i].CurveCantInterpolation) { case CantInterpolationMode.BiasForward: t *= t; t = 1.0 - t * t; t = 1.0 - t * t; break; case CantInterpolationMode.BiasBackward: t = 1.0 - t; t *= t; t = 1.0 - t * t; t *= t; break; } Follower.CurveCant = (1.0 - t) * CurrentTrack.Elements[i].CurveCant + t * CurrentTrack.Elements[i + 1].CurveCant; } else { Follower.CurveCant = CurrentTrack.Elements[i].CurveCant; } } else { Follower.WorldPosition = CurrentTrack.Elements[i].WorldPosition; Follower.WorldDirection = CurrentTrack.Elements[i].WorldDirection; Follower.WorldUp = CurrentTrack.Elements[i].WorldUp; Follower.WorldSide = CurrentTrack.Elements[i].WorldSide; Follower.CurveRadius = CurrentTrack.Elements[i].CurveRadius; Follower.CurveCant = CurrentTrack.Elements[i].CurveCant; } } Follower.AdhesionMultiplier = CurrentTrack.Elements[i].AdhesionMultiplier; if (AddTrackInaccurary) { double f = NewTrackPosition; f = 0.3121 * Math.Sin(0.9843 * f) + 1.1217 * Math.Sin(0.1874 * f) + 1.6421 * Math.Sin(0.1126 * f) + 1.8421 * Math.Sin(0.2546 * f); f *= 0.15 * CurrentTrack.Elements[i].Inaccuracy; double g = NewTrackPosition; g = 0.3495 * Math.Sin(0.8272 * g) + 1.6321 * Math.Sin(0.2356 * g); g *= 0.15 * CurrentTrack.Elements[i].Inaccuracy; Follower.WorldPosition.X += f * Follower.WorldSide.X + g * Follower.WorldUp.X; Follower.WorldPosition.Y += f * Follower.WorldSide.Y + g * Follower.WorldUp.Y; Follower.WorldPosition.Z += f * Follower.WorldSide.Z + g * Follower.WorldUp.Z; } // events CheckEvents(ref Follower, i, Math.Sign(db - da), da, db); // finish Follower.TrackPosition = NewTrackPosition; Follower.LastTrackElement = i; }