Пример #1
0
        /// <summary> Updates the position and state of the animated object</summary>
        /// <param name="IsPartOfTrain">Whether this object forms part of a train</param>
        /// <param name="Train">The train, or a null reference otherwise</param>
        /// <param name="CarIndex">If this object forms part of a train, the car index it refers to</param>
        /// <param name="SectionIndex">If this object has been placed via Track.Sig, the index of the section it is attached to</param>
        /// <param name="TrackPosition"></param>
        /// <param name="Position"></param>
        /// <param name="Direction"></param>
        /// <param name="Up"></param>
        /// <param name="Side"></param>
        /// <param name="UpdateFunctions">Whether the functions associated with this object should be re-evaluated</param>
        /// <param name="Show"></param>
        /// <param name="TimeElapsed">The time elapsed since this object was last updated</param>
        /// <param name="EnableDamping">Whether damping is to be applied for this call</param>
        /// <param name="IsTouch">Whether Animated Object belonging to TouchElement class.</param>
        /// <param name="Camera"></param>
        public void Update(bool IsPartOfTrain, AbstractTrain Train, int CarIndex, int SectionIndex, double TrackPosition, Vector3 Position, Vector3 Direction, Vector3 Up, Vector3 Side, bool UpdateFunctions, bool Show, double TimeElapsed, bool EnableDamping, bool IsTouch = false, dynamic Camera = null)
        {
            int s = CurrentState;

            // state change
            if (StateFunction != null & UpdateFunctions)
            {
                double sd = StateFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState);
                int    si = (int)System.Math.Round(sd);
                int    sn = States.Length;
                if (si < 0 | si >= sn)
                {
                    si = -1;
                }
                if (s != si)
                {
                    Initialize(si, Camera != null, Show);
                    s = si;
                }
            }

            if (s == -1)
            {
                return;
            }
            // translation
            if (TranslateXFunction != null)
            {
                double x;
                if (UpdateFunctions)
                {
                    x = TranslateXFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState);
                }
                else
                {
                    x = TranslateXFunction.LastResult;
                }

                Vector3 translationVector = new Vector3(TranslateXDirection);                 //Must clone
                translationVector.Rotate(Direction, Up, Side);
                translationVector *= x;
                Position          += translationVector;
            }
            else if (TranslateXScriptFile != null)
            {
                //Translate X Script
                if (TranslateXAnimationScript == null)
                {
                    //Load the script if required
                    try
                    {
                        CSScript.GlobalSettings.TargetFramework = "v4.0";
                        TranslateXAnimationScript = CSScript.LoadCode(File.ReadAllText(TranslateXScriptFile))
                                                    .CreateObject("OpenBVEScript")
                                                    .AlignToInterface <AnimationScript>(true);
                    }
                    catch
                    {
                        currentHost.AddMessage(MessageType.Error, false,
                                               "An error occcured whilst parsing script " + TranslateXScriptFile);
                        TranslateXScriptFile = null;
                        return;
                    }
                }

                double x = TranslateXAnimationScript.ExecuteScript(Train, Position, TrackPosition, SectionIndex,
                                                                   IsPartOfTrain, TimeElapsed);
                Vector3 translationVector = new Vector3(TranslateXDirection);                 //Must clone
                translationVector.Rotate(Direction, Up, Side);
                translationVector *= x;
                Position          += translationVector;
            }


            if (TranslateYFunction != null)
            {
                double y;
                if (UpdateFunctions)
                {
                    y = TranslateYFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState);
                }
                else
                {
                    y = TranslateYFunction.LastResult;
                }

                Vector3 translationVector = new Vector3(TranslateYDirection);                 //Must clone
                translationVector.Rotate(Direction, Up, Side);
                translationVector *= y;
                Position          += translationVector;
            }
            else if (TranslateYScriptFile != null)
            {
                //Translate X Script
                if (TranslateYAnimationScript == null)
                {
                    //Load the script if required
                    try
                    {
                        CSScript.GlobalSettings.TargetFramework = "v4.0";
                        TranslateYAnimationScript = CSScript.LoadCode(File.ReadAllText(TranslateYScriptFile))
                                                    .CreateObject("OpenBVEScript")
                                                    .AlignToInterface <AnimationScript>(true);
                    }
                    catch
                    {
                        currentHost.AddMessage(MessageType.Error, false,
                                               "An error occcured whilst parsing script " + TranslateYScriptFile);
                        TranslateYScriptFile = null;
                        return;
                    }
                }

                double y = TranslateYAnimationScript.ExecuteScript(Train, Position, TrackPosition, SectionIndex,
                                                                   IsPartOfTrain, TimeElapsed);
                Vector3 translationVector = new Vector3(TranslateYDirection);                 //Must clone
                translationVector.Rotate(Direction, Up, Side);
                translationVector *= y;
                Position          += translationVector;
            }

            if (TranslateZFunction != null)
            {
                double z;
                if (UpdateFunctions)
                {
                    z = TranslateZFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState);
                }
                else
                {
                    z = TranslateZFunction.LastResult;
                }

                Vector3 translationVector = new Vector3(TranslateZDirection);                 //Must clone
                translationVector.Rotate(Direction, Up, Side);
                translationVector *= z;
                Position          += translationVector;
            }
            else if (TranslateZScriptFile != null)
            {
                //Translate X Script
                if (TranslateZAnimationScript == null)
                {
                    //Load the script if required
                    try
                    {
                        CSScript.GlobalSettings.TargetFramework = "v4.0";
                        TranslateZAnimationScript = CSScript.LoadCode(File.ReadAllText(TranslateZScriptFile))
                                                    .CreateObject("OpenBVEScript")
                                                    .AlignToInterface <AnimationScript>(true);
                    }
                    catch
                    {
                        currentHost.AddMessage(MessageType.Error, false,
                                               "An error occcured whilst parsing script " + TranslateZScriptFile);
                        TranslateZScriptFile = null;
                        return;
                    }
                }

                double z = TranslateZAnimationScript.ExecuteScript(Train, Position, TrackPosition, SectionIndex,
                                                                   IsPartOfTrain, TimeElapsed);
                Vector3 translationVector = new Vector3(TranslateZDirection);                 //Must clone
                translationVector.Rotate(Direction, Up, Side);
                translationVector *= z;
                Position          += translationVector;
            }

            // rotation
            bool   rotateX = RotateXFunction != null;
            bool   rotateY = RotateYFunction != null;
            bool   rotateZ = RotateZFunction != null;
            double radianX;

            if (rotateX)
            {
                double a;
                if (UpdateFunctions)
                {
                    a = RotateXFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState);
                }
                else
                {
                    a = RotateXFunction.LastResult;
                }

                if (RotateXDamping != null)
                {
                    RotateXDamping.Update(TimeElapsed, ref a, EnableDamping);
                }

                radianX = a;
            }
            else
            {
                radianX = 0.0;
            }

            double radianY;

            if (rotateY)
            {
                double a;
                if (UpdateFunctions)
                {
                    a = RotateYFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState);
                }
                else
                {
                    a = RotateYFunction.LastResult;
                }

                if (RotateYDamping != null)
                {
                    RotateYDamping.Update(TimeElapsed, ref a, EnableDamping);
                }

                radianY = a;
            }
            else
            {
                radianY = 0.0;
            }

            double radianZ;

            if (rotateZ)
            {
                double a;
                if (UpdateFunctions)
                {
                    a = RotateZFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState);
                }
                else
                {
                    a = RotateZFunction.LastResult;
                }

                if (RotateZDamping != null)
                {
                    RotateZDamping.Update(TimeElapsed, ref a, EnableDamping);
                }

                radianZ = a;
            }
            else
            {
                radianZ = 0.0;
            }

            // texture shift
            bool shiftx = TextureShiftXFunction != null;
            bool shifty = TextureShiftYFunction != null;

            internalObject.TextureTranslation = Matrix4D.Identity;

            if (shiftx | shifty)
            {
                if (shiftx)
                {
                    double x;
                    if (UpdateFunctions)
                    {
                        x = TextureShiftXFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState);
                    }
                    else
                    {
                        x = TextureShiftXFunction.LastResult;
                    }

                    x -= System.Math.Floor(x);
                    internalObject.TextureTranslation *= Matrix4D.CreateTranslation(x * TextureShiftXDirection.X, x * TextureShiftXDirection.Y, 1.0);
                }

                if (shifty)
                {
                    double y;
                    if (UpdateFunctions)
                    {
                        y = TextureShiftYFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState);
                    }
                    else
                    {
                        y = TextureShiftYFunction.LastResult;
                    }

                    y -= System.Math.Floor(y);
                    internalObject.TextureTranslation *= Matrix4D.CreateTranslation(y * TextureShiftYDirection.X, y * TextureShiftYDirection.Y, 1.0);
                }
            }

            // led
            bool   led = LEDFunction != null;
            double ledangle;

            if (led)
            {
                if (UpdateFunctions)
                {
                    ledangle = LEDFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState);
                }
                else
                {
                    ledangle = LEDFunction.LastResult;
                }
            }
            else
            {
                ledangle = 0.0;
            }

            // null object
            if (States[s].Prototype == null)
            {
                return;
            }

            // led
            if (led)
            {
                /*
                 * Edges:         Vertices:
                 * 0 - bottom     0 - bottom-left
                 * 1 - left       1 - top-left
                 * 2 - top        2 - top-right
                 * 3 - right      3 - bottom-right
                 *                4 - center
                 * */
                int v = 1;
                if (LEDClockwiseWinding)
                {
                    /* winding is clockwise*/
                    if (ledangle < LEDInitialAngle)
                    {
                        ledangle = LEDInitialAngle;
                    }

                    if (ledangle < LEDLastAngle)
                    {
                        double currentEdgeFloat = System.Math.Floor(0.636619772367582 * (ledangle + 0.785398163397449));
                        int    currentEdge      = ((int)currentEdgeFloat % 4 + 4) % 4;
                        double lastEdgeFloat    = System.Math.Floor(0.636619772367582 * (LEDLastAngle + 0.785398163397449));
                        int    lastEdge         = ((int)lastEdgeFloat % 4 + 4) % 4;
                        if (lastEdge < currentEdge | lastEdge == currentEdge & System.Math.Abs(currentEdgeFloat - lastEdgeFloat) > 2.0)
                        {
                            lastEdge += 4;
                        }

                        if (currentEdge == lastEdge)
                        {
                            /* current angle to last angle */
                            {
                                double t = 0.5 + 0.636619772367582 * ledangle - currentEdgeFloat;
                                if (t < 0.0)
                                {
                                    t = 0.0;
                                }
                                else if (t > 1.0)
                                {
                                    t = 1.0;
                                }

                                t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t)));
                                double cx = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].X + t * LEDVectors[currentEdge].X;
                                double cy = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Y + t * LEDVectors[currentEdge].Y;
                                double cz = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Z + t * LEDVectors[currentEdge].Z;
                                States[s].Prototype.Mesh.Vertices[v].Coordinates = new Vector3(cx, cy, cz);
                                v++;
                            }
                            {
                                double t = 0.5 + 0.636619772367582 * LEDLastAngle - lastEdgeFloat;
                                if (t < 0.0)
                                {
                                    t = 0.0;
                                }
                                else if (t > 1.0)
                                {
                                    t = 1.0;
                                }

                                t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t)));
                                double lx = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].X + t * LEDVectors[lastEdge].X;
                                double ly = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Y + t * LEDVectors[lastEdge].Y;
                                double lz = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Z + t * LEDVectors[lastEdge].Z;
                                States[s].Prototype.Mesh.Vertices[v].Coordinates = new Vector3(lx, ly, lz);
                                v++;
                            }
                        }
                        else
                        {
                            {
                                /* current angle to square vertex */
                                double t = 0.5 + 0.636619772367582 * ledangle - currentEdgeFloat;
                                if (t < 0.0)
                                {
                                    t = 0.0;
                                }
                                else if (t > 1.0)
                                {
                                    t = 1.0;
                                }

                                t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t)));
                                double cx = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].X + t * LEDVectors[currentEdge].X;
                                double cy = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Y + t * LEDVectors[currentEdge].Y;
                                double cz = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Z + t * LEDVectors[currentEdge].Z;
                                States[s].Prototype.Mesh.Vertices[v + 0].Coordinates = new Vector3(cx, cy, cz);
                                States[s].Prototype.Mesh.Vertices[v + 1].Coordinates = LEDVectors[currentEdge];
                                v += 2;
                            }
                            for (int j = currentEdge + 1; j < lastEdge; j++)
                            {
                                /* square-vertex to square-vertex */
                                States[s].Prototype.Mesh.Vertices[v + 0].Coordinates = LEDVectors[(j + 3) % 4];
                                States[s].Prototype.Mesh.Vertices[v + 1].Coordinates = LEDVectors[j % 4];
                                v += 2;
                            }

                            {
                                /* square vertex to last angle */
                                double t = 0.5 + 0.636619772367582 * LEDLastAngle - lastEdgeFloat;
                                if (t < 0.0)
                                {
                                    t = 0.0;
                                }
                                else if (t > 1.0)
                                {
                                    t = 1.0;
                                }

                                t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t)));
                                double lx = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].X + t * LEDVectors[lastEdge % 4].X;
                                double ly = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Y + t * LEDVectors[lastEdge % 4].Y;
                                double lz = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Z + t * LEDVectors[lastEdge % 4].Z;
                                States[s].Prototype.Mesh.Vertices[v + 0].Coordinates = LEDVectors[(lastEdge + 3) % 4];
                                States[s].Prototype.Mesh.Vertices[v + 1].Coordinates = new Vector3(lx, ly, lz);
                                v += 2;
                            }
                        }
                    }
                }
                else
                {
                    /* winding is counter-clockwise*/
                    if (ledangle > LEDInitialAngle)
                    {
                        ledangle = LEDInitialAngle;
                    }

                    if (ledangle > LEDLastAngle)
                    {
                        double currentEdgeFloat = System.Math.Floor(0.636619772367582 * (ledangle + 0.785398163397449));
                        int    currentEdge      = ((int)currentEdgeFloat % 4 + 4) % 4;
                        double lastEdgeFloat    = System.Math.Floor(0.636619772367582 * (LEDLastAngle + 0.785398163397449));
                        int    lastEdge         = ((int)lastEdgeFloat % 4 + 4) % 4;
                        if (currentEdge < lastEdge | lastEdge == currentEdge & System.Math.Abs(currentEdgeFloat - lastEdgeFloat) > 2.0)
                        {
                            currentEdge += 4;
                        }

                        if (currentEdge == lastEdge)
                        {
                            /* current angle to last angle */
                            {
                                double t = 0.5 + 0.636619772367582 * LEDLastAngle - lastEdgeFloat;
                                if (t < 0.0)
                                {
                                    t = 0.0;
                                }
                                else if (t > 1.0)
                                {
                                    t = 1.0;
                                }

                                t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t)));
                                double lx = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].X + t * LEDVectors[lastEdge].X;
                                double ly = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Y + t * LEDVectors[lastEdge].Y;
                                double lz = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Z + t * LEDVectors[lastEdge].Z;
                                States[s].Prototype.Mesh.Vertices[v].Coordinates = new Vector3(lx, ly, lz);
                                v++;
                            }
                            {
                                double t = 0.5 + 0.636619772367582 * ledangle - currentEdgeFloat;
                                if (t < 0.0)
                                {
                                    t = 0.0;
                                }
                                else if (t > 1.0)
                                {
                                    t = 1.0;
                                }

                                t = t - System.Math.Floor(t);
                                t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t)));
                                double cx = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].X + t * LEDVectors[currentEdge].X;
                                double cy = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Y + t * LEDVectors[currentEdge].Y;
                                double cz = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Z + t * LEDVectors[currentEdge].Z;
                                States[s].Prototype.Mesh.Vertices[v].Coordinates = new Vector3(cx, cy, cz);
                                v++;
                            }
                        }
                        else
                        {
                            {
                                /* current angle to square vertex */
                                double t = 0.5 + 0.636619772367582 * ledangle - currentEdgeFloat;
                                if (t < 0.0)
                                {
                                    t = 0.0;
                                }
                                else if (t > 1.0)
                                {
                                    t = 1.0;
                                }

                                t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t)));
                                double cx = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].X + t * LEDVectors[currentEdge % 4].X;
                                double cy = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Y + t * LEDVectors[currentEdge % 4].Y;
                                double cz = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Z + t * LEDVectors[currentEdge % 4].Z;
                                States[s].Prototype.Mesh.Vertices[v + 0].Coordinates = LEDVectors[(currentEdge + 3) % 4];
                                States[s].Prototype.Mesh.Vertices[v + 1].Coordinates = new Vector3(cx, cy, cz);
                                v += 2;
                            }
                            for (int j = currentEdge - 1; j > lastEdge; j--)
                            {
                                /* square-vertex to square-vertex */
                                States[s].Prototype.Mesh.Vertices[v + 0].Coordinates = LEDVectors[(j + 3) % 4];
                                States[s].Prototype.Mesh.Vertices[v + 1].Coordinates = LEDVectors[j % 4];
                                v += 2;
                            }

                            {
                                /* square vertex to last angle */
                                double t = 0.5 + 0.636619772367582 * LEDLastAngle - lastEdgeFloat;
                                if (t < 0.0)
                                {
                                    t = 0.0;
                                }
                                else if (t > 1.0)
                                {
                                    t = 1.0;
                                }

                                t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t)));
                                double lx = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].X + t * LEDVectors[lastEdge].X;
                                double ly = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Y + t * LEDVectors[lastEdge].Y;
                                double lz = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Z + t * LEDVectors[lastEdge].Z;
                                States[s].Prototype.Mesh.Vertices[v + 0].Coordinates = new Vector3(lx, ly, lz);
                                States[s].Prototype.Mesh.Vertices[v + 1].Coordinates = LEDVectors[lastEdge % 4];
                                v += 2;
                            }
                        }
                    }
                }

                for (int j = v; v < 11; v++)
                {
                    States[s].Prototype.Mesh.Vertices[j].Coordinates = LEDVectors[4];
                }
            }

            // update prototype
            internalObject.Prototype = States[s].Prototype;

            // update VAO for led if required
            UpdateVAO = led;

            // update state
            // rotate
            internalObject.Rotate = Matrix4D.Identity;

            if (rotateX)
            {
                internalObject.Rotate *= Matrix4D.CreateFromAxisAngle(new Vector3(RotateXDirection.X, RotateXDirection.Y, -RotateXDirection.Z), 2.0 * System.Math.PI - radianX);
            }

            if (rotateY)
            {
                internalObject.Rotate *= Matrix4D.CreateFromAxisAngle(new Vector3(RotateYDirection.X, RotateYDirection.Y, -RotateYDirection.Z), 2.0 * System.Math.PI - radianY);
            }

            if (rotateZ)
            {
                internalObject.Rotate *= Matrix4D.CreateFromAxisAngle(new Vector3(RotateZDirection.X, RotateZDirection.Y, -RotateZDirection.Z), 2.0 * System.Math.PI - radianZ);
            }

            if (Camera != null && Camera.CurrentRestriction != CameraRestrictionMode.NotAvailable && Camera.CurrentRestriction != CameraRestrictionMode.Restricted3D)
            {
                internalObject.Rotate *= States[s].Translation * Matrix4D.CreateTranslation(-Position.X, -Position.Y, Position.Z);
                internalObject.Rotate *= (Matrix4D) new Transformation((Vector3)Camera.AbsoluteDirection, (Vector3)Camera.AbsoluteUp, (Vector3)Camera.AbsoluteSide);

                // translate
                double  dx  = -System.Math.Tan(Camera.Alignment.Yaw) - Camera.Alignment.Position.X;
                double  dy  = -System.Math.Tan(Camera.Alignment.Pitch) - Camera.Alignment.Position.Y;
                double  dz  = -Camera.Alignment.Position.Z;
                Vector3 add = Camera.AbsolutePosition + dx * Camera.AbsoluteSide + dy * Camera.AbsoluteUp + dz * Camera.AbsoluteDirection;
                internalObject.Translation = Matrix4D.CreateTranslation(add.X, add.Y, -add.Z);
            }
            else
            {
                internalObject.Rotate *= States[s].Translation;
                internalObject.Rotate *= (Matrix4D) new Transformation(Direction, Up, Side);

                // translate
                internalObject.Translation = Matrix4D.CreateTranslation(Position.X, Position.Y, -Position.Z);
            }

            // visibility changed
            // TouchElement is handled by another function.
            if (!IsTouch)
            {
                if (Show)
                {
                    if (Camera != null)
                    {
                        currentHost.ShowObject(internalObject, ObjectType.Overlay);
                    }
                    else
                    {
                        currentHost.ShowObject(internalObject, ObjectType.Dynamic);
                    }
                }
                else
                {
                    currentHost.HideObject(internalObject);
                }
            }
        }
Пример #2
0
        /// <summary>Loads a list of compatibility signal objects</summary>
        /// <param name="currentHost">The host application interface</param>
        /// <param name="fileName">The file name of the object list</param>
        /// <param name="objects">The returned array of speed limits</param>
        /// <param name="signalPost">Sets the default signal post</param>
        /// <param name="speedLimits">The array of signal speed limits</param>
        /// <returns>An array of compatability signal objects</returns>
        public static void ReadCompatibilitySignalXML(HostInterface currentHost, string fileName, out CompatibilitySignalObject[] objects, out UnifiedObject signalPost, out double[] speedLimits)
        {
            signalPost = new StaticObject(currentHost);
            objects    = new CompatibilitySignalObject[9];
            //Default Japanese speed limits converted to m/s
            speedLimits = new[] { 0.0, 6.94444444444444, 15.2777777777778, 20.8333333333333, double.PositiveInfinity, double.PositiveInfinity };
            XmlDocument currentXML = new XmlDocument();

            currentXML.Load(fileName);
            string currentPath = System.IO.Path.GetDirectoryName(fileName);

            if (currentXML.DocumentElement != null)
            {
                XmlNode node = currentXML.SelectSingleNode("/openBVE/CompatibilitySignals/SignalSetName");
                if (node != null)
                {
                    currentHost.AddMessage(MessageType.Information, false, "INFO: Using the " + node.InnerText + " compatibility signal set.");
                }
                XmlNodeList DocumentNodes = currentXML.DocumentElement.SelectNodes("/openBVE/CompatibilitySignals/Signal");
                if (DocumentNodes != null)
                {
                    int index = 0;
                    foreach (XmlNode nn in DocumentNodes)
                    {
                        List <StaticObject> objectList = new List <StaticObject>();
                        List <int>          aspectList = new List <int>();
                        try
                        {
                            if (nn.HasChildNodes)
                            {
                                foreach (XmlNode n in nn.ChildNodes)
                                {
                                    if (n.Name != "Aspect")
                                    {
                                        continue;
                                    }

                                    int aspect;
                                    if (!NumberFormats.TryParseIntVb6(n.Attributes["Number"].Value, out aspect))
                                    {
                                        currentHost.AddMessage(MessageType.Error, true, "Invalid aspect number " + aspect + " in the signal object list in the compatability signal file " + fileName);
                                        continue;
                                    }

                                    aspectList.Add(aspect);

                                    StaticObject staticObject = new StaticObject(currentHost);
                                    if (n.InnerText.ToLowerInvariant() != "null")
                                    {
                                        string objectFile = Path.CombineFile(currentPath, n.InnerText);
                                        if (File.Exists(objectFile))
                                        {
                                            currentHost.LoadStaticObject(objectFile, Encoding.UTF8, false, out staticObject);
                                        }
                                        else
                                        {
                                            currentHost.AddMessage(MessageType.Error, true, "Compatibility signal file " + objectFile + " not found in " + fileName);
                                        }
                                    }
                                    objectList.Add(staticObject);
                                }
                            }
                        }
                        catch
                        {
                            currentHost.AddMessage(MessageType.Error, true, "An unexpected error was encountered whilst processing the compatability signal file " + fileName);
                        }
                        objects[index] = new CompatibilitySignalObject(aspectList.ToArray(), objectList.ToArray(), currentHost);
                        index++;
                    }
                }

                string signalPostFile = Path.CombineFile(currentPath, "Japanese\\signal_post.csv");                 //default plain post
                try
                {
                    node = currentXML.SelectSingleNode("/openBVE/CompatibilitySignals/SignalPost");
                    if (node != null)
                    {
                        string newFile = Path.CombineFile(currentPath, node.InnerText);
                        if (File.Exists(newFile))
                        {
                            signalPostFile = newFile;
                        }
                    }
                    currentHost.LoadObject(signalPostFile, Encoding.UTF8, out signalPost);
                }
                catch
                {
                    currentHost.AddMessage(MessageType.Error, true, "An unexpected error was encountered whilst processing the compatability signal file " + fileName);
                }

                DocumentNodes = currentXML.DocumentElement.SelectNodes("/openBVE/CompatibilitySignals/SpeedLimits");
                if (DocumentNodes != null)
                {
                    foreach (XmlNode nn in DocumentNodes)
                    {
                        try
                        {
                            if (nn.HasChildNodes)
                            {
                                foreach (XmlNode n in nn.ChildNodes)
                                {
                                    if (n.Name != "Aspect")
                                    {
                                        continue;
                                    }

                                    int aspect = 0;
                                    if (n.Attributes != null)
                                    {
                                        if (!NumberFormats.TryParseIntVb6(n.Attributes["Number"].Value, out aspect))
                                        {
                                            currentHost.AddMessage(MessageType.Error, true, "Invalid aspect number " + aspect + " in the speed limit list in the compatability signal file " + fileName);
                                            continue;
                                        }
                                    }

                                    if (aspect <= speedLimits.Length)
                                    {
                                        int l = speedLimits.Length;
                                        Array.Resize(ref speedLimits, aspect + 1);
                                        for (int i = l; i < speedLimits.Length; i++)
                                        {
                                            speedLimits[i] = double.PositiveInfinity;
                                        }

                                        if (!NumberFormats.TryParseDoubleVb6(n.InnerText, out speedLimits[aspect]))
                                        {
                                            speedLimits[aspect] = double.MaxValue;
                                            if (n.InnerText.ToLowerInvariant() != "unlimited")
                                            {
                                                currentHost.AddMessage(MessageType.Error, true, "Invalid speed limit provided for aspect " + aspect + " in the compatability signal file " + fileName);
                                            }
                                        }
                                        else
                                        {
                                            //convert to m/s as that's what we use internally
                                            speedLimits[aspect] *= 0.277777777777778;
                                        }
                                    }
                                }
                            }
                        }
                        catch
                        {
                            currentHost.AddMessage(MessageType.Error, true, "An unexpected error was encountered whilst processing the compatability signal file " + fileName);
                        }
                    }
                }
            }
        }