godot/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs

239 lines
5.7 KiB
C#
Raw Normal View History

using System;
2019-08-08 03:29:40 +02:00
using System.Runtime.InteropServices;
#if REAL_T_IS_DOUBLE
using real_t = System.Double;
#else
using real_t = System.Single;
#endif
namespace Godot
{
2019-08-08 03:29:40 +02:00
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Plane : IEquatable<Plane>
{
2018-05-17 17:04:20 +02:00
private Vector3 _normal;
public Vector3 Normal
{
get { return _normal; }
set { _normal = value; }
}
public real_t x
{
get
{
2018-05-17 17:04:20 +02:00
return _normal.x;
}
set
{
2018-05-17 17:04:20 +02:00
_normal.x = value;
}
}
public real_t y
{
get
{
2018-05-17 17:04:20 +02:00
return _normal.y;
}
set
{
2018-05-17 17:04:20 +02:00
_normal.y = value;
}
}
public real_t z
{
get
{
2018-05-17 17:04:20 +02:00
return _normal.z;
}
set
{
2018-05-17 17:04:20 +02:00
_normal.z = value;
}
}
public real_t D { get; set; }
public Vector3 Center
{
get
{
return _normal * D;
}
}
public real_t DistanceTo(Vector3 point)
{
return _normal.Dot(point) - D;
}
2017-11-21 23:32:19 +01:00
public Vector3 GetAnyPoint()
{
return _normal * D;
}
public bool HasPoint(Vector3 point, real_t epsilon = Mathf.Epsilon)
{
real_t dist = _normal.Dot(point) - D;
2017-11-21 23:32:19 +01:00
return Mathf.Abs(dist) <= epsilon;
}
public Vector3? Intersect3(Plane b, Plane c)
{
2018-05-17 17:04:20 +02:00
real_t denom = _normal.Cross(b._normal).Dot(c._normal);
if (Mathf.IsZeroApprox(denom))
return null;
Vector3 result = b._normal.Cross(c._normal) * D +
c._normal.Cross(_normal) * b.D +
_normal.Cross(b._normal) * c.D;
return result / denom;
}
public Vector3? IntersectRay(Vector3 from, Vector3 dir)
{
2018-05-17 17:04:20 +02:00
real_t den = _normal.Dot(dir);
if (Mathf.IsZeroApprox(den))
return null;
real_t dist = (_normal.Dot(from) - D) / den;
// This is a ray, before the emitting pos (from) does not exist
if (dist > Mathf.Epsilon)
return null;
return from + dir * -dist;
}
public Vector3? IntersectSegment(Vector3 begin, Vector3 end)
{
Vector3 segment = begin - end;
2018-05-17 17:04:20 +02:00
real_t den = _normal.Dot(segment);
if (Mathf.IsZeroApprox(den))
return null;
real_t dist = (_normal.Dot(begin) - D) / den;
// Only allow dist to be in the range of 0 to 1, with tolerance.
2018-04-08 05:39:35 +02:00
if (dist < -Mathf.Epsilon || dist > 1.0f + Mathf.Epsilon)
return null;
return begin + segment * -dist;
}
2017-11-21 23:32:19 +01:00
public bool IsPointOver(Vector3 point)
{
return _normal.Dot(point) > D;
}
2017-11-21 23:32:19 +01:00
public Plane Normalized()
{
2018-05-17 17:04:20 +02:00
real_t len = _normal.Length();
if (len == 0)
return new Plane(0, 0, 0, 0);
return new Plane(_normal / len, D / len);
}
2017-11-21 23:32:19 +01:00
public Vector3 Project(Vector3 point)
{
2018-05-17 17:04:20 +02:00
return point - _normal * DistanceTo(point);
}
// Constants
private static readonly Plane _planeYZ = new Plane(1, 0, 0, 0);
private static readonly Plane _planeXZ = new Plane(0, 1, 0, 0);
private static readonly Plane _planeXY = new Plane(0, 0, 1, 0);
public static Plane PlaneYZ { get { return _planeYZ; } }
public static Plane PlaneXZ { get { return _planeXZ; } }
public static Plane PlaneXY { get { return _planeXY; } }
// Constructors
public Plane(real_t a, real_t b, real_t c, real_t d)
{
2018-05-17 17:04:20 +02:00
_normal = new Vector3(a, b, c);
this.D = d;
}
public Plane(Vector3 normal, real_t d)
{
2018-05-17 17:04:20 +02:00
this._normal = normal;
this.D = d;
}
public Plane(Vector3 v1, Vector3 v2, Vector3 v3)
{
2018-05-17 17:04:20 +02:00
_normal = (v1 - v3).Cross(v1 - v2);
_normal.Normalize();
D = _normal.Dot(v1);
}
public static Plane operator -(Plane plane)
{
return new Plane(-plane._normal, -plane.D);
}
public static bool operator ==(Plane left, Plane right)
{
return left.Equals(right);
}
public static bool operator !=(Plane left, Plane right)
{
return !left.Equals(right);
}
public override bool Equals(object obj)
{
if (obj is Plane)
{
return Equals((Plane)obj);
}
return false;
}
public bool Equals(Plane other)
{
return _normal == other._normal && D == other.D;
}
public bool IsEqualApprox(Plane other)
{
return _normal.IsEqualApprox(other._normal) && Mathf.IsEqualApprox(D, other.D);
}
public override int GetHashCode()
{
return _normal.GetHashCode() ^ D.GetHashCode();
}
public override string ToString()
{
return String.Format("({0}, {1})", new object[]
{
2018-05-17 17:04:20 +02:00
_normal.ToString(),
D.ToString()
});
}
public string ToString(string format)
{
return String.Format("({0}, {1})", new object[]
{
2018-05-17 17:04:20 +02:00
_normal.ToString(format),
D.ToString(format)
});
}
}
}