#region ================== Copyright (c) 2021 Boris Iwanski /* * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the * * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program.If not, see. */ #endregion #region ================== Namespaces using System.Dynamic; using CodeImp.DoomBuilder.Geometry; using CodeImp.DoomBuilder.Map; #endregion namespace CodeImp.DoomBuilder.UDBScript.Wrapper { internal struct Vector2DWrapper { #region ================== Variables public double _x; public double _y; private readonly MapElement parent; #endregion #region ================== Properties /// /// The `x` value of the vector. /// public double x { get { return _x; } set { _x = value; if (parent is Vertex) ((Vertex)parent).Move(new Vector2D(_x, _y)); else if (parent is Thing) ((Thing)parent).Move(new Vector2D(_x, _y)); } } /// /// The `y` value of the vector. /// public double y { get { return _y; } set { _y = value; if (parent is Vertex) ((Vertex)parent).Move(new Vector2D(_x, _y)); else if (parent is Thing) ((Thing)parent).Move(new Vector2D(_x, _y)); } } #endregion #region ================== Constructors internal Vector2DWrapper(Vector2D v, MapElement parent = null) { _x = v.x; _y = v.y; this.parent = parent; } internal Vector2DWrapper(double x, double y, MapElement parent) { _x = x; _y = y; this.parent = parent; } /// /// Creates a new `Vector2D` from x and y coordinates /// ``` /// let v = new UDB.Vector2D(32, 64); /// ``` /// /// The x coordinate /// The y coordinate public Vector2DWrapper(double x, double y) { this._x = x; this._y = y; parent = null; } /// /// Creates a new `Vector2D` from a point. /// ``` /// let v = new UDB.Vector2D([ 32, 64 ]); /// ``` /// /// The vector to create the `Vector2D` from public Vector2DWrapper(object v) { try { Vector2D v1 = BuilderPlug.Me.GetVector3DFromObject(v); _x = v1.x; _y = v1.y; parent = null; } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } #endregion #region ================== Internal internal Vector2D AsVector2D() { return new Vector2D(_x, _y); } #endregion #region ================== Operators public static implicit operator Vector3DWrapper(Vector2DWrapper a) { return new Vector3DWrapper(a._x, a._y, 0.0); } #region ================== Addition public static object operator +(Vector2DWrapper lhs, object rhs) { if (rhs is double) { return new Vector2DWrapper(lhs._x + (double)rhs, lhs._y + (double)rhs); } else if (rhs.GetType().IsArray || rhs is ExpandoObject || rhs is Vector2DWrapper || rhs is Vector3DWrapper) { try { Vector2D v = BuilderPlug.Me.GetVector3DFromObject(rhs); return new Vector2DWrapper(lhs._x + v.x, lhs._y + v.y); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } else { return lhs.ToString() + rhs.ToString(); } } public static object operator +(object lhs, Vector2DWrapper rhs) { if (lhs is double) { return new Vector2DWrapper((double)lhs + rhs._x, (double)lhs + rhs._y); } else if (lhs.GetType().IsArray || lhs is ExpandoObject || lhs is Vector2DWrapper || lhs is Vector3DWrapper) { try { Vector2D v = BuilderPlug.Me.GetVector3DFromObject(lhs); return new Vector2DWrapper(v.x + rhs._x, v.y + rhs._y); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } else { return lhs.ToString() + rhs.ToString(); } } #endregion #region ================== Subtraction public static object operator -(Vector2DWrapper lhs, object rhs) { if (rhs is double) return new Vector2DWrapper(lhs._x - (double)rhs, lhs._y - (double)rhs); try { Vector2D v = BuilderPlug.Me.GetVector3DFromObject(rhs); return new Vector2DWrapper(lhs._x - v.x, lhs._y - v.y); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } public static object operator -(object lhs, Vector2DWrapper rhs) { if (lhs is double) return new Vector2DWrapper((double)lhs - rhs._x, (double)lhs - rhs._y); try { Vector2D v = BuilderPlug.Me.GetVector3DFromObject(lhs); return new Vector2DWrapper(v.x - rhs._x, v.y - rhs._y); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } public static Vector2DWrapper operator -(Vector2DWrapper a) { return new Vector2DWrapper(-a._x, -a._y); } #endregion #region ================== Multiply public static object operator *(Vector2DWrapper lhs, object rhs) { if (rhs is double) return new Vector2DWrapper(lhs._x * (double)rhs, lhs._y * (double)rhs); try { Vector2D v = BuilderPlug.Me.GetVector3DFromObject(rhs); return new Vector2DWrapper(lhs._x * v.x, lhs._y * v.y); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } public static object operator *(object lhs, Vector2DWrapper rhs) { if (lhs is double) return new Vector2DWrapper((double)lhs * rhs._x, (double)lhs * rhs._y); try { Vector2D v = BuilderPlug.Me.GetVector3DFromObject(lhs); return new Vector2DWrapper(v.x * rhs._x, v.y * rhs._y); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } #endregion #region ================== Divide public static object operator /(Vector2DWrapper lhs, object rhs) { if (rhs is double) return new Vector2DWrapper(lhs._x / (double)rhs, lhs._y / (double)rhs); try { Vector2D v = BuilderPlug.Me.GetVector3DFromObject(rhs); return new Vector2DWrapper(lhs._x / v.x, lhs._y / v.y); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } public static object operator /(object lhs, Vector2DWrapper rhs) { if (lhs is double) return new Vector2DWrapper(rhs._x / (double)lhs, rhs._y / (double)lhs); try { Vector2D v = BuilderPlug.Me.GetVector3DFromObject(lhs); return new Vector2DWrapper(v.x / rhs._x, v.y / rhs._y); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } #endregion #region ================== Equality public static bool operator ==(Vector2DWrapper lhs, object rhs) { try { Vector2D v1 = BuilderPlug.Me.GetVector3DFromObject(rhs); return (lhs._x == v1.x) && (lhs._y == v1.y); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } public static bool operator ==(object lhs, Vector2DWrapper rhs) { try { Vector2D v1 = BuilderPlug.Me.GetVector3DFromObject(lhs); return (v1.x == rhs._x) && (v1.y == rhs._y); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } public static bool operator !=(Vector2DWrapper lhs, object rhs) { try { Vector2D v1 = BuilderPlug.Me.GetVector3DFromObject(rhs); return (lhs._x != v1.x) || (lhs._y != v1.y); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } public static bool operator !=(object lhs, Vector2DWrapper rhs) { try { Vector2D v1 = BuilderPlug.Me.GetVector3DFromObject(lhs); return (v1.x != rhs._x) || (v1.y != rhs._y); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } #endregion #endregion #region ================== Statics /// /// Returns the dot product of two `Vector2D`s. /// /// First `Vector2D` /// Second `Vector2D` /// The dot product of the two vectors public static double dotProduct(Vector2DWrapper a, Vector2DWrapper b) { // Calculate and return the dot product return a._x * b._x + a._y * b._y; } /// /// Returns the cross product of two `Vector2D`s. /// /// First `Vector2D` /// Second `Vector2D` /// Cross product of the two vectors as `Vector2D` public static Vector2DWrapper crossProduct(object a, object b) { try { Vector2D a1 = BuilderPlug.Me.GetVector3DFromObject(a); Vector2D b1 = BuilderPlug.Me.GetVector3DFromObject(b); return new Vector2DWrapper(a1.y * b1.x, a1.x * b1.y); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } /// /// Reflects a `Vector2D` over a mirror `Vector2D`. /// /// `Vector2D` to reflect /// Mirror `Vector2D` /// The reflected vector as `Vector2D` public static Vector2DWrapper reflect(object v, object m) { try { Vector2D v1 = BuilderPlug.Me.GetVector3DFromObject(v); Vector2D m1 = BuilderPlug.Me.GetVector3DFromObject(m); Vector2D mv = Vector2D.Reflect(v1, m1); return new Vector2DWrapper(mv.x, mv.y); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } /// /// Returns a reversed `Vector2D`. /// /// `Vector2D` to reverse /// The reversed vector as `Vector2D` public static Vector2DWrapper reversed(object v) { try { Vector2D v1 = BuilderPlug.Me.GetVector3DFromObject(v); return new Vector2DWrapper(Vector2D.Reversed(v1)); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } /// /// Creates a `Vector2D` from an angle in radians, /// /// Angle in radians /// Vector as `Vector2D` public static Vector2DWrapper fromAngleRad(double angle) { return new Vector2DWrapper(Vector2D.FromAngle(angle)); } /// /// Creates a `Vector2D` from an angle in degrees, /// /// Angle in degrees /// Vector as `Vector2D` public static Vector2DWrapper fromAngle(double angle) { return new Vector2DWrapper(Vector2D.FromAngle(Angle2D.DegToRad(angle))); } /// /// Returns the angle between two `Vector2D`s in radians /// /// First `Vector2D` /// Second `Vector2D` /// Angle in radians public static double getAngleRad(object a, object b) { try { Vector2D a1 = BuilderPlug.Me.GetVector3DFromObject(a); Vector2D b1 = BuilderPlug.Me.GetVector3DFromObject(b); return Vector2D.GetAngle(a1, b1); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } /// /// Returns the angle between two `Vector2D`s in degrees. /// /// First `Vector2D` /// Second `Vector2D` /// Angle in degrees public static double getAngle(object a, object b) { try { Vector2D a1 = BuilderPlug.Me.GetVector3DFromObject(a); Vector2D b1 = BuilderPlug.Me.GetVector3DFromObject(b); return Angle2D.RadToDeg(Vector2D.GetAngle(a1, b1)); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } /// /// Returns the square distance between two `Vector2D`s. /// /// First `Vector2D` /// Second `Vector2D` /// The squared distance public static double getDistanceSq(object a, object b) { try { Vector2D a1 = BuilderPlug.Me.GetVector3DFromObject(a); Vector2D b1 = BuilderPlug.Me.GetVector3DFromObject(b); return Vector2D.DistanceSq(a1, b1); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } /// /// Returns the distance between two `Vector2D`s. /// /// First `Vector2D` /// Second `Vector2D` /// The distance public static double getDistance(object a, object b) { try { Vector2D a1 = BuilderPlug.Me.GetVector3DFromObject(a); Vector2D b1 = BuilderPlug.Me.GetVector3DFromObject(b); return Vector2D.Distance(a1, b1); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } #endregion #region ================== Methods /// /// Returns the perpendicular to the `Vector2D`. /// /// The perpendicular as `Vector2D` public Vector2DWrapper getPerpendicular() { return new Vector2DWrapper(-_y, _x); } /// /// Returns a `Vector2D` with the sign of all components. /// /// A `Vector2D` with the sign of all components public Vector2DWrapper getSign() { return new Vector2DWrapper(new Vector2D(_x, _y).GetSign()); } /// /// Returns the angle of the `Vector2D` in radians. /// /// The angle of the `Vector2D` in radians public double getAngleRad() { return new Vector2D(_x, _y).GetAngle(); } /// /// Returns the angle of the `Vector2D` in degree. /// /// The angle of the `Vector2D` in degree public double getAngle() { return Angle2D.RadToDeg(new Vector2D(_x, _y).GetAngle()); } /// /// Returns the length of the `Vector2D`. /// /// The length of the `Vector2D` public double getLength() { return new Vector2D(_x, _y).GetLength(); } /// /// Returns the square length of the `Vector2D`. /// /// The square length of the `Vector2D` public double getLengthSq() { return new Vector2D(_x, _y).GetLengthSq(); } /// /// Returns the normal of the `Vector2D`. /// /// The normal as `Vector2D` public Vector2DWrapper getNormal() { return new Vector2DWrapper(new Vector2D(_x, _y).GetNormal()); } /// /// Returns the transformed vector as `Vector2D`. /// /// X offset /// Y offset /// X scale /// Y scale /// The transformed vector as `Vector2D` public Vector2DWrapper getTransformed(double offsetx, double offsety, double scalex, double scaley) { return new Vector2DWrapper(new Vector2D(_x, _y).GetTransformed(offsetx, offsety, scalex, scaley)); } /// /// Returns the inverse transformed vector as `Vector2D`. /// /// X offset /// Y offset /// X scale /// Y scale /// The inverse transformed vector as `Vector2D` public Vector2DWrapper getInverseTransformed(double invoffsetx, double invoffsety, double invscalex, double invscaley) { return new Vector2DWrapper(new Vector2D(_x, _y).GetInvTransformed(invoffsetx, invoffsety, invscalex, invscaley)); } /// /// Returns the rotated vector as `Vector2D`. /// /// Angle in degree to rotate by /// The rotated `Vector2D` public Vector2DWrapper getRotated(double theta) { return new Vector2DWrapper(new Vector2D(_x, _y).GetRotated(Angle2D.DegToRad(theta))); } /// /// Returns the rotated vector as `Vector2D`. /// /// Angle in radians to rotate by /// The rotated `Vector2D` public Vector2DWrapper getRotatedRad(double theta) { return new Vector2DWrapper(new Vector2D(_x, _y).GetRotated(theta)); } /// /// Checks if the `Vector2D` is finite or not. /// /// `true` if `Vector2D` is finite, otherwise `false` public bool isFinite() { return new Vector2D(_x, _y).IsFinite(); } public override string ToString() { return new Vector2D(_x, _y).ToString(); } public override int GetHashCode() { return base.GetHashCode(); } public override bool Equals(object obj) { if (!(obj is Vector2DWrapper)) return false; Vector2DWrapper other = (Vector2DWrapper)obj; if (_x != other._x) return false; if (_y != other._y) return false; return true; } #endregion } }