#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
}
}