Example #1
0
        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);
                    }
                }
            }
        }
Example #2
0
 // 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);
             }
         }
     }
 }
Example #3
0
        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);
                }
            }
        }
Example #4
0
        /// <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;
            }
        }
Example #5
0
 /// <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);
     }
 }
Example #6
0
        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());
            }
        }
Example #7
0
 /// <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;
 }
Example #8
0
        public override void Trigger(int direction, TrackFollower trackFollower)
        {
            trackFollower.EnterStation(StationIndex, direction);

            if (trackFollower.TriggerType == EventTriggerType.TrainFront)
            {
                trackFollower.Train.EnterStation(StationIndex, direction);
            }
        }
Example #9
0
        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);
            }
        }
Example #10
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;
         }
     }
 }
Example #11
0
        /// <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;
                    }
                }
            }
        }
Example #12
0
    /// <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);
    }
Example #13
0
 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;
         }
     }
 }
Example #14
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;
         }
     }
 }
Example #15
0
        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);
        }
Example #16
0
        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;
                    }
                }
            }
        }
Example #17
0
        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);
            }
        }
Example #18
0
        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;
                }
            }
        }
Example #19
0
        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;
            }
        }
Example #20
0
 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;
             }
         }
     }
 }
Example #21
0
        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();
            }
        }
Example #22
0
        /// <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;
            }
        }
Example #23
0
        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;
                }
            }
        }
Example #24
0
        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)
 {
 }
Example #26
0
        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;
        }
Example #27
0
    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);
                 }
             }
         }
     }
 }
Example #29
0
        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);
        }
Example #30
0
#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);
        }
Example #31
0
        // 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;
 }
Example #33
0
		internal static void UpdateTrackFollower(ref TrackFollower Follower, double NewTrackPosition, bool UpdateWorldCoordinates, bool AddTrackInaccurary) { }
 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;
 }