| | | 1 | | //======================================================================= |
| | | 2 | | // Vector4d.cs |
| | | 3 | | //======================================================================= |
| | | 4 | | // MIT License, Copyright (c) 2024–present David Oravsky (mrdav30) |
| | | 5 | | // See LICENSE file in the project root for full license information. |
| | | 6 | | //======================================================================= |
| | | 7 | | |
| | | 8 | | using System; |
| | | 9 | | using System.Collections.Generic; |
| | | 10 | | using System.Globalization; |
| | | 11 | | using System.Runtime.CompilerServices; |
| | | 12 | | using System.Text.Json.Serialization; |
| | | 13 | | using MemoryPack; |
| | | 14 | | |
| | | 15 | | namespace FixedMathSharp; |
| | | 16 | | |
| | | 17 | | /// <summary> |
| | | 18 | | /// Represents a 4D vector with fixed-point precision. |
| | | 19 | | /// </summary> |
| | | 20 | | /// <remarks> |
| | | 21 | | /// This type is useful for generic 4D component math and homogeneous coordinates used by 4x4 |
| | | 22 | | /// transforms. It does not define independent forward or backward semantics; direction naming |
| | | 23 | | /// belongs to <see cref="Vector2d"/>, <see cref="Vector3d"/>, and adapter-level convention code. |
| | | 24 | | /// </remarks> |
| | | 25 | | [Serializable] |
| | | 26 | | [MemoryPackable] |
| | | 27 | | public partial struct Vector4d : IEquatable<Vector4d>, IComparable<Vector4d>, IEqualityComparer<Vector4d>, IFormattable |
| | | 28 | | #if NET8_0_OR_GREATER |
| | | 29 | | , ISpanFormattable |
| | | 30 | | #endif |
| | | 31 | | { |
| | | 32 | | #region Static Readonly Fields |
| | | 33 | | |
| | | 34 | | /// <summary> |
| | | 35 | | /// (1, 0, 0, 0) |
| | | 36 | | /// </summary> |
| | 7 | 37 | | public static Vector4d UnitX => new(1, 0, 0, 0); |
| | | 38 | | |
| | | 39 | | /// <summary> |
| | | 40 | | /// (0, 1, 0, 0) |
| | | 41 | | /// </summary> |
| | 1 | 42 | | public static Vector4d UnitY => new(0, 1, 0, 0); |
| | | 43 | | |
| | | 44 | | /// <summary> |
| | | 45 | | /// The unit Z component vector (0, 0, 1, 0). |
| | | 46 | | /// </summary> |
| | 1 | 47 | | public static Vector4d UnitZ => new(0, 0, 1, 0); |
| | | 48 | | |
| | | 49 | | /// <summary> |
| | | 50 | | /// (0, 0, 0, 1) |
| | | 51 | | /// </summary> |
| | 1 | 52 | | public static Vector4d UnitW => new(0, 0, 0, 1); |
| | | 53 | | |
| | | 54 | | /// <summary> |
| | | 55 | | /// (1, 1, 1, 1) |
| | | 56 | | /// </summary> |
| | 5 | 57 | | public static Vector4d One => new(1, 1, 1, 1); |
| | | 58 | | |
| | | 59 | | /// <summary> |
| | | 60 | | /// (-1, -1, -1, -1) |
| | | 61 | | /// </summary> |
| | 3 | 62 | | public static Vector4d Negative => new(-1, -1, -1, -1); |
| | | 63 | | |
| | | 64 | | /// <summary> |
| | | 65 | | /// (0, 0, 0, 0) |
| | | 66 | | /// </summary> |
| | 68 | 67 | | public static Vector4d Zero => new(0, 0, 0, 0); |
| | | 68 | | |
| | | 69 | | #endregion |
| | | 70 | | |
| | | 71 | | #region Fields |
| | | 72 | | |
| | | 73 | | /// <summary> |
| | | 74 | | /// The X component of the vector. |
| | | 75 | | /// </summary> |
| | | 76 | | [JsonInclude] |
| | | 77 | | [MemoryPackOrder(0)] |
| | | 78 | | public Fixed64 X; |
| | | 79 | | |
| | | 80 | | /// <summary> |
| | | 81 | | /// The Y component of the vector. |
| | | 82 | | /// </summary> |
| | | 83 | | [JsonInclude] |
| | | 84 | | [MemoryPackOrder(1)] |
| | | 85 | | public Fixed64 Y; |
| | | 86 | | |
| | | 87 | | /// <summary> |
| | | 88 | | /// The Z component of the vector. |
| | | 89 | | /// </summary> |
| | | 90 | | [JsonInclude] |
| | | 91 | | [MemoryPackOrder(2)] |
| | | 92 | | public Fixed64 Z; |
| | | 93 | | |
| | | 94 | | /// <summary> |
| | | 95 | | /// The W component of the vector. |
| | | 96 | | /// </summary> |
| | | 97 | | [JsonInclude] |
| | | 98 | | [MemoryPackOrder(3)] |
| | | 99 | | public Fixed64 W; |
| | | 100 | | |
| | | 101 | | #endregion |
| | | 102 | | |
| | | 103 | | #region Constructors |
| | | 104 | | |
| | | 105 | | /// <summary> |
| | | 106 | | /// Initializes a new Vector4d using integer component values. |
| | | 107 | | /// </summary> |
| | | 108 | | public Vector4d(int xInt, int yInt, int zInt, int wInt) |
| | 506 | 109 | | : this((Fixed64)xInt, (Fixed64)yInt, (Fixed64)zInt, (Fixed64)wInt) { } |
| | | 110 | | |
| | | 111 | | /// <summary> |
| | | 112 | | /// Initializes a new Vector4d using the specified components. |
| | | 113 | | /// </summary> |
| | | 114 | | [JsonConstructor] |
| | | 115 | | public Vector4d(Fixed64 x, Fixed64 y, Fixed64 z, Fixed64 w) |
| | | 116 | | { |
| | 431 | 117 | | X = x; |
| | 431 | 118 | | Y = y; |
| | 431 | 119 | | Z = z; |
| | 431 | 120 | | W = w; |
| | 431 | 121 | | } |
| | | 122 | | |
| | | 123 | | /// <summary> |
| | | 124 | | /// Initializes a new Vector4d with all components set to the same value. |
| | | 125 | | /// </summary> |
| | | 126 | | public Vector4d(Fixed64 value) |
| | 2 | 127 | | : this(value, value, value, value) { } |
| | | 128 | | |
| | | 129 | | /// <summary> |
| | | 130 | | /// Initializes a new Vector4d from a Vector2d plus Z and W components. |
| | | 131 | | /// </summary> |
| | | 132 | | public Vector4d(Vector2d value, Fixed64 z, Fixed64 w) |
| | 2 | 133 | | : this(value.X, value.Y, z, w) { } |
| | | 134 | | |
| | | 135 | | /// <summary> |
| | | 136 | | /// Initializes a new Vector4d from a Vector3d plus a W component. |
| | | 137 | | /// </summary> |
| | | 138 | | public Vector4d(Vector3d value, Fixed64 w) |
| | 2 | 139 | | : this(value.X, value.Y, value.Z, w) { } |
| | | 140 | | |
| | | 141 | | /// <summary> |
| | | 142 | | /// Initializes a new Vector4d using double component values. |
| | | 143 | | /// </summary> |
| | | 144 | | /// <remarks> |
| | | 145 | | /// Components are converted through <see cref="Fixed64.FromDouble(double)"/>, so non-finite |
| | | 146 | | /// values throw <see cref="ArgumentOutOfRangeException"/> and finite values outside the Q32.32 |
| | | 147 | | /// range throw <see cref="OverflowException"/>. |
| | | 148 | | /// </remarks> |
| | | 149 | | public static Vector4d FromDouble(double xDoub, double yDoub, double zDoub, double wDoub) => |
| | 11 | 150 | | new(Fixed64.FromDouble(xDoub), Fixed64.FromDouble(yDoub), Fixed64.FromDouble(zDoub), Fixed64.FromDouble(wDoub)); |
| | | 151 | | |
| | | 152 | | #endregion |
| | | 153 | | |
| | | 154 | | #region Properties |
| | | 155 | | |
| | | 156 | | /// <inheritdoc cref="GetNormalized(Vector4d)"/> |
| | | 157 | | [JsonIgnore] |
| | | 158 | | [MemoryPackIgnore] |
| | | 159 | | public readonly Vector4d Normalized |
| | | 160 | | { |
| | | 161 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 19 | 162 | | get => GetNormalized(this); |
| | | 163 | | } |
| | | 164 | | |
| | | 165 | | /// <summary> |
| | | 166 | | /// Returns the actual length of this vector. |
| | | 167 | | /// </summary> |
| | | 168 | | [JsonIgnore] |
| | | 169 | | [MemoryPackIgnore] |
| | | 170 | | public readonly Fixed64 Magnitude |
| | | 171 | | { |
| | | 172 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 16 | 173 | | get => GetMagnitude(this); |
| | | 174 | | } |
| | | 175 | | |
| | | 176 | | /// <summary> |
| | | 177 | | /// Returns the square magnitude of the vector. |
| | | 178 | | /// </summary> |
| | | 179 | | [JsonIgnore] |
| | | 180 | | [MemoryPackIgnore] |
| | | 181 | | public readonly Fixed64 MagnitudeSquared |
| | | 182 | | { |
| | | 183 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 40 | 184 | | get => (X * X) + (Y * Y) + (Z * Z) + (W * W); |
| | | 185 | | } |
| | | 186 | | |
| | | 187 | | /// <summary> |
| | | 188 | | /// Returns a long hash of the vector based on its component values. |
| | | 189 | | /// </summary> |
| | | 190 | | [JsonIgnore] |
| | | 191 | | [MemoryPackIgnore] |
| | | 192 | | public readonly long LongStateHash |
| | | 193 | | { |
| | | 194 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 195 | | get |
| | | 196 | | { |
| | | 197 | | unchecked |
| | | 198 | | { |
| | 6 | 199 | | return (X.m_rawValue * 31) + (Y.m_rawValue * 7) + (Z.m_rawValue * 11) + (W.m_rawValue * 17); |
| | | 200 | | } |
| | | 201 | | } |
| | | 202 | | } |
| | | 203 | | |
| | | 204 | | /// <summary> |
| | | 205 | | /// Returns a hash of the vector based on its state. |
| | | 206 | | /// </summary> |
| | | 207 | | [JsonIgnore] |
| | | 208 | | [MemoryPackIgnore] |
| | | 209 | | public readonly int StateHash |
| | | 210 | | { |
| | | 211 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 4 | 212 | | get => unchecked((int)(LongStateHash % int.MaxValue)); |
| | | 213 | | } |
| | | 214 | | |
| | | 215 | | /// <summary> |
| | | 216 | | /// Are all components of this vector equal to zero? |
| | | 217 | | /// </summary> |
| | | 218 | | [JsonIgnore] |
| | | 219 | | [MemoryPackIgnore] |
| | | 220 | | public readonly bool IsZero |
| | | 221 | | { |
| | | 222 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 49 | 223 | | get => Equals(Zero); |
| | | 224 | | } |
| | | 225 | | |
| | | 226 | | /// <summary> |
| | | 227 | | /// Gets or sets the vector component at the specified index. |
| | | 228 | | /// </summary> |
| | | 229 | | [JsonIgnore] |
| | | 230 | | [MemoryPackIgnore] |
| | | 231 | | public Fixed64 this[int index] |
| | | 232 | | { |
| | | 233 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 234 | | readonly get |
| | | 235 | | { |
| | 10 | 236 | | return index switch |
| | 10 | 237 | | { |
| | 2 | 238 | | 0 => X, |
| | 2 | 239 | | 1 => Y, |
| | 2 | 240 | | 2 => Z, |
| | 2 | 241 | | 3 => W, |
| | 2 | 242 | | _ => throw new IndexOutOfRangeException("Invalid Vector4d index!"), |
| | 10 | 243 | | }; |
| | | 244 | | } |
| | | 245 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 246 | | set |
| | | 247 | | { |
| | | 248 | | switch (index) |
| | | 249 | | { |
| | | 250 | | case 0: |
| | 8 | 251 | | X = value; |
| | 8 | 252 | | break; |
| | | 253 | | case 1: |
| | 8 | 254 | | Y = value; |
| | 8 | 255 | | break; |
| | | 256 | | case 2: |
| | 8 | 257 | | Z = value; |
| | 8 | 258 | | break; |
| | | 259 | | case 3: |
| | 8 | 260 | | W = value; |
| | 8 | 261 | | break; |
| | | 262 | | default: |
| | 2 | 263 | | throw new IndexOutOfRangeException("Invalid Vector4d index!"); |
| | | 264 | | } |
| | | 265 | | } |
| | | 266 | | } |
| | | 267 | | |
| | | 268 | | #endregion |
| | | 269 | | |
| | | 270 | | #region Instance Methods |
| | | 271 | | |
| | | 272 | | /// <summary> |
| | | 273 | | /// Sets the vector components in place and returns the modified vector. |
| | | 274 | | /// </summary> |
| | | 275 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 276 | | public Vector4d Set(Fixed64 newX, Fixed64 newY, Fixed64 newZ, Fixed64 newW) |
| | | 277 | | { |
| | 1 | 278 | | X = newX; |
| | 1 | 279 | | Y = newY; |
| | 1 | 280 | | Z = newZ; |
| | 1 | 281 | | W = newW; |
| | 1 | 282 | | return this; |
| | | 283 | | } |
| | | 284 | | |
| | | 285 | | /// <summary> |
| | | 286 | | /// Adds the specified component values in place. |
| | | 287 | | /// </summary> |
| | | 288 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 289 | | public Vector4d AddInPlace(Fixed64 xAmount, Fixed64 yAmount, Fixed64 zAmount, Fixed64 wAmount) |
| | | 290 | | { |
| | 4 | 291 | | X += xAmount; |
| | 4 | 292 | | Y += yAmount; |
| | 4 | 293 | | Z += zAmount; |
| | 4 | 294 | | W += wAmount; |
| | 4 | 295 | | return this; |
| | | 296 | | } |
| | | 297 | | |
| | | 298 | | /// <summary> |
| | | 299 | | /// Adds the specified scalar to all components in place. |
| | | 300 | | /// </summary> |
| | | 301 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 302 | | public Vector4d AddInPlace(Fixed64 amount) => AddInPlace(amount, amount, amount, amount); |
| | | 303 | | |
| | | 304 | | /// <summary> |
| | | 305 | | /// Adds another vector in place. |
| | | 306 | | /// </summary> |
| | | 307 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 2 | 308 | | public Vector4d AddInPlace(Vector4d other) => AddInPlace(other.X, other.Y, other.Z, other.W); |
| | | 309 | | |
| | | 310 | | /// <summary> |
| | | 311 | | /// Subtracts the specified component values in place. |
| | | 312 | | /// </summary> |
| | | 313 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 314 | | public Vector4d SubtractInPlace(Fixed64 xAmount, Fixed64 yAmount, Fixed64 zAmount, Fixed64 wAmount) |
| | | 315 | | { |
| | 4 | 316 | | X -= xAmount; |
| | 4 | 317 | | Y -= yAmount; |
| | 4 | 318 | | Z -= zAmount; |
| | 4 | 319 | | W -= wAmount; |
| | 4 | 320 | | return this; |
| | | 321 | | } |
| | | 322 | | |
| | | 323 | | /// <summary> |
| | | 324 | | /// Subtracts the specified scalar from all components in place. |
| | | 325 | | /// </summary> |
| | | 326 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 2 | 327 | | public Vector4d SubtractInPlace(Fixed64 amount) => SubtractInPlace(amount, amount, amount, amount); |
| | | 328 | | |
| | | 329 | | |
| | | 330 | | /// <summary> |
| | | 331 | | /// Subtracts another vector in place. |
| | | 332 | | /// </summary> |
| | | 333 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 334 | | public Vector4d SubtractInPlace(Vector4d other) => SubtractInPlace(other.X, other.Y, other.Z, other.W); |
| | | 335 | | |
| | | 336 | | /// <summary> |
| | | 337 | | /// Multiplies the vector components by the specified factors in place. |
| | | 338 | | /// </summary> |
| | | 339 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 340 | | public Vector4d MultiplyInPlace(Fixed64 factorX, Fixed64 factorY, Fixed64 factorZ, Fixed64 factorW) |
| | | 341 | | { |
| | 6 | 342 | | X *= factorX; |
| | 6 | 343 | | Y *= factorY; |
| | 6 | 344 | | Z *= factorZ; |
| | 6 | 345 | | W *= factorW; |
| | 6 | 346 | | return this; |
| | | 347 | | } |
| | | 348 | | |
| | | 349 | | /// <summary> |
| | | 350 | | /// Multiplies all components in place. |
| | | 351 | | /// </summary> |
| | | 352 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 3 | 353 | | public Vector4d MultiplyInPlace(Fixed64 factor) => MultiplyInPlace(factor, factor, factor, factor); |
| | | 354 | | |
| | | 355 | | /// <summary> |
| | | 356 | | /// Multiplies all components by another vector in place. |
| | | 357 | | /// </summary> |
| | | 358 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 2 | 359 | | public Vector4d MultiplyInPlace(Vector4d factor) => MultiplyInPlace(factor.X, factor.Y, factor.Z, factor.W); |
| | | 360 | | |
| | | 361 | | /// <summary> |
| | | 362 | | /// Divides the vector components by the specified divisors in place. |
| | | 363 | | /// </summary> |
| | | 364 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 365 | | public Vector4d DivideInPlace(Fixed64 divisorX, Fixed64 divisorY, Fixed64 divisorZ, Fixed64 divisorW) |
| | | 366 | | { |
| | 4 | 367 | | X /= divisorX; |
| | 4 | 368 | | Y /= divisorY; |
| | 4 | 369 | | Z /= divisorZ; |
| | 4 | 370 | | W /= divisorW; |
| | 4 | 371 | | return this; |
| | | 372 | | } |
| | | 373 | | |
| | | 374 | | /// <summary> |
| | | 375 | | /// Divides all components in place. |
| | | 376 | | /// </summary> |
| | | 377 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 378 | | public Vector4d DivideInPlace(Fixed64 divisor) => DivideInPlace(divisor, divisor, divisor, divisor); |
| | | 379 | | |
| | | 380 | | /// <summary> |
| | | 381 | | /// Divides all components by another vector in place. |
| | | 382 | | /// </summary> |
| | | 383 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 2 | 384 | | public Vector4d DivideInPlace(Vector4d divisor) => DivideInPlace(divisor.X, divisor.Y, divisor.Z, divisor.W); |
| | | 385 | | |
| | | 386 | | /// <summary> |
| | | 387 | | /// Normalizes this vector in place. |
| | | 388 | | /// </summary> |
| | | 389 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 390 | | public Vector4d NormalizeInPlace() => this = GetNormalized(this); |
| | | 391 | | |
| | | 392 | | /// <summary> |
| | | 393 | | /// Normalizes this vector in place and returns its original magnitude. |
| | | 394 | | /// </summary> |
| | | 395 | | public Vector4d NormalizeInPlace(out Fixed64 mag) |
| | | 396 | | { |
| | 15 | 397 | | Vector4d source = this; |
| | 15 | 398 | | bool magnitudeIsRepresentable = TryGetMagnitude( |
| | 15 | 399 | | source, |
| | 15 | 400 | | out mag, |
| | 15 | 401 | | out bool isNormalized); |
| | | 402 | | |
| | 15 | 403 | | if (mag == Fixed64.Zero) |
| | 1 | 404 | | return this = Zero; |
| | | 405 | | |
| | 14 | 406 | | if (isNormalized) |
| | 1 | 407 | | return this; |
| | | 408 | | |
| | 13 | 409 | | if (!magnitudeIsRepresentable || mag == Fixed64.One) |
| | 1 | 410 | | return this = WideNormalization.GetNormalized(source); |
| | | 411 | | |
| | 12 | 412 | | if (mag <= FixedMath.ScaleSafeMagnitudeThreshold) |
| | 1 | 413 | | return this = GetScaleNormalized(source); |
| | | 414 | | |
| | 11 | 415 | | this = new Vector4d( |
| | 11 | 416 | | FixedMath.FastDiv(X, mag), |
| | 11 | 417 | | FixedMath.FastDiv(Y, mag), |
| | 11 | 418 | | FixedMath.FastDiv(Z, mag), |
| | 11 | 419 | | FixedMath.FastDiv(W, mag)); |
| | 11 | 420 | | return IsNormalized() |
| | 11 | 421 | | ? this |
| | 11 | 422 | | : this = WideNormalization.GetNormalized(source); |
| | | 423 | | } |
| | | 424 | | |
| | | 425 | | /// <summary> |
| | | 426 | | /// Determines whether this vector is normalized. |
| | | 427 | | /// </summary> |
| | | 428 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 429 | | public readonly bool IsNormalized() => |
| | 38 | 430 | | !IsZero && FixedMath.Abs(MagnitudeSquared - Fixed64.One) <= Fixed64.Epsilon; |
| | | 431 | | |
| | | 432 | | /// <summary> |
| | | 433 | | /// Determines whether all components are greater than Fixed64.Epsilon. |
| | | 434 | | /// </summary> |
| | | 435 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 436 | | public readonly bool AllComponentsGreaterThanEpsilon() => |
| | 5 | 437 | | X > Fixed64.Epsilon && Y > Fixed64.Epsilon && Z > Fixed64.Epsilon && W > Fixed64.Epsilon; |
| | | 438 | | |
| | | 439 | | /// <summary> |
| | | 440 | | /// Snaps components with absolute values below the threshold to zero. |
| | | 441 | | /// </summary> |
| | | 442 | | public readonly Vector4d SnapSmallComponentsToZero(Fixed64? threshold = null) |
| | | 443 | | { |
| | 3 | 444 | | Fixed64 t = threshold ?? Fixed64.Epsilon; |
| | 3 | 445 | | return new Vector4d( |
| | 3 | 446 | | FixedMath.Abs(X) < t ? Fixed64.Zero : X, |
| | 3 | 447 | | FixedMath.Abs(Y) < t ? Fixed64.Zero : Y, |
| | 3 | 448 | | FixedMath.Abs(Z) < t ? Fixed64.Zero : Z, |
| | 3 | 449 | | FixedMath.Abs(W) < t ? Fixed64.Zero : W); |
| | | 450 | | } |
| | | 451 | | |
| | | 452 | | /// <summary> |
| | | 453 | | /// Calculates the distance to another vector. |
| | | 454 | | /// </summary> |
| | | 455 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 456 | | public readonly Fixed64 Distance(Fixed64 otherX, Fixed64 otherY, Fixed64 otherZ, Fixed64 otherW) |
| | | 457 | | { |
| | 6 | 458 | | Fixed64 deltaX = otherX - X; |
| | 6 | 459 | | Fixed64 deltaY = otherY - Y; |
| | 6 | 460 | | Fixed64 deltaZ = otherZ - Z; |
| | 6 | 461 | | Fixed64 deltaW = otherW - W; |
| | 6 | 462 | | Fixed64 squareSum = deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ + deltaW * deltaW; |
| | 6 | 463 | | return squareSum == Fixed64.MaxValue |
| | 6 | 464 | | ? FixedMath.GetScaledMagnitude(deltaX, deltaY, deltaZ, deltaW) |
| | 6 | 465 | | : FixedMath.Sqrt(squareSum); |
| | | 466 | | } |
| | | 467 | | |
| | | 468 | | /// <summary> |
| | | 469 | | /// Calculates the distance to another vector. |
| | | 470 | | /// </summary> |
| | | 471 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 472 | | public readonly Fixed64 Distance(Vector4d other) => Distance(other.X, other.Y, other.Z, other.W); |
| | | 473 | | |
| | | 474 | | /// <summary> |
| | | 475 | | /// Calculates the squared distance to another vector. |
| | | 476 | | /// </summary> |
| | | 477 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 478 | | public readonly Fixed64 DistanceSquared(Fixed64 otherX, Fixed64 otherY, Fixed64 otherZ, Fixed64 otherW) |
| | | 479 | | { |
| | 2 | 480 | | Fixed64 dx = otherX - X; |
| | 2 | 481 | | Fixed64 dy = otherY - Y; |
| | 2 | 482 | | Fixed64 dz = otherZ - Z; |
| | 2 | 483 | | Fixed64 dw = otherW - W; |
| | 2 | 484 | | return (dx * dx) + (dy * dy) + (dz * dz) + (dw * dw); |
| | | 485 | | } |
| | | 486 | | |
| | | 487 | | /// <summary> |
| | | 488 | | /// Calculates the squared distance to another vector. |
| | | 489 | | /// </summary> |
| | | 490 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 491 | | public readonly Fixed64 DistanceSquared(Vector4d other) => DistanceSquared(other.X, other.Y, other.Z, other.W); |
| | | 492 | | |
| | | 493 | | /// <summary> |
| | | 494 | | /// Calculates the dot product with another vector. |
| | | 495 | | /// </summary> |
| | | 496 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 497 | | public readonly Fixed64 Dot(Fixed64 otherX, Fixed64 otherY, Fixed64 otherZ, Fixed64 otherW) => |
| | 2 | 498 | | (X * otherX) + (Y * otherY) + (Z * otherZ) + (W * otherW); |
| | | 499 | | |
| | | 500 | | /// <summary> |
| | | 501 | | /// Calculates the dot product with another vector. |
| | | 502 | | /// </summary> |
| | | 503 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 504 | | public readonly Fixed64 Dot(Vector4d other) => Dot(other.X, other.Y, other.Z, other.W); |
| | | 505 | | |
| | | 506 | | /// <summary> |
| | | 507 | | /// Converts this vector to Vector3d by dropping the W component. |
| | | 508 | | /// </summary> |
| | | 509 | | /// <remarks> |
| | | 510 | | /// This is a component-preserving conversion, not a coordinate-convention conversion. |
| | | 511 | | /// </remarks> |
| | | 512 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 3 | 513 | | public readonly Vector3d ToVector3d() => new Vector3d(X, Y, Z); |
| | | 514 | | |
| | | 515 | | #endregion |
| | | 516 | | |
| | | 517 | | #region Static Methods |
| | | 518 | | |
| | | 519 | | /// <summary> |
| | | 520 | | /// Adds two vectors component-wise. |
| | | 521 | | /// </summary> |
| | | 522 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 523 | | public static Vector4d Add(Vector4d v1, Vector4d v2) => v1 + v2; |
| | | 524 | | |
| | | 525 | | /// <summary> |
| | | 526 | | /// Subtracts two vectors component-wise. |
| | | 527 | | /// </summary> |
| | | 528 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 529 | | public static Vector4d Subtract(Vector4d v1, Vector4d v2) => v1 - v2; |
| | | 530 | | |
| | | 531 | | /// <summary> |
| | | 532 | | /// Linearly interpolates between two vectors, clamping the interpolation amount to [0, 1]. |
| | | 533 | | /// </summary> |
| | | 534 | | public static Vector4d Lerp(Vector4d a, Vector4d b, Fixed64 amount) |
| | | 535 | | { |
| | 3 | 536 | | amount = FixedMath.Clamp01(amount); |
| | 3 | 537 | | return UnclampedLerp(a, b, amount); |
| | | 538 | | } |
| | | 539 | | |
| | | 540 | | /// <summary> |
| | | 541 | | /// Linearly interpolates between two vectors without clamping the interpolation amount. |
| | | 542 | | /// </summary> |
| | | 543 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 544 | | public static Vector4d UnclampedLerp(Vector4d a, Vector4d b, Fixed64 t) => |
| | 6 | 545 | | new(a.X + ((b.X - a.X) * t), |
| | 6 | 546 | | a.Y + ((b.Y - a.Y) * t), |
| | 6 | 547 | | a.Z + ((b.Z - a.Z) * t), |
| | 6 | 548 | | a.W + ((b.W - a.W) * t)); |
| | | 549 | | |
| | | 550 | | /// <summary> |
| | | 551 | | /// Normalizes the given vector, returning a unit vector with the same direction. |
| | | 552 | | /// </summary> |
| | | 553 | | public static Vector4d GetNormalized(Vector4d value) |
| | | 554 | | { |
| | 22 | 555 | | bool magnitudeIsRepresentable = TryGetMagnitude( |
| | 22 | 556 | | value, |
| | 22 | 557 | | out Fixed64 mag, |
| | 22 | 558 | | out bool isNormalized); |
| | | 559 | | |
| | 22 | 560 | | if (mag == Fixed64.Zero) |
| | 2 | 561 | | return Zero; |
| | | 562 | | |
| | 20 | 563 | | if (isNormalized) |
| | 2 | 564 | | return value; |
| | | 565 | | |
| | 18 | 566 | | if (!magnitudeIsRepresentable || mag == Fixed64.One) |
| | 2 | 567 | | return WideNormalization.GetNormalized(value); |
| | | 568 | | |
| | 16 | 569 | | if (mag <= FixedMath.ScaleSafeMagnitudeThreshold) |
| | 4 | 570 | | return GetScaleNormalized(value); |
| | | 571 | | |
| | 12 | 572 | | var normalized = new Vector4d( |
| | 12 | 573 | | FixedMath.FastDiv(value.X, mag), |
| | 12 | 574 | | FixedMath.FastDiv(value.Y, mag), |
| | 12 | 575 | | FixedMath.FastDiv(value.Z, mag), |
| | 12 | 576 | | FixedMath.FastDiv(value.W, mag)); |
| | 12 | 577 | | return normalized.IsNormalized() |
| | 12 | 578 | | ? normalized |
| | 12 | 579 | | : WideNormalization.GetNormalized(value); |
| | | 580 | | } |
| | | 581 | | |
| | | 582 | | private static Vector4d GetScaleNormalized(Vector4d value) |
| | | 583 | | { |
| | 5 | 584 | | Fixed64 scale = FixedMath.Max( |
| | 5 | 585 | | FixedMath.Max(value.X.Abs(), value.Y.Abs()), |
| | 5 | 586 | | FixedMath.Max(value.Z.Abs(), value.W.Abs())); |
| | 5 | 587 | | Vector4d scaled = value / scale; |
| | 5 | 588 | | Fixed64 scaledMagnitude = FixedMath.GetScaledMagnitude(scaled.X, scaled.Y, scaled.Z, scaled.W); |
| | 5 | 589 | | return scaled / scaledMagnitude; |
| | | 590 | | } |
| | | 591 | | |
| | | 592 | | /// <summary> |
| | | 593 | | /// Returns the magnitude of the given vector. |
| | | 594 | | /// </summary> |
| | | 595 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 596 | | public static Fixed64 GetMagnitude(Vector4d vector) |
| | | 597 | | { |
| | 16 | 598 | | _ = TryGetMagnitude(vector, out Fixed64 magnitude); |
| | 16 | 599 | | return magnitude; |
| | | 600 | | } |
| | | 601 | | |
| | | 602 | | /// <summary> |
| | | 603 | | /// Attempts to return the magnitude of the given vector without saturating the result. |
| | | 604 | | /// </summary> |
| | | 605 | | /// <param name="vector">The vector to measure.</param> |
| | | 606 | | /// <param name="magnitude">The magnitude, or <see cref="Fixed64.MaxValue"/> when it is not representable.</param> |
| | | 607 | | /// <returns><see langword="true"/> when the magnitude fits in <see cref="Fixed64"/>; otherwise, <see langword="fals |
| | | 608 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 609 | | public static bool TryGetMagnitude(Vector4d vector, out Fixed64 magnitude) => |
| | 23 | 610 | | TryGetMagnitude(vector, out magnitude, out _); |
| | | 611 | | |
| | | 612 | | private static bool TryGetMagnitude( |
| | | 613 | | Vector4d vector, |
| | | 614 | | out Fixed64 magnitude, |
| | | 615 | | out bool isNormalized) |
| | | 616 | | { |
| | 60 | 617 | | Fixed64 mag = (vector.X * vector.X) + (vector.Y * vector.Y) + (vector.Z * vector.Z) + (vector.W * vector.W); |
| | 60 | 618 | | isNormalized = mag != Fixed64.Zero |
| | 60 | 619 | | && FixedMath.Abs(mag - Fixed64.One) <= Fixed64.Epsilon; |
| | | 620 | | |
| | 60 | 621 | | if (mag == Fixed64.MaxValue) |
| | 9 | 622 | | return FixedMath.TryGetScaledMagnitude(vector.X, vector.Y, vector.Z, vector.W, out magnitude); |
| | | 623 | | |
| | 51 | 624 | | if (mag <= FixedMath.ScaleSafeMagnitudeSquaredThreshold) |
| | | 625 | | { |
| | 10 | 626 | | magnitude = FixedMath.GetScaledMagnitude(vector.X, vector.Y, vector.Z, vector.W); |
| | 10 | 627 | | return true; |
| | | 628 | | } |
| | | 629 | | |
| | 41 | 630 | | if (isNormalized) |
| | | 631 | | { |
| | 8 | 632 | | magnitude = Fixed64.One; |
| | 8 | 633 | | return true; |
| | | 634 | | } |
| | | 635 | | |
| | 33 | 636 | | magnitude = FixedMath.Sqrt(mag); |
| | 33 | 637 | | return true; |
| | | 638 | | } |
| | | 639 | | |
| | | 640 | | /// <summary> |
| | | 641 | | /// Compares the exact squared magnitudes of two vectors without fixed-point saturation. |
| | | 642 | | /// </summary> |
| | | 643 | | /// <returns>A negative value when <paramref name="left"/> is shorter, zero when the |
| | | 644 | | /// magnitudes are equal, or a positive value when <paramref name="left"/> is longer.</returns> |
| | | 645 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 646 | | public static int CompareMagnitudeSquared(Vector4d left, Vector4d right) => |
| | 3 | 647 | | Fixed64.CompareMagnitudeSquared( |
| | 3 | 648 | | left.X, |
| | 3 | 649 | | left.Y, |
| | 3 | 650 | | left.Z, |
| | 3 | 651 | | left.W, |
| | 3 | 652 | | right.X, |
| | 3 | 653 | | right.Y, |
| | 3 | 654 | | right.Z, |
| | 3 | 655 | | right.W); |
| | | 656 | | |
| | | 657 | | /// <summary> |
| | | 658 | | /// Returns a new vector containing the absolute value of each component. |
| | | 659 | | /// </summary> |
| | | 660 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 661 | | public static Vector4d Abs(Vector4d value) => |
| | 2 | 662 | | new(FixedMath.Abs(value.X), |
| | 2 | 663 | | FixedMath.Abs(value.Y), |
| | 2 | 664 | | FixedMath.Abs(value.Z), |
| | 2 | 665 | | FixedMath.Abs(value.W)); |
| | | 666 | | |
| | | 667 | | /// <summary> |
| | | 668 | | /// Returns a new vector containing the sign of each component. |
| | | 669 | | /// </summary> |
| | | 670 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 671 | | public static Vector4d Sign(Vector4d value) => |
| | 2 | 672 | | new(value.X.Sign(), |
| | 2 | 673 | | value.Y.Sign(), |
| | 2 | 674 | | value.Z.Sign(), |
| | 2 | 675 | | value.W.Sign()); |
| | | 676 | | |
| | | 677 | | /// <summary> |
| | | 678 | | /// Clamps each component of the given vector within the specified min and max bounds. |
| | | 679 | | /// </summary> |
| | | 680 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 681 | | public static Vector4d Clamp(Vector4d value, Vector4d min, Vector4d max) => |
| | 3 | 682 | | new(FixedMath.Clamp(value.X, min.X, max.X), |
| | 3 | 683 | | FixedMath.Clamp(value.Y, min.Y, max.Y), |
| | 3 | 684 | | FixedMath.Clamp(value.Z, min.Z, max.Z), |
| | 3 | 685 | | FixedMath.Clamp(value.W, min.W, max.W)); |
| | | 686 | | |
| | | 687 | | /// <summary> |
| | | 688 | | /// Computes the midpoint between two vectors. |
| | | 689 | | /// </summary> |
| | | 690 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 691 | | public static Vector4d Midpoint(Vector4d v1, Vector4d v2) => |
| | 4 | 692 | | new(FixedMath.Midpoint(v1.X, v2.X), |
| | 4 | 693 | | FixedMath.Midpoint(v1.Y, v2.Y), |
| | 4 | 694 | | FixedMath.Midpoint(v1.Z, v2.Z), |
| | 4 | 695 | | FixedMath.Midpoint(v1.W, v2.W)); |
| | | 696 | | |
| | | 697 | | /// <inheritdoc cref="Distance(Fixed64, Fixed64, Fixed64, Fixed64)" /> |
| | | 698 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 699 | | public static Fixed64 Distance(Vector4d start, Vector4d end) => |
| | 4 | 700 | | start.Distance(end.X, end.Y, end.Z, end.W); |
| | | 701 | | |
| | | 702 | | /// <inheritdoc cref="DistanceSquared(Fixed64, Fixed64, Fixed64, Fixed64)" /> |
| | | 703 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 704 | | public static Fixed64 DistanceSquared(Vector4d start, Vector4d end) => |
| | 1 | 705 | | start.DistanceSquared(end.X, end.Y, end.Z, end.W); |
| | | 706 | | |
| | | 707 | | /// <summary> |
| | | 708 | | /// Calculates the dot product of two vectors. |
| | | 709 | | /// </summary> |
| | | 710 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 711 | | public static Fixed64 Dot(Vector4d lhs, Vector4d rhs) => |
| | 1 | 712 | | lhs.Dot(rhs.X, rhs.Y, rhs.Z, rhs.W); |
| | | 713 | | |
| | | 714 | | /// <summary> |
| | | 715 | | /// Multiplies two vectors component-wise. |
| | | 716 | | /// </summary> |
| | | 717 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 718 | | public static Vector4d Multiply(Vector4d a, Vector4d b) => |
| | 3 | 719 | | new(a.X * b.X, a.Y * b.Y, a.Z * b.Z, a.W * b.W); |
| | | 720 | | |
| | | 721 | | /// <summary> |
| | | 722 | | /// Multiplies each vector component by the specified scalar. |
| | | 723 | | /// </summary> |
| | | 724 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 725 | | public static Vector4d Multiply(Vector4d value, Fixed64 factor) => value * factor; |
| | | 726 | | |
| | | 727 | | /// <summary> |
| | | 728 | | /// Divides each component of the first vector by the corresponding component of the second vector. |
| | | 729 | | /// </summary> |
| | | 730 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 731 | | public static Vector4d Divide(Vector4d v1, Vector4d v2) => v1 / v2; |
| | | 732 | | |
| | | 733 | | /// <summary> |
| | | 734 | | /// Divides each vector component by the specified scalar. |
| | | 735 | | /// </summary> |
| | | 736 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 737 | | public static Vector4d Divide(Vector4d value, Fixed64 divisor) => value / divisor; |
| | | 738 | | |
| | | 739 | | /// <summary> |
| | | 740 | | /// Returns a vector whose elements are the maximum of each pair of elements. |
| | | 741 | | /// </summary> |
| | | 742 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 743 | | public static Vector4d Max(Vector4d value1, Vector4d value2) => |
| | 3 | 744 | | new(FixedMath.Max(value1.X, value2.X), |
| | 3 | 745 | | FixedMath.Max(value1.Y, value2.Y), |
| | 3 | 746 | | FixedMath.Max(value1.Z, value2.Z), |
| | 3 | 747 | | FixedMath.Max(value1.W, value2.W)); |
| | | 748 | | |
| | | 749 | | /// <summary> |
| | | 750 | | /// Returns a vector whose elements are the minimum of each pair of elements. |
| | | 751 | | /// </summary> |
| | | 752 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 753 | | public static Vector4d Min(Vector4d value1, Vector4d value2) => |
| | 3 | 754 | | new(FixedMath.Min(value1.X, value2.X), |
| | 3 | 755 | | FixedMath.Min(value1.Y, value2.Y), |
| | 3 | 756 | | FixedMath.Min(value1.Z, value2.Z), |
| | 3 | 757 | | FixedMath.Min(value1.W, value2.W)); |
| | | 758 | | |
| | | 759 | | /// <summary> |
| | | 760 | | /// Transforms a 4D vector by a 4x4 matrix. |
| | | 761 | | /// </summary> |
| | | 762 | | /// <remarks> |
| | | 763 | | /// This follows the same row-vector storage convention as <see cref="Fixed4x4.TransformPoint(Fixed4x4, Vector3d)"/> |
| | | 764 | | /// preserving the computed W component instead of performing perspective division. |
| | | 765 | | /// </remarks> |
| | | 766 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 767 | | public static Vector4d Transform(Fixed4x4 matrix, Vector4d vector) => |
| | 10 | 768 | | new(vector.X * matrix.M11 + vector.Y * matrix.M21 + vector.Z * matrix.M31 + vector.W * matrix.M41, |
| | 10 | 769 | | vector.X * matrix.M12 + vector.Y * matrix.M22 + vector.Z * matrix.M32 + vector.W * matrix.M42, |
| | 10 | 770 | | vector.X * matrix.M13 + vector.Y * matrix.M23 + vector.Z * matrix.M33 + vector.W * matrix.M43, |
| | 10 | 771 | | matrix.M14 * vector.X + matrix.M24 * vector.Y + matrix.M34 * vector.Z + matrix.M44 * vector.W); |
| | | 772 | | |
| | | 773 | | #endregion |
| | | 774 | | |
| | | 775 | | #region Operators |
| | | 776 | | |
| | | 777 | | /// <summary> |
| | | 778 | | /// Adds two vectors component-wise. |
| | | 779 | | /// </summary> |
| | | 780 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 2 | 781 | | public static Vector4d operator +(Vector4d v1, Vector4d v2) => new(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z, v1.W + v2. |
| | | 782 | | |
| | | 783 | | /// <summary> |
| | | 784 | | /// Adds a scalar to each component. |
| | | 785 | | /// </summary> |
| | | 786 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 2 | 787 | | public static Vector4d operator +(Vector4d v1, Fixed64 mag) => new(v1.X + mag, v1.Y + mag, v1.Z + mag, v1.W + mag); |
| | | 788 | | |
| | | 789 | | /// <inheritdoc cref="operator +(Vector4d, Fixed64)"/> |
| | | 790 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 791 | | public static Vector4d operator +(Fixed64 mag, Vector4d v1) => v1 + mag; |
| | | 792 | | |
| | | 793 | | /// <summary> |
| | | 794 | | /// Adds a tuple to each component. |
| | | 795 | | /// </summary> |
| | | 796 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 797 | | public static Vector4d operator +(Vector4d v1, (int x, int y, int z, int w) v2) => |
| | 2 | 798 | | new(v1.X + v2.x, v1.Y + v2.y, v1.Z + v2.z, v1.W + v2.w); |
| | | 799 | | |
| | | 800 | | /// <summary> |
| | | 801 | | /// Adds a tuple to each component. |
| | | 802 | | /// </summary> |
| | | 803 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 804 | | public static Vector4d operator +((int x, int y, int z, int w) v2, Vector4d v1) => v1 + v2; |
| | | 805 | | |
| | | 806 | | /// <summary> |
| | | 807 | | /// Subtracts two vectors component-wise. |
| | | 808 | | /// </summary> |
| | | 809 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 810 | | public static Vector4d operator -(Vector4d v1, Vector4d v2) => |
| | 2 | 811 | | new(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z, v1.W - v2.W); |
| | | 812 | | |
| | | 813 | | /// <summary> |
| | | 814 | | /// Subtracts a scalar from each component. |
| | | 815 | | /// </summary> |
| | | 816 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 817 | | public static Vector4d operator -(Vector4d v1, Fixed64 mag) => |
| | 1 | 818 | | new(v1.X - mag, v1.Y - mag, v1.Z - mag, v1.W - mag); |
| | | 819 | | |
| | | 820 | | /// <inheritdoc cref="operator -(Vector4d, Fixed64)"/> |
| | | 821 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 822 | | public static Vector4d operator -(Fixed64 mag, Vector4d v1) => |
| | 1 | 823 | | new(mag - v1.X, mag - v1.Y, mag - v1.Z, mag - v1.W); |
| | | 824 | | |
| | | 825 | | /// <summary> |
| | | 826 | | /// Subtracts a tuple from each component. |
| | | 827 | | /// </summary> |
| | | 828 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 829 | | public static Vector4d operator -(Vector4d v1, (int x, int y, int z, int w) v2) => |
| | 1 | 830 | | new(v1.X - v2.x, v1.Y - v2.y, v1.Z - v2.z, v1.W - v2.w); |
| | | 831 | | |
| | | 832 | | /// <summary> |
| | | 833 | | /// Subtracts each vector component from a tuple component. |
| | | 834 | | /// </summary> |
| | | 835 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 836 | | public static Vector4d operator -((int x, int y, int z, int w) v1, Vector4d v2) => |
| | 1 | 837 | | new(v1.x - v2.X, v1.y - v2.Y, v1.z - v2.Z, v1.w - v2.W); |
| | | 838 | | |
| | | 839 | | /// <summary> |
| | | 840 | | /// Negates the vector. |
| | | 841 | | /// </summary> |
| | | 842 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 843 | | public static Vector4d operator -(Vector4d v1) => |
| | 1 | 844 | | new(-v1.X, -v1.Y, -v1.Z, -v1.W); |
| | | 845 | | |
| | | 846 | | /// <summary> |
| | | 847 | | /// Multiplies each component by a scalar. |
| | | 848 | | /// </summary> |
| | | 849 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 850 | | public static Vector4d operator *(Vector4d v1, Fixed64 mag) => |
| | 6 | 851 | | new(v1.X * mag, v1.Y * mag, v1.Z * mag, v1.W * mag); |
| | | 852 | | |
| | | 853 | | /// <inheritdoc cref="operator *(Vector4d, Fixed64)"/> |
| | | 854 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 2 | 855 | | public static Vector4d operator *(Fixed64 mag, Vector4d v1) => v1 * mag; |
| | | 856 | | |
| | | 857 | | /// <summary> |
| | | 858 | | /// Multiplies each component by an integer scalar. |
| | | 859 | | /// </summary> |
| | | 860 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 2 | 861 | | public static Vector4d operator *(Vector4d v1, int mag) => v1 * (Fixed64)mag; |
| | | 862 | | |
| | | 863 | | /// <inheritdoc cref="operator *(Vector4d, int)"/> |
| | | 864 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 865 | | public static Vector4d operator *(int mag, Vector4d v1) => v1 * mag; |
| | | 866 | | |
| | | 867 | | /// <summary> |
| | | 868 | | /// Multiplies two vectors component-wise. |
| | | 869 | | /// </summary> |
| | | 870 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 871 | | public static Vector4d operator *(Vector4d v1, Vector4d v2) => Multiply(v1, v2); |
| | | 872 | | |
| | | 873 | | /// <summary> |
| | | 874 | | /// Transforms a vector by a 4x4 matrix. |
| | | 875 | | /// </summary> |
| | | 876 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 5 | 877 | | public static Vector4d operator *(Fixed4x4 matrix, Vector4d vector) => Transform(matrix, vector); |
| | | 878 | | |
| | | 879 | | /// <inheritdoc cref="operator *(Fixed4x4, Vector4d)"/> |
| | | 880 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 881 | | public static Vector4d operator *(Vector4d vector, Fixed4x4 matrix) => matrix * vector; |
| | | 882 | | |
| | | 883 | | /// <summary> |
| | | 884 | | /// Divides each component by a scalar. |
| | | 885 | | /// </summary> |
| | | 886 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 19 | 887 | | public static Vector4d operator /(Vector4d v1, Fixed64 div) => new(v1.X / div, v1.Y / div, v1.Z / div, v1.W / div); |
| | | 888 | | |
| | | 889 | | /// <summary> |
| | | 890 | | /// Divides each component by another vector's corresponding component. |
| | | 891 | | /// </summary> |
| | | 892 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 2 | 893 | | public static Vector4d operator /(Vector4d v1, Vector4d v2) => new(v1.X / v2.X, v1.Y / v2.Y, v1.Z / v2.Z, v1.W / v2. |
| | | 894 | | |
| | | 895 | | /// <summary> |
| | | 896 | | /// Divides each component by an integer scalar. |
| | | 897 | | /// </summary> |
| | | 898 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 899 | | public static Vector4d operator /(Vector4d v1, int div) => v1 / (Fixed64)div; |
| | | 900 | | |
| | | 901 | | /// <summary> |
| | | 902 | | /// Compares two vectors for equality. |
| | | 903 | | /// </summary> |
| | | 904 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 905 | | public static bool operator ==(Vector4d left, Vector4d right) => left.Equals(right); |
| | | 906 | | |
| | | 907 | | /// <summary> |
| | | 908 | | /// Compares two vectors for inequality. |
| | | 909 | | /// </summary> |
| | | 910 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 911 | | public static bool operator !=(Vector4d left, Vector4d right) => !left.Equals(right); |
| | | 912 | | |
| | | 913 | | /// <summary> |
| | | 914 | | /// Returns true when every component in the left vector is greater than the corresponding component in the right ve |
| | | 915 | | /// </summary> |
| | | 916 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 917 | | public static bool operator >(Vector4d left, Vector4d right) => |
| | 5 | 918 | | left.X > right.X && left.Y > right.Y && left.Z > right.Z && left.W > right.W; |
| | | 919 | | |
| | | 920 | | /// <summary> |
| | | 921 | | /// Returns true when every component in the left vector is less than the corresponding component in the right vecto |
| | | 922 | | /// </summary> |
| | | 923 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 924 | | public static bool operator <(Vector4d left, Vector4d right) => |
| | 5 | 925 | | left.X < right.X && left.Y < right.Y && left.Z < right.Z && left.W < right.W; |
| | | 926 | | |
| | | 927 | | /// <summary> |
| | | 928 | | /// Returns true when every component in the left vector is greater than or equal to the corresponding component in |
| | | 929 | | /// </summary> |
| | | 930 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 931 | | public static bool operator >=(Vector4d left, Vector4d right) => |
| | 6 | 932 | | left.X >= right.X && left.Y >= right.Y && left.Z >= right.Z && left.W >= right.W; |
| | | 933 | | |
| | | 934 | | /// <summary> |
| | | 935 | | /// Returns true when every component in the left vector is less than or equal to the corresponding component in the |
| | | 936 | | /// </summary> |
| | | 937 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 938 | | public static bool operator <=(Vector4d left, Vector4d right) => |
| | 6 | 939 | | left.X <= right.X && left.Y <= right.Y && left.Z <= right.Z && left.W <= right.W; |
| | | 940 | | |
| | | 941 | | #endregion |
| | | 942 | | |
| | | 943 | | #region Conversion and Formatting |
| | | 944 | | |
| | | 945 | | /// <summary> |
| | | 946 | | /// Returns a string representation of this vector. |
| | | 947 | | /// </summary> |
| | | 948 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 1 | 949 | | public override readonly string ToString() => ToString(null, CultureInfo.InvariantCulture); |
| | | 950 | | |
| | | 951 | | /// <summary> |
| | | 952 | | /// Returns a string representation of this vector. |
| | | 953 | | /// </summary> |
| | | 954 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 955 | | public readonly string ToString(string? format, IFormatProvider? formatProvider) |
| | | 956 | | { |
| | 2 | 957 | | Vector4d value = this; |
| | 2 | 958 | | return FixedDiagnosticsFormatter.ToString((Span<char> destination, out int charsWritten) => |
| | 2 | 959 | | value.TryFormat(destination, out charsWritten, format.AsSpan(), formatProvider)); |
| | | 960 | | } |
| | | 961 | | |
| | | 962 | | /// <summary> |
| | | 963 | | /// Formats this vector into the provided destination buffer. |
| | | 964 | | /// </summary> |
| | | 965 | | public readonly bool TryFormat( |
| | | 966 | | Span<char> destination, |
| | | 967 | | out int charsWritten, |
| | | 968 | | ReadOnlySpan<char> format, |
| | | 969 | | IFormatProvider? provider) |
| | | 970 | | { |
| | 32 | 971 | | int written = 0; |
| | 32 | 972 | | if (!FixedDiagnosticsFormatter.Append('(', destination, ref written) || |
| | 32 | 973 | | !FixedDiagnosticsFormatter.Append(X, destination, ref written, format, provider) || |
| | 32 | 974 | | !FixedDiagnosticsFormatter.Append(", ", destination, ref written) || |
| | 32 | 975 | | !FixedDiagnosticsFormatter.Append(Y, destination, ref written, format, provider) || |
| | 32 | 976 | | !FixedDiagnosticsFormatter.Append(", ", destination, ref written) || |
| | 32 | 977 | | !FixedDiagnosticsFormatter.Append(Z, destination, ref written, format, provider) || |
| | 32 | 978 | | !FixedDiagnosticsFormatter.Append(", ", destination, ref written) || |
| | 32 | 979 | | !FixedDiagnosticsFormatter.Append(W, destination, ref written, format, provider) || |
| | 32 | 980 | | !FixedDiagnosticsFormatter.Append(')', destination, ref written)) |
| | | 981 | | { |
| | 26 | 982 | | charsWritten = 0; |
| | 26 | 983 | | return false; |
| | | 984 | | } |
| | | 985 | | |
| | 6 | 986 | | charsWritten = written; |
| | 6 | 987 | | return true; |
| | | 988 | | } |
| | | 989 | | |
| | | 990 | | /// <summary> |
| | | 991 | | /// Deconstructs the Vector4d into its four Fixed64 components. |
| | | 992 | | /// </summary> |
| | | 993 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 994 | | public void Deconstruct(out Fixed64 x, out Fixed64 y, out Fixed64 z, out Fixed64 w) |
| | | 995 | | { |
| | 1 | 996 | | x = X; |
| | 1 | 997 | | y = Y; |
| | 1 | 998 | | z = Z; |
| | 1 | 999 | | w = W; |
| | 1 | 1000 | | } |
| | | 1001 | | |
| | | 1002 | | /// <summary> |
| | | 1003 | | /// Deconstructs the Vector4d into its four int components. |
| | | 1004 | | /// </summary> |
| | | 1005 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 1006 | | public void Deconstruct(out int x, out int y, out int z, out int w) |
| | | 1007 | | { |
| | 1 | 1008 | | x = X.RoundToInt(); |
| | 1 | 1009 | | y = Y.RoundToInt(); |
| | 1 | 1010 | | z = Z.RoundToInt(); |
| | 1 | 1011 | | w = W.RoundToInt(); |
| | 1 | 1012 | | } |
| | | 1013 | | |
| | | 1014 | | /// <summary> |
| | | 1015 | | /// Deconstructs the Vector4d into its four long components. |
| | | 1016 | | /// </summary> |
| | | 1017 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 1018 | | public void Deconstruct(out long x, out long y, out long z, out long w) |
| | | 1019 | | { |
| | 1 | 1020 | | x = X.m_rawValue; |
| | 1 | 1021 | | y = Y.m_rawValue; |
| | 1 | 1022 | | z = Z.m_rawValue; |
| | 1 | 1023 | | w = W.m_rawValue; |
| | 1 | 1024 | | } |
| | | 1025 | | |
| | | 1026 | | /// <summary> |
| | | 1027 | | /// Deconstructs the Vector4d into its four double components. |
| | | 1028 | | /// </summary> |
| | | 1029 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 1030 | | public void Deconstruct(out double x, out double y, out double z, out double w) |
| | | 1031 | | { |
| | 1 | 1032 | | x = (double)X; |
| | 1 | 1033 | | y = (double)Y; |
| | 1 | 1034 | | z = (double)Z; |
| | 1 | 1035 | | w = (double)W; |
| | 1 | 1036 | | } |
| | | 1037 | | |
| | | 1038 | | #endregion |
| | | 1039 | | |
| | | 1040 | | #region Equality and HashCode Overrides |
| | | 1041 | | |
| | | 1042 | | /// <inheritdoc/> |
| | | 1043 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 2 | 1044 | | public override readonly bool Equals(object? obj) => obj is Vector4d other && Equals(other); |
| | | 1045 | | |
| | | 1046 | | /// <inheritdoc/> |
| | | 1047 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 173 | 1048 | | public readonly bool Equals(Vector4d other) => other.X == X && other.Y == Y && other.Z == Z && other.W == W; |
| | | 1049 | | |
| | | 1050 | | /// <inheritdoc/> |
| | 1 | 1051 | | public readonly bool Equals(Vector4d x, Vector4d y) => x.Equals(y); |
| | | 1052 | | |
| | | 1053 | | /// <summary> |
| | | 1054 | | /// Returns a hash code for this vector based on its state. |
| | | 1055 | | /// </summary> |
| | | 1056 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | 2 | 1057 | | public override readonly int GetHashCode() => StateHash; |
| | | 1058 | | |
| | | 1059 | | /// <inheritdoc/> |
| | 1 | 1060 | | public readonly int GetHashCode(Vector4d obj) => obj.GetHashCode(); |
| | | 1061 | | |
| | | 1062 | | /// <summary> |
| | | 1063 | | /// Compares the current Vector4d instance with another Vector4d based on squared magnitude. |
| | | 1064 | | /// </summary> |
| | 1 | 1065 | | public readonly int CompareTo(Vector4d other) => MagnitudeSquared.CompareTo(other.MagnitudeSquared); |
| | | 1066 | | |
| | | 1067 | | #endregion |
| | | 1068 | | } |