Skip to main content

Vector3Unity.zero

using System;
using System.IO;
using System.Diagnostics;

#if !(UNITY_STANDALONE || UNITY_EDITOR)
using System.Numerics;
#endif


class Testing
{
    string logFile;
    int sampleCount;

    public Testing(string logFile, int sampleCount)
    {
        this.logFile = logFile;
        this.sampleCount = sampleCount;
    }

    /// <summary>
    /// Complete copy of Unity3D Vector3 struct
    /// </summary>
    public void TestVector3UnityCustom()
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();

        Stopwatch watch = new Stopwatch();
        float x = 2;

        //Results
        long msPlusEqualProp = -1;
        long msManualAdd = -1;
        long msPlusEqualVar = -1;
        long msManualAddNonProp = -1;
        long msMulVar = -1;
        long msMulConst = -1;


        Vector3Unity res = Vector3Unity.one;
        watch.Reset();
        watch.Start();
        for (int i = 0; i < sampleCount; i++)
        {
            res += Vector3Unity.one;
        }
        watch.Stop();
        msPlusEqualProp = watch.ElapsedMilliseconds;

        res = Vector3Unity.one;
        watch.Reset();
        watch.Start();
        for (int i = 0; i < sampleCount; i++)
        {
            res.x += Vector3Unity.one.x;
            res.y += Vector3Unity.one.y;
            res.z += Vector3Unity.one.z;
        }
        watch.Stop();
        msManualAdd = watch.ElapsedMilliseconds;

        res = Vector3Unity.one;
        watch.Reset();
        watch.Start();
        Vector3Unity toAdd = Vector3Unity.one;
        for (int i = 0; i < sampleCount; i++)
        {
            res += toAdd;
        }
        watch.Stop();
        msPlusEqualVar = watch.ElapsedMilliseconds;

        res = Vector3Unity.one;
        watch.Reset();
        watch.Start();
        toAdd = Vector3Unity.one;
        for (int i = 0; i < sampleCount; i++)
        {
            res.x += toAdd.x;
            res.y += toAdd.y;
            res.z += toAdd.z;
        }
        watch.Stop();
        msManualAddNonProp = watch.ElapsedMilliseconds;

        res = Vector3Unity.one;
        watch.Reset();
        watch.Start();
        for (int i = 0; i < sampleCount; i++)
        {
            res *= x;
        }
        watch.Stop();
        msMulVar = watch.ElapsedMilliseconds;

        res = Vector3Unity.one;
        watch.Reset();
        watch.Start();
        for (int i = 0; i < sampleCount; i++)
        {
            res *= 2;
        }
        watch.Stop();
        msMulConst = watch.ElapsedMilliseconds;

        File.AppendAllText(logFile, "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= UnityEngine.Vector3 COPY =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\r\n");
        File.AppendAllText(logFile, "Test: res += Vector3.one: " + msPlusEqualProp + " ms\r\n");
        File.AppendAllText(logFile, "Test: Manual Add: " + msManualAdd + " ms\r\n");
        File.AppendAllText(logFile, "Test: res += res: " + msPlusEqualVar + " ms\r\n");
        File.AppendAllText(logFile, "Test: Manual Add (non-property): " + msManualAddNonProp + " ms\r\n");
        File.AppendAllText(logFile, "Test: Vector3 => res *= x: " + msMulVar + " ms\r\n");
        File.AppendAllText(logFile, "Test: Vector3 => res *= const: " + msMulVar + " ms\r\n");

        File.AppendAllText(logFile, "\r\n");
    }

    public void TestVector3Numerics()
    {
#if !(UNITY_STANDALONE || UNITY_EDITOR)
        GC.Collect();
        GC.WaitForPendingFinalizers();

        //Results
        long msPlusEqualProp = -1;
        long msManualAdd = -1;
        long msPlusEqualVar = -1;
        long msManualAddNonProp = -1;
        long msMulVar = -1;
        long msMulConst = -1;

        Stopwatch watch = new Stopwatch();
        float x = 2;

        Vector3 res = Vector3.One;
        watch.Reset();
        watch.Start();
        for (int i = 0; i < sampleCount; i++)
        {
            res += Vector3.One;
        }
        watch.Stop();
        msPlusEqualProp = watch.ElapsedMilliseconds;

        res = Vector3.One;
        watch.Reset();
        watch.Start();
        for (int i = 0; i < sampleCount; i++)
        {
            res.X += Vector3.One.X;
            res.Y += Vector3.One.Y;
            res.Z += Vector3.One.Z;
        }
        watch.Stop();
        msManualAdd = watch.ElapsedMilliseconds;

        res = Vector3.One;
        watch.Reset();
        watch.Start();
        Vector3 toAdd = Vector3.One;
        for (int i = 0; i < sampleCount; i++)
        {
            res += toAdd;
        }
        watch.Stop();
        msPlusEqualVar = watch.ElapsedMilliseconds;

        res = Vector3.One;
        watch.Reset();
        watch.Start();
        toAdd = Vector3.One;
        for (int i = 0; i < sampleCount; i++)
        {
            res.X += toAdd.X;
            res.Y += toAdd.Y;
            res.Z += toAdd.Z;
        }
        watch.Stop();
        msManualAddNonProp = watch.ElapsedMilliseconds;

        res = Vector3.One;
        watch.Reset();
        watch.Start();
        for (int i = 0; i < sampleCount; i++)
        {
            res *= x;
        }
        watch.Stop();
        msMulVar = watch.ElapsedMilliseconds;

        res = Vector3.One;
        watch.Reset();
        watch.Start();
        for (int i = 0; i < sampleCount; i++)
        {
            res *= 2;
        }
        watch.Stop();
        msMulConst = watch.ElapsedMilliseconds;

        File.AppendAllText(logFile, "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= System.Numerics.Vector3 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\r\n");

        File.AppendAllText(logFile, "res => res += Vector3.One: " + msPlusEqualProp + " ms\r\n");
        File.AppendAllText(logFile, "Test: res => Manual Add: " + msManualAdd + " ms\r\n");
        File.AppendAllText(logFile, "Test: vec += vec " + msPlusEqualVar + " ms\r\n");
        File.AppendAllText(logFile, "Test: Vector3 => Manual Add (non-property) " + msManualAddNonProp + " ms\r\n");
        File.AppendAllText(logFile, "Test: res *= x: " + msMulVar + " ms\r\n");
        File.AppendAllText(logFile, "Test: res *= const: " + msMulConst + " ms\r\n");

        File.AppendAllText(logFile, "\r\n");
#else
        File.AppendAllText(logFile, "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= System.Numerics.Vector3 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\r\n");

        File.AppendAllText(logFile, "System.Numerics not available in Unity3D\r\n");
        File.AppendAllText(logFile, "\r\n");
#endif
    }

    public void TestVector3Unity()
    {
#if UNITY_STANDALONE || UNTY_EDITOR
        GC.Collect();
        GC.WaitForPendingFinalizers();

        //Results
        long msPlusEqualProp = -1;
        long msManualAdd = -1;
        long msPlusEqualVar = -1;
        long msManualAddNonProp = -1;
        long msMulVar = -1;
        long msMulConst = -1;

        Stopwatch watch = new Stopwatch();
        float x = 2;

        UnityEngine.Vector3 res = UnityEngine.Vector3.one;
        watch.Reset();
        watch.Start();
        for (int i = 0; i < sampleCount; i++)
        {
            res += UnityEngine.Vector3.one;
        }
        watch.Stop();
        msPlusEqualProp = watch.ElapsedMilliseconds;

        res = UnityEngine.Vector3.one;
        watch.Reset();
        watch.Start();
        for (int i = 0; i < sampleCount; i++)
        {
            res.x += UnityEngine.Vector3.one.x;
            res.y += UnityEngine.Vector3.one.y;
            res.z += UnityEngine.Vector3.one.z;
        }
        watch.Stop();
        msManualAdd = watch.ElapsedMilliseconds;

        res = UnityEngine.Vector3.one;
        watch.Reset();
        watch.Start();
        UnityEngine.Vector3 toAdd = UnityEngine.Vector3.one;
        for (int i = 0; i < sampleCount; i++)
        {
            res += toAdd;
        }
        watch.Stop();
        msPlusEqualVar = watch.ElapsedMilliseconds;

        res = UnityEngine.Vector3.one;
        watch.Reset();
        watch.Start();
        toAdd = UnityEngine.Vector3.one;
        for (int i = 0; i < sampleCount; i++)
        {
            res.x += toAdd.x;
            res.y += toAdd.y;
            res.z += toAdd.z;
        }
        watch.Stop();
        msManualAddNonProp = watch.ElapsedMilliseconds;

        res = UnityEngine.Vector3.one;
        watch.Reset();
        watch.Start();
        for (int i = 0; i < sampleCount; i++)
        {
            res *= x;
        }
        watch.Stop();
        msMulVar = watch.ElapsedMilliseconds;

        res = UnityEngine.Vector3.one;
        watch.Reset();
        watch.Start();
        for (int i = 0; i < sampleCount; i++)
        {
            res *= 2;
        }
        watch.Stop();
        msMulConst = watch.ElapsedMilliseconds;

        File.AppendAllText(logFile, "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= System.Numerics.UnityEngine.Vector3 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\r\n");

        File.AppendAllText(logFile, "res => res += UnityEngine.Vector3.one: " + msPlusEqualProp + " ms\r\n");
        File.AppendAllText(logFile, "Test: res => Manual Add: " + msManualAdd + " ms\r\n");
        File.AppendAllText(logFile, "Test: vec += vec " + msPlusEqualVar + " ms\r\n");
        File.AppendAllText(logFile, "Test: UnityEngine.Vector3 => Manual Add (non-property) " + msManualAddNonProp + " ms\r\n");
        File.AppendAllText(logFile, "Test: res *= x: " + msMulVar + " ms\r\n");
        File.AppendAllText(logFile, "Test: res *= const: " + msMulConst + " ms\r\n");

        File.AppendAllText(logFile, "\r\n");
#else
        File.AppendAllText(logFile, "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= UnityEngine.Vector3 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\r\n");

        File.AppendAllText(logFile, "Unity3D Not found...\r\n");
        File.AppendAllText(logFile, "\r\n");
#endif
    }

    public void TestAll()
    {
        File.WriteAllText(logFile, "Samples: " + sampleCount + "\r\n");
        File.AppendAllText(logFile, "CLR Version: " + Environment.Version + "\r\n");
        File.AppendAllText(logFile, "Runtime Version: " + (typeof(string).Assembly.ImageRuntimeVersion) + "\r\n");
        File.AppendAllText(logFile, "Is Mono: " + (Type.GetType("Mono.Runtime") != null) + "\r\n");
        File.AppendAllText(logFile, "Is Unity3D: " + this.IsUnity() + "\r\n");
        File.AppendAllText(logFile, "Is Unity3D Editor: " + this.IsUnityEditor() + "\r\n");

        TestVector3UnityCustom();
        TestVector3Numerics();
        TestVector3Unity();
    }

    private bool IsUnity()
    {
#if UNITY_STANDALONE || UNITY_EDITOR
        return true;
#else
        return false;
#endif
    }

    private bool IsUnityEditor()
    {
#if UNITY_EDITOR
        return true;
#else
        return false;
#endif
    }
}

public struct Vector3Unity
{
    private static readonly Vector3Unity zeroVector = new Vector3Unity(0.0f, 0.0f, 0.0f);
    private static readonly Vector3Unity oneVector = new Vector3Unity(1f, 1f, 1f);
    private static readonly Vector3Unity upVector = new Vector3Unity(0.0f, 1f, 0.0f);
    private static readonly Vector3Unity downVector = new Vector3Unity(0.0f, -1f, 0.0f);
    private static readonly Vector3Unity leftVector = new Vector3Unity(-1f, 0.0f, 0.0f);
    private static readonly Vector3Unity rightVector = new Vector3Unity(1f, 0.0f, 0.0f);
    private static readonly Vector3Unity forwardVector = new Vector3Unity(0.0f, 0.0f, 1f);
    private static readonly Vector3Unity backVector = new Vector3Unity(0.0f, 0.0f, -1f);
    private static readonly Vector3Unity positiveInfinityVector = new Vector3Unity(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
    private static readonly Vector3Unity negativeInfinityVector = new Vector3Unity(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);
    public const float kEpsilon = 1E-05f;
    /// <summary>
    ///   <para>X component of the vector.</para>
    /// </summary>
    public float x;
    /// <summary>
    ///   <para>Y component of the vector.</para>
    /// </summary>
    public float y;
    /// <summary>
    ///   <para>Z component of the vector.</para>
    /// </summary>
    public float z;

    public float this[int index]
    {
        get
        {
            switch (index)
            {
                case 0:
                    return this.x;
                case 1:
                    return this.y;
                case 2:
                    return this.z;
                default:
                    throw new IndexOutOfRangeException("Invalid Vector3 index!");
            }
        }
        set
        {
            switch (index)
            {
                case 0:
                    this.x = value;
                    break;
                case 1:
                    this.y = value;
                    break;
                case 2:
                    this.z = value;
                    break;
                default:
                    throw new IndexOutOfRangeException("Invalid Vector3 index!");
            }
        }
    }

    /// <summary>
    ///   <para>Returns this vector with a magnitude of 1 (Read Only).</para>
    /// </summary>
    public Vector3Unity normalized
    {
        get
        {
            return Vector3Unity.Normalize(this);
        }
    }

    /// <summary>
    ///   <para>Returns the length of this vector (Read Only).</para>
    /// </summary>
    public float magnitude
    {
        get
        {
            return (float)Math.Sqrt(x * x + y * y + z * z);
        }
    }

    /// <summary>
    ///   <para>Returns the squared length of this vector (Read Only).</para>
    /// </summary>
    public float sqrMagnitude
    {
        get
        {
            return x * x + y * y + z * z;
        }
    }

    /// <summary>
    ///   <para>Shorthand for writing Vector3(0, 0, 0).</para>
    /// </summary>
    public static Vector3Unity zero
    {
        get
        {
            return Vector3Unity.zeroVector;
        }
    }

    /// <summary>
    ///   <para>Shorthand for writing Vector3(1, 1, 1).</para>
    /// </summary>
    public static Vector3Unity one
    {
        get
        {
            return Vector3Unity.oneVector;
        }
    }

    /// <summary>
    ///   <para>Shorthand for writing Vector3(0, 0, 1).</para>
    /// </summary>
    public static Vector3Unity forward
    {
        get
        {
            return Vector3Unity.forwardVector;
        }
    }

    /// <summary>
    ///   <para>Shorthand for writing Vector3(0, 0, -1).</para>
    /// </summary>
    public static Vector3Unity back
    {
        get
        {
            return Vector3Unity.backVector;
        }
    }

    /// <summary>
    ///   <para>Shorthand for writing Vector3(0, 1, 0).</para>
    /// </summary>
    public static Vector3Unity up
    {
        get
        {
            return Vector3Unity.upVector;
        }
    }

    /// <summary>
    ///   <para>Shorthand for writing Vector3(0, -1, 0).</para>
    /// </summary>
    public static Vector3Unity down
    {
        get
        {
            return Vector3Unity.downVector;
        }
    }

    /// <summary>
    ///   <para>Shorthand for writing Vector3(-1, 0, 0).</para>
    /// </summary>
    public static Vector3Unity left
    {
        get
        {
            return Vector3Unity.leftVector;
        }
    }

    /// <summary>
    ///   <para>Shorthand for writing Vector3(1, 0, 0).</para>
    /// </summary>
    public static Vector3Unity right
    {
        get
        {
            return Vector3Unity.rightVector;
        }
    }

    /// <summary>
    ///   <para>Shorthand for writing Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity).</para>
    /// </summary>
    public static Vector3Unity positiveInfinity
    {
        get
        {
            return Vector3Unity.positiveInfinityVector;
        }
    }

    /// <summary>
    ///   <para>Shorthand for writing Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity).</para>
    /// </summary>
    public static Vector3Unity negativeInfinity
    {
        get
        {
            return Vector3Unity.negativeInfinityVector;
        }
    }

    [Obsolete("Use Vector3.forward instead.")]
    public static Vector3Unity fwd
    {
        get
        {
            return new Vector3Unity(0.0f, 0.0f, 1f);
        }
    }

    /// <summary>
    ///   <para>Creates a new vector with given x, y, z components.</para>
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <param name="z"></param>
    public Vector3Unity(float x, float y, float z)
    {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    /// <summary>
    ///   <para>Creates a new vector with given x, y components and sets z to zero.</para>
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    public Vector3Unity(float x, float y)
    {
        this.x = x;
        this.y = y;
        this.z = 0.0f;
    }

    public static Vector3Unity operator +(Vector3Unity a, Vector3Unity b)
    {
        return new Vector3Unity(a.x + b.x, a.y + b.y, a.z + b.z);
    }

    public static Vector3Unity operator -(Vector3Unity a, Vector3Unity b)
    {
        return new Vector3Unity(a.x - b.x, a.y - b.y, a.z - b.z);
    }

    public static Vector3Unity operator -(Vector3Unity a)
    {
        return new Vector3Unity(-a.x, -a.y, -a.z);
    }

    public static Vector3Unity operator *(Vector3Unity a, float d)
    {
        return new Vector3Unity(a.x * d, a.y * d, a.z * d);
    }

    public static Vector3Unity operator *(float d, Vector3Unity a)
    {
        return new Vector3Unity(a.x * d, a.y * d, a.z * d);
    }

    public static Vector3Unity operator /(Vector3Unity a, float d)
    {
        return new Vector3Unity(a.x / d, a.y / d, a.z / d);
    }

    public static bool operator ==(Vector3Unity lhs, Vector3Unity rhs)
    {
        return (double)Vector3Unity.SqrMagnitude(lhs - rhs) < 9.99999943962493E-11;
    }

    public static bool operator !=(Vector3Unity lhs, Vector3Unity rhs)
    {
        return !(lhs == rhs);
    }

    /// <summary>
    ///   <para>Spherically interpolates between two vectors.</para>
    /// </summary>
    /// <param name="a">Dear Unity... EXPLANATON??????</param>
    /// <param name="b">Dear Unity... EXPLANATON??????</param>
    /// <param name="t">Dear Unity... EXPLANATON??????</param>
    public static Vector3Unity Lerp(Vector3Unity a, Vector3Unity b, float t)
    {
        t = (t > 1 ? 1 : t < 0 ? 0 : t); //Clamp T. Use ternary operator, faster than IF-ELSE
        return new Vector3Unity(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t);
    }

    /// <summary>
    ///   <para>Spherically interpolates between two vectors.</para>
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    /// <param name="t"></param>
    public static Vector3Unity LerpUnclamped(Vector3Unity a, Vector3Unity b, float t)
    {
        return new Vector3Unity(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t);
    }

    /// <summary>
    ///   <para>Moves a point current in a straight line towards a target point.</para>
    /// </summary>
    /// <param name="current"></param>
    /// <param name="target"></param>
    /// <param name="maxDistanceDelta"></param>
    public static Vector3Unity MoveTowards(Vector3Unity current, Vector3Unity target, float maxDistanceDelta)
    {
        Vector3Unity vector3 = target - current;
        float magnitude = vector3.magnitude;
        if (magnitude <= maxDistanceDelta || magnitude < 1.40129846432482E-45) return target;
        return current + vector3 / magnitude * maxDistanceDelta;
    }

    /// <summary>
    ///   <para>Set x, y and z components of an existing Vector3.</para>
    /// </summary>
    /// <param name="newX"></param>
    /// <param name="newY"></param>
    /// <param name="newZ"></param>
    public void Set(float newX, float newY, float newZ)
    {
        this.x = newX;
        this.y = newY;
        this.z = newZ;
    }

    /// <summary>
    ///   <para>Multiplies two vectors component-wise.</para>
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    public static Vector3Unity Scale(Vector3Unity a, Vector3Unity b)
    {
        return new Vector3Unity(a.x * b.x, a.y * b.y, a.z * b.z);
    }

    /// <summary>
    ///   <para>Multiplies every component of this vector by the same component of scale.</para>
    /// </summary>
    /// <param name="scale"></param>
    public void Scale(Vector3Unity scale)
    {
        this.x *= scale.x;
        this.y *= scale.y;
        this.z *= scale.z;
    }

    /// <summary>
    ///   <para>Cross Product of two vectors.</para>
    /// </summary>
    /// <param name="lhs"></param>
    /// <param name="rhs"></param>
    public static Vector3Unity Cross(Vector3Unity lhs, Vector3Unity rhs)
    {
        return new Vector3Unity((float)((double)lhs.y * (double)rhs.z - (double)lhs.z * (double)rhs.y), (float)((double)lhs.z * (double)rhs.x - (double)lhs.x * (double)rhs.z), (float)((double)lhs.x * (double)rhs.y - (double)lhs.y * (double)rhs.x));
    }

    public override int GetHashCode()
    {
        return this.x.GetHashCode() ^ this.y.GetHashCode() << 2 ^ this.z.GetHashCode() >> 2;
    }

    /// <summary>
    ///   <para>Returns true if the given vector is exactly equal to this vector.</para>
    /// </summary>
    /// <param name="other"></param>
    public override bool Equals(object other)
    {
        if (!(other is Vector3Unity))
            return false;
        Vector3Unity vector3 = (Vector3Unity)other;
        return this.x.Equals(vector3.x) && this.y.Equals(vector3.y) && this.z.Equals(vector3.z);
    }

    /// <summary>
    ///   <para>Reflects a vector off the plane defined by a normal.</para>
    /// </summary>
    /// <param name="inDirection"></param>
    /// <param name="inNormal"></param>
    public static Vector3Unity Reflect(Vector3Unity inDirection, Vector3Unity inNormal)
    {
        return -2f * Vector3Unity.Dot(inNormal, inDirection) * inNormal + inDirection;
    }

    /// <summary>
    ///   <para>Makes this vector have a magnitude of 1.</para>
    /// </summary>
    /// <param name="value"></param>
    public static Vector3Unity Normalize(Vector3Unity value)
    {
        float num = Vector3Unity.Magnitude(value);
        if ((double)num > 9.99999974737875E-06)
            return value / num;
        return Vector3Unity.zero;
    }

    public void Normalize()
    {
        float num = Vector3Unity.Magnitude(this);
        if ((double)num > 9.99999974737875E-06)
            this = this / num;
        else
            this = Vector3Unity.zero;
    }

    /// <summary>
    ///   <para>Dot Product of two vectors.</para>
    /// </summary>
    /// <param name="lhs"></param>
    /// <param name="rhs"></param>
    public static float Dot(Vector3Unity lhs, Vector3Unity rhs)
    {
        return (float)((double)lhs.x * (double)rhs.x + (double)lhs.y * (double)rhs.y + (double)lhs.z * (double)rhs.z);
    }


    public static float Magnitude(Vector3Unity vector)
    {
        return vector.magnitude;
    }

    public static float SqrMagnitude(Vector3Unity vector)
    {
        return vector.sqrMagnitude;
    }
}