1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
|
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Globalization;
using System.Runtime.CompilerServices;
namespace System.Numerics
{
/// <summary>
/// A structure encapsulating a 3D Plane
/// </summary>
public struct Plane : IEquatable<Plane>
{
/// <summary>
/// The normal vector of the Plane.
/// </summary>
public Vector3 Normal;
/// <summary>
/// The distance of the Plane along its normal from the origin.
/// </summary>
public float D;
/// <summary>
/// Constructs a Plane from the X, Y, and Z components of its normal, and its distance from the origin on that normal.
/// </summary>
/// <param name="x">The X-component of the normal.</param>
/// <param name="y">The Y-component of the normal.</param>
/// <param name="z">The Z-component of the normal.</param>
/// <param name="d">The distance of the Plane along its normal from the origin.</param>
public Plane(float x, float y, float z, float d)
{
Normal = new Vector3(x, y, z);
this.D = d;
}
/// <summary>
/// Constructs a Plane from the given normal and distance along the normal from the origin.
/// </summary>
/// <param name="normal">The Plane's normal vector.</param>
/// <param name="d">The Plane's distance from the origin along its normal vector.</param>
public Plane(Vector3 normal, float d)
{
this.Normal = normal;
this.D = d;
}
/// <summary>
/// Constructs a Plane from the given Vector4.
/// </summary>
/// <param name="value">A vector whose first 3 elements describe the normal vector,
/// and whose W component defines the distance along that normal from the origin.</param>
public Plane(Vector4 value)
{
Normal = new Vector3(value.X, value.Y, value.Z);
D = value.W;
}
/// <summary>
/// Creates a Plane that contains the three given points.
/// </summary>
/// <param name="point1">The first point defining the Plane.</param>
/// <param name="point2">The second point defining the Plane.</param>
/// <param name="point3">The third point defining the Plane.</param>
/// <returns>The Plane containing the three points.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Plane CreateFromVertices(Vector3 point1, Vector3 point2, Vector3 point3)
{
if (Vector.IsHardwareAccelerated)
{
Vector3 a = point2 - point1;
Vector3 b = point3 - point1;
// N = Cross(a, b)
Vector3 n = Vector3.Cross(a, b);
Vector3 normal = Vector3.Normalize(n);
// D = - Dot(N, point1)
float d = -Vector3.Dot(normal, point1);
return new Plane(normal, d);
}
else
{
float ax = point2.X - point1.X;
float ay = point2.Y - point1.Y;
float az = point2.Z - point1.Z;
float bx = point3.X - point1.X;
float by = point3.Y - point1.Y;
float bz = point3.Z - point1.Z;
// N=Cross(a,b)
float nx = ay * bz - az * by;
float ny = az * bx - ax * bz;
float nz = ax * by - ay * bx;
// Normalize(N)
float ls = nx * nx + ny * ny + nz * nz;
float invNorm = 1.0f / (float)Math.Sqrt((double)ls);
Vector3 normal = new Vector3(
nx * invNorm,
ny * invNorm,
nz * invNorm);
return new Plane(
normal,
-(normal.X * point1.X + normal.Y * point1.Y + normal.Z * point1.Z));
}
}
/// <summary>
/// Creates a new Plane whose normal vector is the source Plane's normal vector normalized.
/// </summary>
/// <param name="value">The source Plane.</param>
/// <returns>The normalized Plane.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Plane Normalize(Plane value)
{
const float FLT_EPSILON = 1.192092896e-07f; // smallest such that 1.0+FLT_EPSILON != 1.0
if (Vector.IsHardwareAccelerated)
{
float normalLengthSquared = value.Normal.LengthSquared();
if (Math.Abs(normalLengthSquared - 1.0f) < FLT_EPSILON)
{
// It already normalized, so we don't need to farther process.
return value;
}
float normalLength = (float)Math.Sqrt(normalLengthSquared);
return new Plane(
value.Normal / normalLength,
value.D / normalLength);
}
else
{
float f = value.Normal.X * value.Normal.X + value.Normal.Y * value.Normal.Y + value.Normal.Z * value.Normal.Z;
if (Math.Abs(f - 1.0f) < FLT_EPSILON)
{
return value; // It already normalized, so we don't need to further process.
}
float fInv = 1.0f / (float)Math.Sqrt(f);
return new Plane(
value.Normal.X * fInv,
value.Normal.Y * fInv,
value.Normal.Z * fInv,
value.D * fInv);
}
}
/// <summary>
/// Transforms a normalized Plane by a Matrix.
/// </summary>
/// <param name="plane"> The normalized Plane to transform.
/// This Plane must already be normalized, so that its Normal vector is of unit length, before this method is called.</param>
/// <param name="matrix">The transformation matrix to apply to the Plane.</param>
/// <returns>The transformed Plane.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Plane Transform(Plane plane, Matrix4x4 matrix)
{
Matrix4x4 m;
Matrix4x4.Invert(matrix, out m);
float x = plane.Normal.X, y = plane.Normal.Y, z = plane.Normal.Z, w = plane.D;
return new Plane(
x * m.M11 + y * m.M12 + z * m.M13 + w * m.M14,
x * m.M21 + y * m.M22 + z * m.M23 + w * m.M24,
x * m.M31 + y * m.M32 + z * m.M33 + w * m.M34,
x * m.M41 + y * m.M42 + z * m.M43 + w * m.M44);
}
/// <summary>
/// Transforms a normalized Plane by a Quaternion rotation.
/// </summary>
/// <param name="plane"> The normalized Plane to transform.
/// This Plane must already be normalized, so that its Normal vector is of unit length, before this method is called.</param>
/// <param name="rotation">The Quaternion rotation to apply to the Plane.</param>
/// <returns>A new Plane that results from applying the rotation.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Plane Transform(Plane plane, Quaternion rotation)
{
// Compute rotation matrix.
float x2 = rotation.X + rotation.X;
float y2 = rotation.Y + rotation.Y;
float z2 = rotation.Z + rotation.Z;
float wx2 = rotation.W * x2;
float wy2 = rotation.W * y2;
float wz2 = rotation.W * z2;
float xx2 = rotation.X * x2;
float xy2 = rotation.X * y2;
float xz2 = rotation.X * z2;
float yy2 = rotation.Y * y2;
float yz2 = rotation.Y * z2;
float zz2 = rotation.Z * z2;
float m11 = 1.0f - yy2 - zz2;
float m21 = xy2 - wz2;
float m31 = xz2 + wy2;
float m12 = xy2 + wz2;
float m22 = 1.0f - xx2 - zz2;
float m32 = yz2 - wx2;
float m13 = xz2 - wy2;
float m23 = yz2 + wx2;
float m33 = 1.0f - xx2 - yy2;
float x = plane.Normal.X, y = plane.Normal.Y, z = plane.Normal.Z;
return new Plane(
x * m11 + y * m21 + z * m31,
x * m12 + y * m22 + z * m32,
x * m13 + y * m23 + z * m33,
plane.D);
}
/// <summary>
/// Calculates the dot product of a Plane and Vector4.
/// </summary>
/// <param name="plane">The Plane.</param>
/// <param name="value">The Vector4.</param>
/// <returns>The dot product.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Dot(Plane plane, Vector4 value)
{
return plane.Normal.X * value.X +
plane.Normal.Y * value.Y +
plane.Normal.Z * value.Z +
plane.D * value.W;
}
/// <summary>
/// Returns the dot product of a specified Vector3 and the normal vector of this Plane plus the distance (D) value of the Plane.
/// </summary>
/// <param name="plane">The plane.</param>
/// <param name="value">The Vector3.</param>
/// <returns>The resulting value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float DotCoordinate(Plane plane, Vector3 value)
{
if (Vector.IsHardwareAccelerated)
{
return Vector3.Dot(plane.Normal, value) + plane.D;
}
else
{
return plane.Normal.X * value.X +
plane.Normal.Y * value.Y +
plane.Normal.Z * value.Z +
plane.D;
}
}
/// <summary>
/// Returns the dot product of a specified Vector3 and the Normal vector of this Plane.
/// </summary>
/// <param name="plane">The plane.</param>
/// <param name="value">The Vector3.</param>
/// <returns>The resulting dot product.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float DotNormal(Plane plane, Vector3 value)
{
if (Vector.IsHardwareAccelerated)
{
return Vector3.Dot(plane.Normal, value);
}
else
{
return plane.Normal.X * value.X +
plane.Normal.Y * value.Y +
plane.Normal.Z * value.Z;
}
}
/// <summary>
/// Returns a boolean indicating whether the two given Planes are equal.
/// </summary>
/// <param name="value1">The first Plane to compare.</param>
/// <param name="value2">The second Plane to compare.</param>
/// <returns>True if the Planes are equal; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Plane value1, Plane value2)
{
return (value1.Normal.X == value2.Normal.X &&
value1.Normal.Y == value2.Normal.Y &&
value1.Normal.Z == value2.Normal.Z &&
value1.D == value2.D);
}
/// <summary>
/// Returns a boolean indicating whether the two given Planes are not equal.
/// </summary>
/// <param name="value1">The first Plane to compare.</param>
/// <param name="value2">The second Plane to compare.</param>
/// <returns>True if the Planes are not equal; False if they are equal.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Plane value1, Plane value2)
{
return (value1.Normal.X != value2.Normal.X ||
value1.Normal.Y != value2.Normal.Y ||
value1.Normal.Z != value2.Normal.Z ||
value1.D != value2.D);
}
/// <summary>
/// Returns a boolean indicating whether the given Plane is equal to this Plane instance.
/// </summary>
/// <param name="other">The Plane to compare this instance to.</param>
/// <returns>True if the other Plane is equal to this instance; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Plane other)
{
if (Vector.IsHardwareAccelerated)
{
return this.Normal.Equals(other.Normal) && this.D == other.D;
}
else
{
return (Normal.X == other.Normal.X &&
Normal.Y == other.Normal.Y &&
Normal.Z == other.Normal.Z &&
D == other.D);
}
}
/// <summary>
/// Returns a boolean indicating whether the given Object is equal to this Plane instance.
/// </summary>
/// <param name="obj">The Object to compare against.</param>
/// <returns>True if the Object is equal to this Plane; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj)
{
if (obj is Plane)
{
return Equals((Plane)obj);
}
return false;
}
/// <summary>
/// Returns a String representing this Plane instance.
/// </summary>
/// <returns>The string representation.</returns>
public override string ToString()
{
CultureInfo ci = CultureInfo.CurrentCulture;
return String.Format(ci, "{{Normal:{0} D:{1}}}", Normal.ToString(), D.ToString(ci));
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>The hash code.</returns>
public override int GetHashCode()
{
return Normal.GetHashCode() + D.GetHashCode();
}
}
}
|