#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 CodeImp.DoomBuilder.Geometry; #endregion namespace CodeImp.DoomBuilder.UDBScript.Wrapper { internal struct Line2DWrapper { #region ================== Variables /// /// `Vector2D` position of start of the line. /// public Vector2DWrapper v1; /// /// `Vector2D` position of end of the line. /// public Vector2DWrapper v2; #endregion #region ================== Constructors internal Line2DWrapper(Line2D line) { v1 = new Vector2DWrapper(line.v1); v2 = new Vector2DWrapper(line.v2); } /// /// Creates a new `Line2D` from two points. /// ``` /// let line1 = new UDB.Line2D(new Vector2D(32, 64), new Vector2D(96, 128)); /// let line2 = new UDB.Line2D([ 32, 64 ], [ 96, 128 ]); /// ``` /// /// First point /// Second point public Line2DWrapper(object v1, object v2) { try { this.v1 = new Vector2DWrapper(BuilderPlug.Me.GetVector3DFromObject(v1)); this.v2 = new Vector2DWrapper(BuilderPlug.Me.GetVector3DFromObject(v2)); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } #endregion #region ================== Internals internal Line2D AsLine2D() { return new Line2D(v1._x, v1._y, v2._x, v2._y); } #endregion #region ================== Statics /// /// Checks if two lines intersect. If `bounded` is set to `true` (default) the finite length of the lines is used, otherwise the infinite length of the lines is used. /// /// First `Line2D` /// Second `Line2D` /// `true` to use finite length of lines, `false` to use infinite length of lines /// `true` if the lines intersect, `false` if they do not public static bool areIntersecting(Line2DWrapper line1, Line2DWrapper line2, bool bounded=true) { double u_ray; return Line2D.GetIntersection(line1.v1.AsVector2D(), line1.v2.AsVector2D(), line2.v1._x, line2.v1._y, line2.v2._x, line2.v2._y, out u_ray, bounded); } /// /// Checks if two lines defined by their start and end points intersect. If `bounded` is set to `true` (default) the finite length of the lines is used, otherwise the infinite length of the lines is used. /// /// First point of first line /// Second point of first line /// First point of second line /// Second point of second line /// `true` (default) to use finite length of lines, `false` to use infinite length of lines /// `true` if the lines intersect, `false` if they do not public static bool areIntersecting(object a1, object a2, object b1, object b2, bool bounded=true) { try { Vector2D v1 = BuilderPlug.Me.GetVector3DFromObject(a1); Vector2D v2 = BuilderPlug.Me.GetVector3DFromObject(a2); Vector2D v3 = BuilderPlug.Me.GetVector3DFromObject(b1); Vector2D v4 = BuilderPlug.Me.GetVector3DFromObject(b2); double u_ray; return Line2D.GetIntersection(v1, v2, v3.x, v3.y, v4.x, v4.y, out u_ray, bounded); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } /// /// Returns the intersection point of two lines as `Vector2D`. If the lines do not intersect the `x` and `y` properties of the `Vector2D` are `NaN`. If `bounded` is set to `true` (default) the finite length of the lines is used, otherwise the infinite length of the lines is used. /// /// First point of first line /// Second point of first line /// First point of second line /// Second point of second line /// `true` (default) to use finite length of lines, `false` to use infinite length of lines /// The intersection point as `Vector2D` public static Vector2DWrapper getIntersectionPoint(object a1, object a2, object b1, object b2, bool bounded = true) { try { Vector2D v1 = BuilderPlug.Me.GetVector3DFromObject(a1); Vector2D v2 = BuilderPlug.Me.GetVector3DFromObject(a2); Vector2D v3 = BuilderPlug.Me.GetVector3DFromObject(b1); Vector2D v4 = BuilderPlug.Me.GetVector3DFromObject(b2); return new Vector2DWrapper(Line2D.GetIntersectionPoint(new Line2D(v1, v2), new Line2D(v3, v4), bounded)); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } /// /// Returns which the of the line defined by its start and end point a given point is on. /// /// First point of the line /// Second point of the line /// Point to check /// `< 0` if `p` is on the front (right) side, `> 0` if `p` is on the back (left) side, `== 0` if `p` in on the line public static double getSideOfLine(object v1, object v2, object p) { try { Vector2D v11 = BuilderPlug.Me.GetVector3DFromObject(v1); Vector2D v21 = BuilderPlug.Me.GetVector3DFromObject(v2); Vector2D p1 = BuilderPlug.Me.GetVector3DFromObject(p); return Line2D.GetSideOfLine(v11, v21, p1); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } /// /// Returns the shortest distance from point `p` to the line defined by its start and end points. If `bounded` is set to `true` (default) the finite length of the lines is used, otherwise the infinite length of the lines is used. /// /// First point of the line /// Second point of the line /// Point to get the distance to /// `true` (default) to use finite length of lines, `false` to use infinite length of lines /// The shortest distance to the line public static double getDistanceToLine(object v1, object v2, object p, bool bounded=true) { try { Vector2D v11 = BuilderPlug.Me.GetVector3DFromObject(v1); Vector2D v21 = BuilderPlug.Me.GetVector3DFromObject(v2); Vector2D p1 = BuilderPlug.Me.GetVector3DFromObject(p); return Line2D.GetDistanceToLine(v11, v21, p1, bounded); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } /// /// Returns the shortest square distance from point `p` to the line defined by its start and end points. If `bounded` is set to `true` (default) the finite length of the lines is used, otherwise the infinite length of the lines is used. /// /// First point of the line /// Second point of the line /// Point to get the distance to /// `true` (default) to use finite length of lines, `false` to use infinite length of lines /// The shortest square distance to the line public static double getDistanceToLineSq(object v1, object v2, object p, bool bounded = true) { try { Vector2D v11 = BuilderPlug.Me.GetVector3DFromObject(v1); Vector2D v21 = BuilderPlug.Me.GetVector3DFromObject(v2); Vector2D p1 = BuilderPlug.Me.GetVector3DFromObject(p); return Line2D.GetDistanceToLineSq(v11, v21, p1, bounded); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } /// /// Returns the offset coordinate on the line nearest to the given point. `0.0` being on the first point, `1.0` being on the second point, and `u = 0.5` being in the middle between the points. /// /// First point of the line /// Second point of the line /// Point to get the nearest offset coordinate from /// The offset value relative to the first point of the line. public static double getNearestOnLine(object v1, object v2, object p) { try { Vector2D v11 = BuilderPlug.Me.GetVector3DFromObject(v1); Vector2D v21 = BuilderPlug.Me.GetVector3DFromObject(v2); Vector2D p1 = BuilderPlug.Me.GetVector3DFromObject(p); return Line2D.GetNearestOnLine(v11, v21, p1); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } /// /// Returns the coordinate on a line defined by its start and end points as `Vector2D`. /// /// First point of the line /// Second point of the line /// Offset coordinate relative to the first point of the line /// Point on the line as `Vector2D` public static Vector2DWrapper getCoordinatesAt(object v1, object v2, double u) { try { Vector2D v11 = BuilderPlug.Me.GetVector3DFromObject(v1); Vector2D v21 = BuilderPlug.Me.GetVector3DFromObject(v2); return new Vector2DWrapper(Line2D.GetCoordinatesAt(v11, v21, u)); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } #endregion #region ================== Methods /// /// Returns the coordinates on the line, where `u` is the position between the first and second point, `u = 0.0` being on the first point, `u = 1.0` being on the second point, and `u = 0.5` being in the middle between the points. /// /// Position on the line, between 0.0 and 1.0 /// Position on the line as `Vector2D` public Vector2DWrapper getCoordinatesAt(double u) { return new Vector2DWrapper(new Line2D(v1._x, v1._y, v2._x, v2._y).GetCoordinatesAt(u)); } /// /// Returns the length of the `Line2D`. /// /// Length of the `Line2D` public double getLength() { return Line2D.GetLength(v2._x - v1._x, v2._y - v1._y); } /// /// Returns the angle of the `Line2D` in radians. /// /// Angle of `Line2D` in radians public double getAngleRad() { return new Line2D(v1.AsVector2D(), v2.AsVector2D()).GetAngle(); } /// /// Return the angle of the `Line2D` in degrees. /// /// Angle of the `Line2D` in degrees public double getAngle() { return Angle2D.RadToDeg(new Line2D(v1.AsVector2D(), v2.AsVector2D()).GetAngle()); } /// /// Returns the perpendicular of this line as `Vector2D`. /// /// Perpendicular of this line as `Vector2D` public Vector2DWrapper getPerpendicular() { return new Vector2DWrapper(new Line2D(v1._x, v1._y, v2._x, v2._y).GetPerpendicular()); } /// /// Checks if the given `Line2D` intersects this line. If `bounded` is set to `true` (default) the finite length of the lines is used, otherwise the infinite length of the lines is used. /// /// `Line2D` to check against /// `true` (default) to use finite length of lines, `false` to use infinite length of lines /// `true` if lines intersect, `false` if they do not intersect public bool isIntersecting(Line2DWrapper ray, bool bounded=true) { double u_ray; return AsLine2D().GetIntersection(ray.v1._x, ray.v1._y, ray.v2._x, ray.v2._y, out u_ray, bounded); } /// /// Checks if the given line intersects this line. If `bounded` is set to `true` (default) the finite length of the lines is used, otherwise the infinite length of the lines is used. /// /// First point of the line to check against /// Second point of the line to check against /// `true` (default) to use finite length of lines, `false` to use infinite length of lines /// `true` if the lines intersect, `false` if they do not public bool isIntersecting(object a1, object a2, bool bounded = true) { try { Vector2D v3 = BuilderPlug.Me.GetVector3DFromObject(a1); Vector2D v4 = BuilderPlug.Me.GetVector3DFromObject(a2); double u_ray; return AsLine2D().GetIntersection(v3.x, v3.y, v4.x, v4.y, out u_ray, bounded); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } /// /// Returns the intersection point of of the given line defined by its start and end points with this line as `Vector2D`. If the lines do not intersect the `x` and `y` properties of the `Vector2D` are `NaN`. If `bounded` is set to `true` (default) the finite length of the lines is used, otherwise the infinite length of the lines is used. /// /// First point of first line /// Second point of first line /// `true` (default) to use finite length of lines, `false` to use infinite length of lines /// The intersection point as `Vector2D` public Vector2DWrapper getIntersectionPoint(object a1, object a2, bool bounded = true) { try { Vector2D v3 = BuilderPlug.Me.GetVector3DFromObject(a1); Vector2D v4 = BuilderPlug.Me.GetVector3DFromObject(a2); Line2D line = AsLine2D(); double u_ray; line.GetIntersection(v3.x, v3.y, v4.x, v4.y, out u_ray, bounded); return new Vector2DWrapper(line.GetCoordinatesAt(u_ray)); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } /// /// Returns the intersection point of of the given line with this line as `Vector2D`. If the lines do not intersect the `x` and `y` properties of the `Vector2D` are `NaN`. If `bounded` is set to `true` (default) the finite length of the lines is used, otherwise the infinite length of the lines is used. /// /// Other `Line2D` to get the intersection point from /// `true` (default) to use finite length of lines, `false` to use infinite length of lines /// The intersection point as `Vector2D` public Vector2DWrapper getIntersectionPoint(Line2DWrapper ray, bool bounded=true) { Line2D thisline = AsLine2D(); Line2D otherline = ray.AsLine2D(); double u_ray; thisline.GetIntersection(otherline, out u_ray, bounded); return new Vector2DWrapper(thisline.GetCoordinatesAt(u_ray)); } /// /// Returns which the of the line defined by its start and end point a given point is on. /// /// Point to check /// `< 0` if `p` is on the front (right) side, `> 0` if `p` is on the back (left) side, `== 0` if `p` in on the line public double getSideOfLine(object p) { try { Vector2D p1 = BuilderPlug.Me.GetVector3DFromObject(p); return AsLine2D().GetSideOfLine(p1); } catch (CantConvertToVectorException e) { throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException(e.Message); } } public override string ToString() { return AsLine2D().ToString(); } #endregion } }