| | 1 | | using System.Diagnostics; |
| | 2 | | using System.Text; |
| | 3 | |
|
| | 4 | | namespace Towel.Mathematics; |
| | 5 | |
|
| | 6 | | /// <summary>Represents a vector with an arbitrary number of components of a generic type.</summary> |
| | 7 | | /// <typeparam name="T">The numeric type of this Vector.</typeparam> |
| | 8 | | [DebuggerDisplay("{" + nameof(DebuggerString) + "}")] |
| | 9 | | public class Vector<T> |
| | 10 | | { |
| | 11 | | internal readonly T[] _vector; |
| | 12 | |
|
| | 13 | | #region Basic Properties |
| | 14 | |
|
| | 15 | | /// <summary>Index 0</summary> |
| | 16 | | public T X |
| | 17 | | { |
| | 18 | | get |
| 0 | 19 | | { |
| 0 | 20 | | if (sourceof(Dimensions < 1, out string c1)) throw new InvalidOperationException(c1); |
| 0 | 21 | | return _vector[0]; |
| 0 | 22 | | } |
| | 23 | | set |
| 0 | 24 | | { |
| 0 | 25 | | if (sourceof(Dimensions < 1, out string c1)) throw new InvalidOperationException(c1); |
| 0 | 26 | | _vector[0] = value; |
| 0 | 27 | | } |
| | 28 | | } |
| | 29 | |
|
| | 30 | | /// <summary>Index 1</summary> |
| | 31 | | public T Y |
| | 32 | | { |
| | 33 | | get |
| 0 | 34 | | { |
| 0 | 35 | | if (sourceof(Dimensions < 2, out string c1)) throw new InvalidOperationException(c1); |
| 0 | 36 | | return _vector[1]; |
| 0 | 37 | | } |
| | 38 | | set |
| 0 | 39 | | { |
| 0 | 40 | | if (sourceof(Dimensions < 2, out string c1)) throw new InvalidOperationException(c1); |
| 0 | 41 | | _vector[1] = value; |
| 0 | 42 | | } |
| | 43 | | } |
| | 44 | |
|
| | 45 | | /// <summary>Index 2</summary> |
| | 46 | | public T Z |
| | 47 | | { |
| | 48 | | get |
| 0 | 49 | | { |
| 0 | 50 | | if (sourceof(Dimensions < 3, out string c1)) throw new InvalidOperationException(c1); |
| 0 | 51 | | return _vector[2]; |
| 0 | 52 | | } |
| | 53 | | set |
| 0 | 54 | | { |
| 0 | 55 | | if (sourceof(Dimensions < 3, out string c1)) throw new InvalidOperationException(c1); |
| 0 | 56 | | _vector[2] = value; |
| 0 | 57 | | } |
| | 58 | | } |
| | 59 | |
|
| | 60 | | /// <summary>The number of components in this vector.</summary> |
| 213 | 61 | | public int Dimensions => _vector is null ? 0 : _vector.Length; |
| | 62 | |
|
| | 63 | | /// <summary>Allows indexed access to this vector.</summary> |
| | 64 | | /// <param name="index">The index to access.</param> |
| | 65 | | /// <returns>The value of the given index.</returns> |
| | 66 | | public T this[int index] |
| | 67 | | { |
| | 68 | | get |
| 12 | 69 | | { |
| 12 | 70 | | if (sourceof(0 > index || index > Dimensions, out string c1)) throw new ArgumentOutOfRangeException(nameof(index), |
| 12 | 71 | | return _vector[index]; |
| 12 | 72 | | } |
| | 73 | | set |
| 0 | 74 | | { |
| 0 | 75 | | if (sourceof(0 > index || index > Dimensions, out string c1)) throw new ArgumentOutOfRangeException(nameof(index), |
| 0 | 76 | | _vector[index] = value; |
| 0 | 77 | | } |
| | 78 | | } |
| | 79 | |
|
| | 80 | | #endregion |
| | 81 | |
|
| | 82 | | #region Debugger Properties |
| | 83 | |
|
| | 84 | | internal string DebuggerString |
| | 85 | | { |
| | 86 | | get |
| 0 | 87 | | { |
| 0 | 88 | | StringBuilder stringBuilder = new(); |
| 0 | 89 | | stringBuilder.Append('['); |
| 0 | 90 | | stringBuilder.Append(_vector[0]); |
| 0 | 91 | | for (int i = 1; i < _vector.Length; i++) |
| 0 | 92 | | { |
| 0 | 93 | | stringBuilder.Append(','); |
| 0 | 94 | | stringBuilder.Append(_vector[i]); |
| 0 | 95 | | } |
| 0 | 96 | | stringBuilder.Append(']'); |
| 0 | 97 | | return stringBuilder.ToString(); |
| 0 | 98 | | } |
| | 99 | | } |
| | 100 | |
|
| | 101 | | #endregion |
| | 102 | |
|
| | 103 | | #region Constructors |
| | 104 | |
|
| | 105 | | /// <summary>Creates a new vector with the given number of components.</summary> |
| | 106 | | /// <param name="dimensions">The number of dimensions this vector will have.</param> |
| 57 | 107 | | public Vector(int dimensions) |
| 57 | 108 | | { |
| 57 | 109 | | if (dimensions < 0) |
| 0 | 110 | | { |
| 0 | 111 | | throw new ArgumentOutOfRangeException(nameof(dimensions), dimensions, "!(" + nameof(dimensions) + " >= 0)"); |
| | 112 | | } |
| 57 | 113 | | _vector = new T[dimensions]; |
| 57 | 114 | | } |
| | 115 | |
|
| | 116 | | /// <summary>Creates a vector out of the given values.</summary> |
| | 117 | | /// <param name="vector">The values to initialize the vector to.</param> |
| 167 | 118 | | public Vector(params T[] vector) |
| 167 | 119 | | { |
| 167 | 120 | | _vector = vector; |
| 167 | 121 | | } |
| | 122 | |
|
| | 123 | | /// <summary>Creates a new vector and initializes it via function.</summary> |
| | 124 | | /// <param name="dimensions">The number of dimensions of the vector to construct.</param> |
| | 125 | | /// <param name="function">The function to initialize the values of the vector.</param> |
| 0 | 126 | | public Vector(int dimensions, Func<int, T> function) : this(dimensions) |
| 0 | 127 | | { |
| 0 | 128 | | for (int i = 0; i < dimensions; i++) |
| 0 | 129 | | { |
| 0 | 130 | | _vector[i] = function(i); |
| 0 | 131 | | } |
| 0 | 132 | | } |
| | 133 | |
|
| 0 | 134 | | internal Vector(Vector<T> vector) |
| 0 | 135 | | { |
| 0 | 136 | | _vector = (T[])vector._vector.Clone(); |
| 0 | 137 | | } |
| | 138 | |
|
| | 139 | | #endregion |
| | 140 | |
|
| | 141 | | #region Factories |
| | 142 | |
|
| | 143 | | /// <summary>Creates a vector with the given number of components with the values initialized to zeroes.</summary> |
| | 144 | | /// <param name="dimensions">The number of components in the vector.</param> |
| | 145 | | /// <returns>The newly constructed vector.</returns> |
| | 146 | | public static Vector<T> FactoryZero(int dimensions) |
| 0 | 147 | | { |
| 0 | 148 | | return FactoryZeroImplementation(dimensions); |
| 0 | 149 | | } |
| | 150 | |
|
| 0 | 151 | | internal static Func<int, Vector<T>> FactoryZeroImplementation = dimensions => |
| 0 | 152 | | { |
| 0 | 153 | | if (Equate(default, Constant<T>.Zero)) |
| 0 | 154 | | { |
| 0 | 155 | | FactoryZeroImplementation = DIMENSIONS => new Vector<T>(DIMENSIONS); |
| 0 | 156 | | } |
| 0 | 157 | | else |
| 0 | 158 | | { |
| 0 | 159 | | FactoryZeroImplementation = DIMENSIONS => |
| 0 | 160 | | { |
| 0 | 161 | | T[] vector = new T[DIMENSIONS]; |
| 0 | 162 | | vector.Format(Constant<T>.Zero); |
| 0 | 163 | | return new Vector<T>(vector); |
| 0 | 164 | | }; |
| 0 | 165 | | } |
| 0 | 166 | | return FactoryZeroImplementation(dimensions); |
| 0 | 167 | | }; |
| | 168 | |
|
| | 169 | | /// <summary>Creates a vector with the given number of components with the values initialized to ones.</summary> |
| | 170 | | /// <param name="dimensions">The number of components in the vector.</param> |
| | 171 | | /// <returns>The newly constructed vector.</returns> |
| | 172 | | public static Vector<T> FactoryOne(int dimensions) |
| 0 | 173 | | { |
| 0 | 174 | | return FactoryOneImplementation(dimensions); |
| 0 | 175 | | } |
| | 176 | |
|
| 0 | 177 | | internal static Func<int, Vector<T>> FactoryOneImplementation = dimensions => |
| 0 | 178 | | { |
| 0 | 179 | | if (Equate(default, Constant<T>.One)) |
| 0 | 180 | | { |
| 0 | 181 | | FactoryZeroImplementation = DIMENSIONS => new Vector<T>(DIMENSIONS); |
| 0 | 182 | | } |
| 0 | 183 | | else |
| 0 | 184 | | { |
| 0 | 185 | | FactoryZeroImplementation = DIMENSIONS => |
| 0 | 186 | | { |
| 0 | 187 | | T[] vector = new T[DIMENSIONS]; |
| 0 | 188 | | vector.Format(Constant<T>.One); |
| 0 | 189 | | return new Vector<T>(vector); |
| 0 | 190 | | }; |
| 0 | 191 | | } |
| 0 | 192 | | return FactoryZeroImplementation(dimensions); |
| 0 | 193 | | }; |
| | 194 | |
|
| | 195 | | #endregion |
| | 196 | |
|
| | 197 | | #region Mathematics |
| | 198 | |
|
| | 199 | | #region Magnitude |
| | 200 | |
|
| | 201 | | /// <summary>Computes the length of this vector.</summary> |
| | 202 | | /// <param name="a">The <see cref="Vector{T}"/> to get the magnitude of.</param> |
| | 203 | | /// <returns>The length of this vector.</returns> |
| | 204 | | public static T GetMagnitude(Vector<T> a) |
| 12 | 205 | | { |
| 12 | 206 | | if (a is null) throw new ArgumentNullException(nameof(a)); |
| 12 | 207 | | return SquareRoot(GetMagnitudeSquared(a)); |
| 12 | 208 | | } |
| | 209 | |
|
| | 210 | | /// <summary>Computes the length of this vector.</summary> |
| 12 | 211 | | public T Magnitude => GetMagnitude(this); |
| | 212 | |
|
| | 213 | | #endregion |
| | 214 | |
|
| | 215 | | #region MagnitudeSquared |
| | 216 | |
|
| | 217 | | /// <summary>Computes the length of this vector, but doesn't square root it for |
| | 218 | | /// possible optimization purposes.</summary> |
| | 219 | | /// <param name="a">The <see cref="Vector{T}"/> to get the magnitude squared of.</param> |
| | 220 | | /// <returns>The squared length of the vector.</returns> |
| | 221 | | public static T GetMagnitudeSquared(Vector<T> a) |
| 18 | 222 | | { |
| 18 | 223 | | if (a is null) throw new ArgumentNullException(nameof(a)); |
| 18 | 224 | | int Length = a.Dimensions; |
| 18 | 225 | | T result = Constant<T>.Zero; |
| 18 | 226 | | T[] A = a._vector; |
| 162 | 227 | | for (int i = 0; i < Length; i++) |
| 63 | 228 | | { |
| 63 | 229 | | result = MultiplyAddImplementation<T>.Function(A[i], A[i], result); |
| 63 | 230 | | } |
| 18 | 231 | | return result; |
| 18 | 232 | | } |
| | 233 | |
|
| | 234 | | /// <summary>Computes the length of this vector, but doesn't square root it for |
| | 235 | | /// possible optimization purposes.</summary> |
| 6 | 236 | | public T MagnitudeSquared => GetMagnitudeSquared(this); |
| | 237 | |
|
| | 238 | | #endregion |
| | 239 | |
|
| | 240 | | #region Negate |
| | 241 | |
|
| | 242 | | /// <summary>Negates all the values in a vector.</summary> |
| | 243 | | /// <param name="a">The vector to have its values negated.</param> |
| | 244 | | /// <param name="b">The result of the negations.</param> |
| | 245 | | public static void Negate(Vector<T> a, ref Vector<T>? b) |
| 4 | 246 | | { |
| 4 | 247 | | if (a is null) throw new ArgumentNullException(nameof(a)); |
| 4 | 248 | | T[] A = a._vector; |
| 4 | 249 | | int Length = A.Length; |
| | 250 | | T[] B; |
| 4 | 251 | | if (b is null || b.Dimensions != Length) |
| 4 | 252 | | { |
| 4 | 253 | | b = new Vector<T>(Length); |
| 4 | 254 | | B = b._vector; |
| 4 | 255 | | } |
| | 256 | | else |
| 0 | 257 | | { |
| 0 | 258 | | B = b._vector; |
| 0 | 259 | | if (B.Length != Length) |
| 0 | 260 | | { |
| 0 | 261 | | b = new Vector<T>(Length); |
| 0 | 262 | | B = b._vector; |
| 0 | 263 | | } |
| 0 | 264 | | } |
| 32 | 265 | | for (int i = 0; i < Length; i++) |
| 12 | 266 | | { |
| 12 | 267 | | B[i] = Statics.Negation(A[i]); |
| 12 | 268 | | } |
| 4 | 269 | | } |
| | 270 | |
|
| | 271 | | /// <summary>Negates all the values in a vector.</summary> |
| | 272 | | /// <param name="a">The vector to have its values negated.</param> |
| | 273 | | /// <returns>The result of the negations.</returns> |
| | 274 | | public static Vector<T> Negate(Vector<T> a) |
| 4 | 275 | | { |
| 4 | 276 | | Vector<T>? b = null; |
| 4 | 277 | | Negate(a, ref b); |
| 4 | 278 | | return b!; |
| 4 | 279 | | } |
| | 280 | |
|
| | 281 | | /// <summary>Negates a vector.</summary> |
| | 282 | | /// <param name="vector">The vector to negate.</param> |
| | 283 | | /// <returns>The result of the negation.</returns> |
| | 284 | | public static Vector<T> operator -(Vector<T> vector) |
| 4 | 285 | | { |
| 4 | 286 | | return Negate(vector); |
| 4 | 287 | | } |
| | 288 | |
|
| | 289 | | /// <summary>Negates all the values in a vector.</summary> |
| | 290 | | /// <param name="b">The result of the negations.</param> |
| | 291 | | public void Negate(ref Vector<T>? b) |
| 0 | 292 | | { |
| 0 | 293 | | Negate(this, ref b); |
| 0 | 294 | | } |
| | 295 | |
|
| | 296 | | /// <summary>Negates this vector.</summary> |
| | 297 | | /// <returns>The result of the negation.</returns> |
| | 298 | | public Vector<T> Negate() |
| 0 | 299 | | { |
| 0 | 300 | | return -this; |
| 0 | 301 | | } |
| | 302 | |
|
| | 303 | | #endregion |
| | 304 | |
|
| | 305 | | #region Add |
| | 306 | |
|
| | 307 | | /// <summary>Adds two vectors together.</summary> |
| | 308 | | /// <param name="a">The first vector of the addition.</param> |
| | 309 | | /// <param name="b">The second vector of the addiiton.</param> |
| | 310 | | /// <param name="c">The result of the addition.</param> |
| | 311 | | public static void Add(Vector<T> a, Vector<T> b, ref Vector<T>? c) |
| 8 | 312 | | { |
| 8 | 313 | | if (a is null) throw new ArgumentNullException(nameof(a)); |
| 8 | 314 | | if (b is null) throw new ArgumentNullException(nameof(b)); |
| 8 | 315 | | T[] A = a._vector; |
| 8 | 316 | | T[] B = b._vector; |
| 8 | 317 | | int Length = A.Length; |
| 8 | 318 | | if (sourceof(Length != B.Length, out string c1)) throw new ArgumentException(c1); |
| | 319 | | T[] C; |
| 8 | 320 | | if (c is null) |
| 8 | 321 | | { |
| 8 | 322 | | c = new Vector<T>(Length); |
| 8 | 323 | | C = c._vector; |
| 8 | 324 | | } |
| | 325 | | else |
| 0 | 326 | | { |
| 0 | 327 | | C = c._vector; |
| 0 | 328 | | if (C.Length != Length) |
| 0 | 329 | | { |
| 0 | 330 | | c = new Vector<T>(Length); |
| 0 | 331 | | C = c._vector; |
| 0 | 332 | | } |
| 0 | 333 | | } |
| 64 | 334 | | for (int i = 0; i < Length; i++) |
| 24 | 335 | | { |
| 24 | 336 | | C[i] = Statics.Addition(A[i], B[i]); |
| 24 | 337 | | } |
| 8 | 338 | | } |
| | 339 | |
|
| | 340 | | /// <summary>Adds two vectors together.</summary> |
| | 341 | | /// <param name="a">The first vector of the addition.</param> |
| | 342 | | /// <param name="b">The second vector of the addiiton.</param> |
| | 343 | | /// <returns>The result of the addition.</returns> |
| | 344 | | public static Vector<T> Add(Vector<T> a, Vector<T> b) |
| 8 | 345 | | { |
| 8 | 346 | | Vector<T>? c = null; |
| 8 | 347 | | Add(a, b, ref c); |
| 8 | 348 | | return c!; |
| 8 | 349 | | } |
| | 350 | |
|
| | 351 | | /// <summary>Adds two vectors together.</summary> |
| | 352 | | /// <param name="a">The first vector of the addition.</param> |
| | 353 | | /// <param name="b">The second vector of the addition.</param> |
| | 354 | | /// <returns>The result of the addition.</returns> |
| | 355 | | public static Vector<T> operator +(Vector<T> a, Vector<T> b) |
| 8 | 356 | | { |
| 8 | 357 | | return Add(a, b); |
| 8 | 358 | | } |
| | 359 | |
|
| | 360 | | /// <summary>Adds two vectors together.</summary> |
| | 361 | | /// <param name="b">The second vector of the addition.</param> |
| | 362 | | /// <param name="c">The result of the addition.</param> |
| | 363 | | public void Add(Vector<T> b, ref Vector<T>? c) |
| 0 | 364 | | { |
| 0 | 365 | | Add(this, b, ref c); |
| 0 | 366 | | } |
| | 367 | |
|
| | 368 | | /// <summary>Adds two vectors together.</summary> |
| | 369 | | /// <param name="b">The vector to add to this one.</param> |
| | 370 | | /// <returns>The result of the addition.</returns> |
| | 371 | | public Vector<T> Add(Vector<T> b) |
| 0 | 372 | | { |
| 0 | 373 | | return this + b; |
| 0 | 374 | | } |
| | 375 | |
|
| | 376 | | #endregion |
| | 377 | |
|
| | 378 | | #region Subtract |
| | 379 | |
|
| | 380 | | /// <summary>Subtracts two vectors.</summary> |
| | 381 | | /// <param name="a">The left vector of the subtraction.</param> |
| | 382 | | /// <param name="b">The right vector of the subtraction.</param> |
| | 383 | | /// <param name="c">The result of the vector subtracton.</param> |
| | 384 | | public static void Subtract(Vector<T> a, Vector<T> b, ref Vector<T>? c) |
| 8 | 385 | | { |
| 8 | 386 | | if (a is null) throw new ArgumentNullException(nameof(a)); |
| 8 | 387 | | if (b is null) throw new ArgumentNullException(nameof(b)); |
| 8 | 388 | | T[] A = a._vector; |
| 8 | 389 | | T[] B = b._vector; |
| 8 | 390 | | int Length = A.Length; |
| 8 | 391 | | if (sourceof(Length != B.Length, out string c1)) throw new ArgumentException(c1); |
| | 392 | | T[] C; |
| 8 | 393 | | if (c is null) |
| 8 | 394 | | { |
| 8 | 395 | | c = new Vector<T>(Length); |
| 8 | 396 | | C = c._vector; |
| 8 | 397 | | } |
| | 398 | | else |
| 0 | 399 | | { |
| 0 | 400 | | C = c._vector; |
| 0 | 401 | | if (C.Length != Length) |
| 0 | 402 | | { |
| 0 | 403 | | c = new Vector<T>(Length); |
| 0 | 404 | | C = c._vector; |
| 0 | 405 | | } |
| 0 | 406 | | } |
| 64 | 407 | | for (int i = 0; i < Length; i++) |
| 24 | 408 | | { |
| 24 | 409 | | C[i] = Subtraction(A[i], B[i]); |
| 24 | 410 | | } |
| 8 | 411 | | } |
| | 412 | |
|
| | 413 | | /// <summary>Subtracts two vectors.</summary> |
| | 414 | | /// <param name="a">The left vector of the subtraction.</param> |
| | 415 | | /// <param name="b">The right vector of the subtraction.</param> |
| | 416 | | /// <returns>The result of the vector subtracton.</returns> |
| | 417 | | public static Vector<T> Subtract(Vector<T> a, Vector<T> b) |
| 8 | 418 | | { |
| 8 | 419 | | Vector<T>? c = null; |
| 8 | 420 | | Subtract(a, b, ref c); |
| 8 | 421 | | return c!; |
| 8 | 422 | | } |
| | 423 | |
|
| | 424 | | /// <summary>Subtracts two vectors.</summary> |
| | 425 | | /// <param name="a">The left operand of the subtraction.</param> |
| | 426 | | /// <param name="b">The right operand of the subtraction.</param> |
| | 427 | | /// <returns>The result of the subtraction.</returns> |
| | 428 | | public static Vector<T> operator -(Vector<T> a, Vector<T> b) |
| 8 | 429 | | { |
| 8 | 430 | | return Subtract(a, b); |
| 8 | 431 | | } |
| | 432 | |
|
| | 433 | | /// <summary>Subtracts two vectors.</summary> |
| | 434 | | /// <param name="b">The right vector of the subtraction.</param> |
| | 435 | | /// <param name="c">The result of the vector subtracton.</param> |
| | 436 | | public void Subtract(Vector<T> b, ref Vector<T>? c) |
| 0 | 437 | | { |
| 0 | 438 | | Subtract(this, b, ref c); |
| 0 | 439 | | } |
| | 440 | |
|
| | 441 | | /// <summary>Subtracts another vector from this one.</summary> |
| | 442 | | /// <param name="b">The vector to subtract from this one.</param> |
| | 443 | | /// <returns>The result of the subtraction.</returns> |
| | 444 | | public Vector<T> Subtract(Vector<T> b) |
| 0 | 445 | | { |
| 0 | 446 | | return this - b; |
| 0 | 447 | | } |
| | 448 | |
|
| | 449 | | #endregion |
| | 450 | |
|
| | 451 | | #region Multiply |
| | 452 | |
|
| | 453 | | /// <summary>Multiplies all the values in a vector by a scalar.</summary> |
| | 454 | | /// <param name="a">The vector to have all its values multiplied.</param> |
| | 455 | | /// <param name="b">The scalar to multiply all the vector values by.</param> |
| | 456 | | /// <param name="c">The result of the multiplication.</param> |
| | 457 | | public static void Multiply(Vector<T> a, T b, ref Vector<T>? c) |
| 11 | 458 | | { |
| 11 | 459 | | if (a is null) throw new ArgumentNullException(nameof(a)); |
| 11 | 460 | | T[] A = a._vector; |
| 11 | 461 | | int Length = A.Length; |
| | 462 | | T[] C; |
| 11 | 463 | | if (c is null) |
| 8 | 464 | | { |
| 8 | 465 | | c = new Vector<T>(Length); |
| 8 | 466 | | C = c._vector; |
| 8 | 467 | | } |
| | 468 | | else |
| 3 | 469 | | { |
| 3 | 470 | | C = c._vector; |
| 3 | 471 | | if (C.Length != Length) |
| 0 | 472 | | { |
| 0 | 473 | | c = new Vector<T>(Length); |
| 0 | 474 | | C = c._vector; |
| 0 | 475 | | } |
| 3 | 476 | | } |
| 88 | 477 | | for (int i = 0; i < Length; i++) |
| 33 | 478 | | { |
| 33 | 479 | | C[i] = Multiplication(A[i], b); |
| 33 | 480 | | } |
| 11 | 481 | | } |
| | 482 | |
|
| | 483 | | /// <summary>Multiplies all the values in a vector by a scalar.</summary> |
| | 484 | | /// <param name="a">The vector to have all its values multiplied.</param> |
| | 485 | | /// <param name="b">The scalar to multiply all the vector values by.</param> |
| | 486 | | /// <returns>The result of the multiplication.</returns> |
| | 487 | | public static Vector<T> Multiply(Vector<T> a, T b) |
| 8 | 488 | | { |
| 8 | 489 | | Vector<T>? c = null; |
| 8 | 490 | | Multiply(a, b, ref c); |
| 8 | 491 | | return c!; |
| 8 | 492 | | } |
| | 493 | |
|
| | 494 | | /// <summary>Multiplies all the values in a vector by a scalar.</summary> |
| | 495 | | /// <param name="a">The vector to have all its values multiplied.</param> |
| | 496 | | /// <param name="b">The scalar to multiply all the vector values by.</param> |
| | 497 | | /// <returns>The result of the multiplication.</returns> |
| | 498 | | public static Vector<T> operator *(Vector<T> a, T b) |
| 8 | 499 | | { |
| 8 | 500 | | return Multiply(a, b); |
| 8 | 501 | | } |
| | 502 | |
|
| | 503 | | /// <summary>Multiplies all the values in a vector by a scalar.</summary> |
| | 504 | | /// <param name="a">The scalar to multiply all the vector values by.</param> |
| | 505 | | /// <param name="b">The vector to have all its values multiplied.</param> |
| | 506 | | /// <returns>The result of the multiplication.</returns> |
| | 507 | | public static Vector<T> operator *(T a, Vector<T> b) |
| 0 | 508 | | { |
| 0 | 509 | | return Multiply(b, a); |
| 0 | 510 | | } |
| | 511 | |
|
| | 512 | | /// <summary>Multiplies all the values in a vector by a scalar.</summary> |
| | 513 | | /// <param name="b">The scalar to multiply all the vector values by.</param> |
| | 514 | | /// <param name="c">The result of the multiplication.</param> |
| | 515 | | public void Multiply(T b, ref Vector<T>? c) |
| 3 | 516 | | { |
| 3 | 517 | | Multiply(this, b, ref c); |
| 3 | 518 | | } |
| | 519 | |
|
| | 520 | | /// <summary>Multiplies the values in this vector by a scalar.</summary> |
| | 521 | | /// <param name="b">The scalar to multiply these values by.</param> |
| | 522 | | /// <returns>The result of the multiplications</returns> |
| | 523 | | public Vector<T> Multiply(T b) |
| 0 | 524 | | { |
| 0 | 525 | | return this * b; |
| 0 | 526 | | } |
| | 527 | |
|
| | 528 | | #endregion |
| | 529 | |
|
| | 530 | | #region Divide |
| | 531 | |
|
| | 532 | | /// <summary>Divides all the components of a vector by a scalar.</summary> |
| | 533 | | /// <param name="a">The vector to have the components divided by.</param> |
| | 534 | | /// <param name="b">The scalar to divide the vector components by.</param> |
| | 535 | | /// <param name="c">The resulting vector after the divisions.</param> |
| | 536 | | public static void Divide(Vector<T> a, T b, ref Vector<T>? c) |
| 8 | 537 | | { |
| 8 | 538 | | if (a is null) throw new ArgumentNullException(nameof(a)); |
| 8 | 539 | | T[] A = a._vector; |
| 8 | 540 | | int Length = A.Length; |
| | 541 | | T[] C; |
| 8 | 542 | | if (c is null) |
| 8 | 543 | | { |
| 8 | 544 | | c = new Vector<T>(Length); |
| 8 | 545 | | C = c._vector; |
| 8 | 546 | | } |
| | 547 | | else |
| 0 | 548 | | { |
| 0 | 549 | | C = c._vector; |
| 0 | 550 | | if (C.Length != Length) |
| 0 | 551 | | { |
| 0 | 552 | | c = new Vector<T>(Length); |
| 0 | 553 | | C = c._vector; |
| 0 | 554 | | } |
| 0 | 555 | | } |
| 64 | 556 | | for (int i = 0; i < Length; i++) |
| 24 | 557 | | { |
| 24 | 558 | | C[i] = Division(A[i], b); |
| 24 | 559 | | } |
| 8 | 560 | | } |
| | 561 | |
|
| | 562 | | /// <summary>Divides all the components of a vector by a scalar.</summary> |
| | 563 | | /// <param name="a">The vector to have the components divided by.</param> |
| | 564 | | /// <param name="b">The scalar to divide the vector components by.</param> |
| | 565 | | /// <returns>The resulting vector after the divisions.</returns> |
| | 566 | | public static Vector<T> Divide(Vector<T> a, T b) |
| 8 | 567 | | { |
| 8 | 568 | | Vector<T>? c = null; |
| 8 | 569 | | Divide(a, b, ref c); |
| 8 | 570 | | return c!; |
| 8 | 571 | | } |
| | 572 | |
|
| | 573 | | /// <summary>Divides all the values in the vector by a scalar.</summary> |
| | 574 | | /// <param name="a">The vector to have its values divided.</param> |
| | 575 | | /// <param name="b">The scalar to divide all the vectors values by.</param> |
| | 576 | | /// <returns>The vector after the divisions.</returns> |
| 8 | 577 | | public static Vector<T> operator /(Vector<T> a, T b) => Divide(a, b); |
| | 578 | |
|
| | 579 | | /// <summary>Divides all the components of a vector by a scalar.</summary> |
| | 580 | | /// <param name="b">The scalar to divide the vector components by.</param> |
| | 581 | | /// <param name="c">The resulting vector after the divisions.</param> |
| 0 | 582 | | public void Divide(T b, ref Vector<T>? c) => Divide(this, b, ref c); |
| | 583 | |
|
| | 584 | | /// <summary>Divides all the values in this vector by a scalar.</summary> |
| | 585 | | /// <param name="b">The scalar to divide the values of the vector by.</param> |
| | 586 | | /// <returns>The resulting vector after the divisions.</returns> |
| 0 | 587 | | public Vector<T> Divide(T b) => this / b; |
| | 588 | |
|
| | 589 | | #endregion |
| | 590 | |
|
| | 591 | | #region DotProduct |
| | 592 | |
|
| | 593 | | /// <summary>Computes the dot product between two vectors.</summary> |
| | 594 | | /// <param name="a">The first vector of the dot product operation.</param> |
| | 595 | | /// <param name="b">The second vector of the dot product operation.</param> |
| | 596 | | /// <returns>The result of the dot product operation.</returns> |
| | 597 | | public static T DotProduct(Vector<T> a, Vector<T> b) |
| 11 | 598 | | { |
| 11 | 599 | | if (a is null) throw new ArgumentNullException(nameof(a)); |
| 11 | 600 | | if (b is null) throw new ArgumentNullException(nameof(b)); |
| 11 | 601 | | int Length = a.Dimensions; |
| 12 | 602 | | if (sourceof(Length != b.Dimensions, out string c1)) throw new ArgumentException(c1); |
| 10 | 603 | | T result = Constant<T>.Zero; |
| 10 | 604 | | T[] A = a._vector; |
| 10 | 605 | | T[] B = b._vector; |
| 80 | 606 | | for (int i = 0; i < Length; i++) |
| 30 | 607 | | { |
| 30 | 608 | | result = MultiplyAddImplementation<T>.Function(A[i], B[i], result); |
| 30 | 609 | | } |
| 10 | 610 | | return result; |
| 10 | 611 | | } |
| | 612 | |
|
| | 613 | | /// <summary>Computes the dot product between this vector and another.</summary> |
| | 614 | | /// <param name="right">The second vector of the dot product operation.</param> |
| | 615 | | /// <returns>The result of the dot product.</returns> |
| | 616 | | public T DotProduct(Vector<T> right) |
| 11 | 617 | | { |
| 11 | 618 | | return DotProduct(this, right); |
| 10 | 619 | | } |
| | 620 | |
|
| | 621 | | #endregion |
| | 622 | |
|
| | 623 | | #region CrossProduct |
| | 624 | |
|
| | 625 | | /// <summary>Computes the cross product of two vectors.</summary> |
| | 626 | | /// <param name="a">The first vector of the cross product operation.</param> |
| | 627 | | /// <param name="b">The second vector of the cross product operation.</param> |
| | 628 | | /// <param name="c">The result of the cross product operation.</param> |
| | 629 | | public static void CrossProduct(Vector<T> a, Vector<T> b, ref Vector<T>? c) |
| 5 | 630 | | { |
| 5 | 631 | | if (a is null) throw new ArgumentNullException(nameof(a)); |
| 5 | 632 | | if (b is null) throw new ArgumentNullException(nameof(b)); |
| 5 | 633 | | T[] A = a._vector; |
| 5 | 634 | | T[] B = b._vector; |
| 6 | 635 | | if (sourceof(A.Length != 3, out string c1)) throw new ArgumentException(c1); |
| 4 | 636 | | if (sourceof(B.Length != 3, out string c2)) throw new ArgumentException(c2); |
| 4 | 637 | | if (c is null || c.Dimensions != 3) |
| 4 | 638 | | { |
| 4 | 639 | | c = new Vector<T>(3); |
| 4 | 640 | | } |
| 4 | 641 | | T[] C = c._vector; |
| 4 | 642 | | C[0] = Subtraction(Multiplication(A[1], B[2]), Multiplication(A[2], B[1])); |
| 4 | 643 | | C[1] = Subtraction(Multiplication(A[2], B[0]), Multiplication(A[0], B[2])); |
| 4 | 644 | | C[2] = Subtraction(Multiplication(A[0], B[1]), Multiplication(A[1], B[0])); |
| 4 | 645 | | } |
| | 646 | |
|
| | 647 | | /// <summary>Computes the cross product of two vectors.</summary> |
| | 648 | | /// <param name="a">The first vector of the cross product operation.</param> |
| | 649 | | /// <param name="b">The second vector of the cross product operation.</param> |
| | 650 | | /// <returns>The result of the cross product operation.</returns> |
| | 651 | | public static Vector<T> CrossProduct(Vector<T> a, Vector<T> b) |
| 5 | 652 | | { |
| 5 | 653 | | Vector<T>? c = null; |
| 5 | 654 | | CrossProduct(a, b, ref c); |
| 4 | 655 | | return c!; |
| 4 | 656 | | } |
| | 657 | |
|
| | 658 | | /// <summary>Computes the cross product of two vectors.</summary> |
| | 659 | | /// <param name="b">The second vector of the cross product operation.</param> |
| | 660 | | /// <param name="c">The result of the cross product operation.</param> |
| | 661 | | public void CrossProduct(Vector<T> b, ref Vector<T>? c) |
| 0 | 662 | | { |
| 0 | 663 | | CrossProduct(this, b, ref c); |
| 0 | 664 | | } |
| | 665 | |
|
| | 666 | | /// <summary>Computes the cross product of two vectors.</summary> |
| | 667 | | /// <param name="b">The second vector of the dot product operation.</param> |
| | 668 | | /// <returns>The result of the dot product operation.</returns> |
| | 669 | | public Vector<T> CrossProduct(Vector<T> b) |
| 5 | 670 | | { |
| 5 | 671 | | return CrossProduct(this, b); |
| 4 | 672 | | } |
| | 673 | |
|
| | 674 | | #endregion |
| | 675 | |
|
| | 676 | | #region Normalize |
| | 677 | |
|
| | 678 | | /// <summary>Normalizes a vector.</summary> |
| | 679 | | /// <param name="a">The vector to normalize.</param> |
| | 680 | | /// <param name="b">The result of the normalization.</param> |
| | 681 | | public static void Normalize(Vector<T> a, ref Vector<T>? b) |
| 3 | 682 | | { |
| 3 | 683 | | if (a is null) throw new ArgumentNullException(nameof(a)); |
| 3 | 684 | | if (sourceof(a.Dimensions < 1, out string c1)) throw new ArgumentOutOfRangeException(nameof(a), a, c1); |
| 3 | 685 | | T magnitude = a.Magnitude; |
| 3 | 686 | | if (Equate(magnitude, Constant<T>.Zero)) |
| 0 | 687 | | { |
| 0 | 688 | | throw new ArgumentOutOfRangeException(nameof(a), a, "!(" + nameof(a) + "." + nameof(a.Magnitude) + " > 0)"); |
| | 689 | | } |
| 3 | 690 | | if (b is null || b.Dimensions != a.Dimensions) |
| 3 | 691 | | { |
| 3 | 692 | | b = new Vector<T>(a.Dimensions); |
| 3 | 693 | | } |
| 30 | 694 | | for (int i = 0; i < a.Dimensions; i++) |
| 12 | 695 | | { |
| 12 | 696 | | b._vector[i] = Division(a[i], magnitude); |
| 12 | 697 | | } |
| 3 | 698 | | } |
| | 699 | |
|
| | 700 | | /// <summary>Normalizes a vector.</summary> |
| | 701 | | /// <param name="a">The vector to normalize.</param> |
| | 702 | | /// <returns>The result of the normalization.</returns> |
| | 703 | | public static Vector<T> Normalize(Vector<T> a) |
| 3 | 704 | | { |
| 3 | 705 | | Vector<T>? b = null; |
| 3 | 706 | | Normalize(a, ref b); |
| 3 | 707 | | return b!; |
| 3 | 708 | | } |
| | 709 | |
|
| | 710 | | /// <summary>Normalizes a vector.</summary> |
| | 711 | | /// <param name="b">The result of the normalization.</param> |
| | 712 | | public void Normalize(ref Vector<T>? b) |
| 0 | 713 | | { |
| 0 | 714 | | Normalize(this, ref b); |
| 0 | 715 | | } |
| | 716 | |
|
| | 717 | | /// <summary>Normalizes this vector.</summary> |
| | 718 | | /// <returns>The result of the normalization.</returns> |
| | 719 | | public Vector<T> Normalize() |
| 3 | 720 | | { |
| 3 | 721 | | return Normalize(this); |
| 3 | 722 | | } |
| | 723 | |
|
| | 724 | | #endregion |
| | 725 | |
|
| | 726 | | #region Angle |
| | 727 | |
|
| | 728 | | /// <summary>Computes the angle between two vectors.</summary> |
| | 729 | | /// <typeparam name="TArcCos">A type of function for how to compute the inverse of a cosine ratio.</typeparam> |
| | 730 | | /// <param name="a">The first vector to determine the angle between.</param> |
| | 731 | | /// <param name="b">The second vector to determine the angle between.</param> |
| | 732 | | /// <param name="arccos">A function for how to compute the inverse of a cosine ratio.</param> |
| | 733 | | /// <returns>The angle between the two vectors in radians.</returns> |
| | 734 | | public static Angle<T> Angle<TArcCos>(Vector<T> a, Vector<T> b, TArcCos arccos = default) |
| | 735 | | where TArcCos : struct, IFunc<T, Angle<T>> |
| 3 | 736 | | { |
| | 737 | | // a ⋅ b = |a| * |b| * cosθ |
| | 738 | |
|
| 3 | 739 | | if (a is null) throw new ArgumentNullException(nameof(a)); |
| 3 | 740 | | if (b is null) throw new ArgumentNullException(nameof(b)); |
| 3 | 741 | | T dotProduct = a.DotProduct(b); |
| 3 | 742 | | T aMagTimesbMag = Multiplication(a.Magnitude, b.Magnitude); |
| 3 | 743 | | T divided = Division(dotProduct, aMagTimesbMag); |
| 3 | 744 | | return arccos.Invoke(divided); |
| 3 | 745 | | } |
| | 746 | |
|
| | 747 | | /// <summary>Computes the angle between two vectors.</summary> |
| | 748 | | /// <param name="a">The first vector to determine the angle between.</param> |
| | 749 | | /// <param name="b">The second vector to determine the angle between.</param> |
| | 750 | | /// <param name="arccos">A delegate for how to compute the inverse of a cosine ratio.</param> |
| | 751 | | /// <returns>The angle between the two vectors in radians.</returns> |
| | 752 | | public static Angle<T> Angle(Vector<T> a, Vector<T> b, Func<T, Angle<T>> arccos) => |
| 3 | 753 | | Angle<SFunc<T, Angle<T>>>(a, b, arccos); |
| | 754 | |
|
| | 755 | | /// <summary>Computes the angle between two vectors.</summary> |
| | 756 | | /// <param name="b">The second vector to determine the angle between.</param> |
| | 757 | | /// <param name="arccos">A function for how to compute the inverse of a cosine ratio.</param> |
| | 758 | | /// <returns>The angle between the two vectors in radians.</returns> |
| 3 | 759 | | public Angle<T> Angle(Vector<T> b, Func<T, Angle<T>> arccos) => Angle(this, b, arccos); |
| | 760 | |
|
| | 761 | | /// <summary>Computes the angle between two vectors.</summary> |
| | 762 | | /// <typeparam name="TArcCos">A type of function for how to compute the inverse of a cosine ratio.</typeparam> |
| | 763 | | /// <param name="b">The second vector to determine the angle between.</param> |
| | 764 | | /// <param name="arccos">A function for how to compute the inverse of a cosine ratio.</param> |
| | 765 | | /// <returns>The angle between the two vectors in radians.</returns> |
| | 766 | | public Angle<T> Angle<TArcCos>(Vector<T> b, TArcCos arccos = default) |
| | 767 | | where TArcCos : struct, IFunc<T, Angle<T>> => |
| 0 | 768 | | Angle(this, b, arccos); |
| | 769 | |
|
| | 770 | | #endregion |
| | 771 | |
|
| | 772 | | #region Projection |
| | 773 | |
|
| | 774 | | /// <summary>Computes the cross product of two vectors.</summary> |
| | 775 | | /// <param name="a">The first vector of the cross product operation.</param> |
| | 776 | | /// <param name="b">The second vector of the cross product operation.</param> |
| | 777 | | /// <param name="c">The result of the cross product operation.</param> |
| | 778 | | public static void Projection(Vector<T> a, Vector<T> b, ref Vector<T>? c) |
| 4 | 779 | | { |
| 4 | 780 | | if (a is null) throw new ArgumentNullException(nameof(a)); |
| 4 | 781 | | if (b is null) throw new ArgumentNullException(nameof(b)); |
| 5 | 782 | | if (sourceof(a.Dimensions != b.Dimensions, out string c1)) throw new ArgumentException(c1); |
| 3 | 783 | | int Dimensions = a.Dimensions; |
| 3 | 784 | | if (c is null || c.Dimensions != Dimensions) |
| 3 | 785 | | { |
| 3 | 786 | | c = new Vector<T>(Dimensions); |
| 3 | 787 | | } |
| 3 | 788 | | T magSquared = a.MagnitudeSquared; |
| 3 | 789 | | if (Equate(magSquared, Constant<T>.Zero)) |
| 0 | 790 | | { |
| 0 | 791 | | throw new ArgumentOutOfRangeException(nameof(a), a, "!(" + nameof(a) + "." + nameof(a.Magnitude) + " > 0)"); |
| | 792 | | } |
| 3 | 793 | | T dot = a.DotProduct(b); |
| 3 | 794 | | T divided = Division(dot, magSquared); |
| 3 | 795 | | a.Multiply(divided, ref c); |
| 3 | 796 | | } |
| | 797 | |
|
| | 798 | | /// <summary>Computes the cross product of two vectors.</summary> |
| | 799 | | /// <param name="a">The first vector of the cross product operation.</param> |
| | 800 | | /// <param name="b">The second vector of the cross product operation.</param> |
| | 801 | | /// <returns>The result of the cross product operation.</returns> |
| | 802 | | public static Vector<T> Projection(Vector<T> a, Vector<T> b) |
| 4 | 803 | | { |
| 4 | 804 | | Vector<T>? c = null; |
| 4 | 805 | | Projection(a, b, ref c); |
| 3 | 806 | | return c!; |
| 3 | 807 | | } |
| | 808 | |
|
| | 809 | | /// <summary>Computes the cross product of two vectors.</summary> |
| | 810 | | /// <param name="b">The second vector of the cross product operation.</param> |
| | 811 | | /// <param name="c">The result of the cross product operation.</param> |
| | 812 | | public void Projection(Vector<T> b, ref Vector<T>? c) |
| 0 | 813 | | { |
| 0 | 814 | | Projection(this, b, ref c); |
| 0 | 815 | | } |
| | 816 | |
|
| | 817 | | /// <summary>Computes the cross product of two vectors.</summary> |
| | 818 | | /// <param name="b">The second vector of the dot product operation.</param> |
| | 819 | | /// <returns>The result of the dot product operation.</returns> |
| | 820 | | public Vector<T> Projection(Vector<T> b) |
| 4 | 821 | | { |
| 4 | 822 | | return Projection(this, b); |
| 3 | 823 | | } |
| | 824 | |
|
| | 825 | | #endregion |
| | 826 | |
|
| | 827 | | #region RotateBy |
| | 828 | |
|
| | 829 | | /// <summary>Rotates a vector by the specified axis and rotation values.</summary> |
| | 830 | | /// <param name="vector">The vector to rotate.</param> |
| | 831 | | /// <param name="angle">The angle of the rotation.</param> |
| | 832 | | /// <param name="x">The x component of the axis vector to rotate about.</param> |
| | 833 | | /// <param name="y">The y component of the axis vector to rotate about.</param> |
| | 834 | | /// <param name="z">The z component of the axis vector to rotate about.</param> |
| | 835 | | /// <returns>The result of the rotation.</returns> |
| | 836 | | public static Vector<T> RotateBy(Vector<T> vector, Angle<T> angle, T x, T y, T z) |
| 0 | 837 | | { |
| 0 | 838 | | throw new NotImplementedException(); |
| | 839 | | } |
| | 840 | |
|
| | 841 | | /// <summary>Rotates this vector by quaternon values.</summary> |
| | 842 | | /// <param name="angle">The amount of rotation about the axis.</param> |
| | 843 | | /// <param name="x">The x component deterniming the axis of rotation.</param> |
| | 844 | | /// <param name="y">The y component determining the axis of rotation.</param> |
| | 845 | | /// <param name="z">The z component determining the axis of rotation.</param> |
| | 846 | | /// <returns>The resulting vector after the rotation.</returns> |
| | 847 | | public Vector<T> RotateBy(Angle<T> angle, T x, T y, T z) |
| 0 | 848 | | { |
| 0 | 849 | | return RotateBy(this, angle, x, y, z); |
| 0 | 850 | | } |
| | 851 | |
|
| | 852 | | /// <summary>Rotates a vector by a quaternion.</summary> |
| | 853 | | /// <param name="a">The vector to rotate.</param> |
| | 854 | | /// <param name="b">The quaternion to rotate the 3-component vector by.</param> |
| | 855 | | /// <param name="c">The result of the rotation.</param> |
| | 856 | | public static void RotateBy(Vector<T> a, Quaternion<T> b, ref Vector<T>? c) |
| 0 | 857 | | { |
| 0 | 858 | | Quaternion<T>.Rotate(b, a, ref c); |
| 0 | 859 | | } |
| | 860 | |
|
| | 861 | | /// <summary>Rotates a vector by a quaternion.</summary> |
| | 862 | | /// <param name="a">The vector to rotate.</param> |
| | 863 | | /// <param name="b">The quaternion to rotate the 3-component vector by.</param> |
| | 864 | | /// <returns>The result of the rotation.</returns> |
| | 865 | | public static Vector<T> RotateBy(Vector<T> a, Quaternion<T> b) |
| 0 | 866 | | { |
| 0 | 867 | | Vector<T>? c = null; |
| 0 | 868 | | Quaternion<T>.Rotate(b, a, ref c); |
| 0 | 869 | | return c!; |
| 0 | 870 | | } |
| | 871 | |
|
| | 872 | | /// <summary>Rotates a vector by a quaternion.</summary> |
| | 873 | | /// <param name="b">The quaternion to rotate the 3-component vector by.</param> |
| | 874 | | /// <returns>The result of the rotation.</returns> |
| | 875 | | public Vector<T> RotateBy(Quaternion<T> b) |
| 0 | 876 | | { |
| 0 | 877 | | return RotateBy(this, b); |
| 0 | 878 | | } |
| | 879 | |
|
| | 880 | | #endregion |
| | 881 | |
|
| | 882 | | #region LinearInterpolation |
| | 883 | |
|
| | 884 | | /// <summary>Computes the linear interpolation between two vectors.</summary> |
| | 885 | | /// <param name="a">The starting vector of the interpolation.</param> |
| | 886 | | /// <param name="b">The ending vector of the interpolation.</param> |
| | 887 | | /// <param name="blend">The ratio 0.0 to 1.0 of the interpolation between the start and end.</param> |
| | 888 | | /// <param name="c">The result of the interpolation.</param> |
| | 889 | | public static void LinearInterpolation(Vector<T> a, Vector<T> b, T blend, ref Vector<T>? c) |
| 0 | 890 | | { |
| 0 | 891 | | if (LessThan(blend, Constant<T>.Zero) || GreaterThan(blend, Constant<T>.One)) |
| 0 | 892 | | { |
| 0 | 893 | | throw new ArgumentOutOfRangeException(nameof(blend), blend, "!(0 <= " + nameof(blend) + " <= 1)"); |
| | 894 | | } |
| 0 | 895 | | if (sourceof(a.Dimensions != b.Dimensions, out string c2)) throw new ArgumentException(c2); |
| 0 | 896 | | if (c is null || c.Dimensions != a.Dimensions) |
| 0 | 897 | | { |
| 0 | 898 | | c = new Vector<T>(a.Dimensions); |
| 0 | 899 | | } |
| 0 | 900 | | for (int i = 0; i < a.Dimensions; i++) |
| 0 | 901 | | { |
| 0 | 902 | | c._vector[i] = Addition(a._vector[i], Multiplication(blend, Subtraction(b._vector[i], a._vector[i]))); |
| 0 | 903 | | } |
| 0 | 904 | | } |
| | 905 | |
|
| | 906 | | /// <summary>Computes the linear interpolation between two vectors.</summary> |
| | 907 | | /// <param name="a">The starting vector of the interpolation.</param> |
| | 908 | | /// <param name="b">The ending vector of the interpolation.</param> |
| | 909 | | /// <param name="blend">The ratio 0.0 to 1.0 of the interpolation between the start and end.</param> |
| | 910 | | /// <returns>The result of the interpolation.</returns> |
| | 911 | | public static Vector<T> LinearInterpolation(Vector<T> a, Vector<T> b, T blend) |
| 0 | 912 | | { |
| 0 | 913 | | Vector<T>? c = null; |
| 0 | 914 | | LinearInterpolation(a, b, blend, ref c); |
| 0 | 915 | | return c!; |
| 0 | 916 | | } |
| | 917 | |
|
| | 918 | | /// <summary>Computes the linear interpolation between two vectors.</summary> |
| | 919 | | /// <param name="b">The ending vector of the interpolation.</param> |
| | 920 | | /// <param name="blend">The ratio 0.0 to 1.0 of the interpolation between the start and end.</param> |
| | 921 | | /// <param name="c">The result of the interpolation.</param> |
| | 922 | | public void LinearInterpolation(Vector<T> b, T blend, ref Vector<T>? c) |
| 0 | 923 | | { |
| 0 | 924 | | LinearInterpolation(this, b, blend, ref c); |
| 0 | 925 | | } |
| | 926 | |
|
| | 927 | | /// <summary>Computes the linear interpolation between two vectors.</summary> |
| | 928 | | /// <param name="b">The ending vector of the interpolation.</param> |
| | 929 | | /// <param name="blend">The ratio 0.0 to 1.0 of the interpolation between the start and end.</param> |
| | 930 | | /// <returns>The result of the interpolation.</returns> |
| | 931 | | public Vector<T> LinearInterpolation(Vector<T> b, T blend) |
| 0 | 932 | | { |
| 0 | 933 | | return LinearInterpolation(this, b, blend); |
| 0 | 934 | | } |
| | 935 | |
|
| | 936 | | #endregion |
| | 937 | |
|
| | 938 | | #region SphericalInterpolation |
| | 939 | |
|
| | 940 | | /// <summary>Spherically interpolates between two vectors.</summary> |
| | 941 | | /// <param name="a">The starting vector of the interpolation.</param> |
| | 942 | | /// <param name="b">The ending vector of the interpolation.</param> |
| | 943 | | /// <param name="blend">The ratio 0.0 to 1.0 defining the interpolation distance between the two vectors.</param> |
| | 944 | | /// <param name="c">The result of the slerp operation.</param> |
| | 945 | | public static void SphericalInterpolation(Vector<T> a, Vector<T> b, T blend, ref Vector<T>? c) |
| 0 | 946 | | { |
| 0 | 947 | | throw new NotImplementedException(); |
| | 948 | | } |
| | 949 | |
|
| | 950 | | /// <summary>Spherically interpolates between two vectors.</summary> |
| | 951 | | /// <param name="a">The starting vector of the interpolation.</param> |
| | 952 | | /// <param name="b">The ending vector of the interpolation.</param> |
| | 953 | | /// <param name="blend">The ratio 0.0 to 1.0 defining the interpolation distance between the two vectors.</param> |
| | 954 | | /// <returns>The result of the slerp operation.</returns> |
| | 955 | | public static Vector<T> SphericalInterpolation(Vector<T> a, Vector<T> b, T blend) |
| 0 | 956 | | { |
| 0 | 957 | | Vector<T>? c = null; |
| 0 | 958 | | SphericalInterpolation(a, b, blend, ref c); |
| 0 | 959 | | return c!; |
| 0 | 960 | | } |
| | 961 | |
|
| | 962 | | /// <summary>Sphereically interpolates between two vectors.</summary> |
| | 963 | | /// <param name="b">The ending vector of the interpolation.</param> |
| | 964 | | /// <param name="blend">The ratio 0.0 to 1.0 defining the interpolation distance between the two vectors.</param> |
| | 965 | | /// <returns>The result of the slerp operation.</returns> |
| 0 | 966 | | public Vector<T> SphericalInterpolation(Vector<T> b, T blend) => SphericalInterpolation(this, b, blend); |
| | 967 | |
|
| | 968 | | #endregion |
| | 969 | |
|
| | 970 | | #region BarycentricInterpolation |
| | 971 | |
|
| | 972 | | /// <summary>Interpolates between three vectors using barycentric coordinates.</summary> |
| | 973 | | /// <param name="a">The first vector of the interpolation.</param> |
| | 974 | | /// <param name="b">The second vector of the interpolation.</param> |
| | 975 | | /// <param name="c">The thrid vector of the interpolation.</param> |
| | 976 | | /// <param name="u">The "U" value of the barycentric interpolation equation.</param> |
| | 977 | | /// <param name="v">The "V" value of the barycentric interpolation equation.</param> |
| | 978 | | /// <param name="d">The result of the interpolation.</param> |
| | 979 | | public static void BarycentricInterpolation(Vector<T> a, Vector<T> b, Vector<T> c, T u, T v, ref Vector<T>? d) |
| 0 | 980 | | { |
| 0 | 981 | | if (a is null) throw new ArgumentNullException(nameof(a)); |
| 0 | 982 | | if (b is null) throw new ArgumentNullException(nameof(b)); |
| 0 | 983 | | if (c is null) throw new ArgumentNullException(nameof(c)); |
| 0 | 984 | | if (Equate(a.Dimensions, b.Dimensions, c.Dimensions)) |
| 0 | 985 | | { |
| 0 | 986 | | throw new ArgumentException("Arguments invalid !(" + |
| 0 | 987 | | nameof(a) + "." + nameof(a.Dimensions) + " == " + |
| 0 | 988 | | nameof(b) + "." + nameof(b.Dimensions) + " == " + |
| 0 | 989 | | nameof(c) + "." + nameof(c.Dimensions) + ")"); |
| | 990 | | } |
| | 991 | |
|
| | 992 | | // Note: needs optimization (call the "ref" methods) |
| 0 | 993 | | d = a + (u * (b - a)) + (v * (c - a)); |
| 0 | 994 | | } |
| | 995 | |
|
| | 996 | | /// <summary>Interpolates between three vectors using barycentric coordinates.</summary> |
| | 997 | | /// <param name="a">The first vector of the interpolation.</param> |
| | 998 | | /// <param name="b">The second vector of the interpolation.</param> |
| | 999 | | /// <param name="c">The thrid vector of the interpolation.</param> |
| | 1000 | | /// <param name="u">The "U" value of the barycentric interpolation equation.</param> |
| | 1001 | | /// <param name="v">The "V" value of the barycentric interpolation equation.</param> |
| | 1002 | | /// <returns>The resulting vector of the barycentric interpolation.</returns> |
| | 1003 | | public static Vector<T> BarycentricInterpolation(Vector<T> a, Vector<T> b, Vector<T> c, T u, T v) |
| 0 | 1004 | | { |
| 0 | 1005 | | Vector<T>? d = null; |
| 0 | 1006 | | BarycentricInterpolation(a._vector, b._vector, c._vector, u, v, ref d); |
| 0 | 1007 | | return d!; |
| 0 | 1008 | | } |
| | 1009 | |
|
| | 1010 | | /// <summary>Interpolates between three vectors using barycentric coordinates.</summary> |
| | 1011 | | /// <param name="b">The second vector of the interpolation.</param> |
| | 1012 | | /// <param name="c">The thrid vector of the interpolation.</param> |
| | 1013 | | /// <param name="u">The "U" value of the barycentric interpolation equation.</param> |
| | 1014 | | /// <param name="v">The "V" value of the barycentric interpolation equation.</param> |
| | 1015 | | /// <returns>The resulting vector of the barycentric interpolation.</returns> |
| | 1016 | | public Vector<T> BarycentricInterpolation(Vector<T> b, Vector<T> c, T u, T v) |
| 0 | 1017 | | { |
| 0 | 1018 | | return BarycentricInterpolation(this, b._vector, c._vector, u, v); |
| 0 | 1019 | | } |
| | 1020 | |
|
| | 1021 | | #endregion |
| | 1022 | |
|
| | 1023 | | #region Equal |
| | 1024 | |
|
| | 1025 | | /// <summary>Does a value equality check.</summary> |
| | 1026 | | /// <param name="a">The first vector to check for equality.</param> |
| | 1027 | | /// <param name="b">The second vector to check for equality.</param> |
| | 1028 | | /// <returns>True if values are equal, false if not.</returns> |
| | 1029 | | public static bool Equal(Vector<T> a, Vector<T> b) |
| 54 | 1030 | | { |
| 54 | 1031 | | if (a is null) |
| 0 | 1032 | | { |
| 0 | 1033 | | if (b is null) |
| 0 | 1034 | | { |
| 0 | 1035 | | return true; |
| | 1036 | | } |
| | 1037 | | else |
| 0 | 1038 | | { |
| 0 | 1039 | | return false; |
| | 1040 | | } |
| | 1041 | | } |
| 54 | 1042 | | if (b is null) |
| 0 | 1043 | | { |
| 0 | 1044 | | return false; |
| | 1045 | | } |
| | 1046 | | else |
| 54 | 1047 | | { |
| 54 | 1048 | | int Length = a.Dimensions; |
| 54 | 1049 | | if (Length != b.Dimensions) |
| 0 | 1050 | | { |
| 0 | 1051 | | return false; |
| | 1052 | | } |
| 54 | 1053 | | T[] A = a._vector; |
| 54 | 1054 | | T[] B = b._vector; |
| 438 | 1055 | | for (int i = 0; i < Length; i++) |
| 165 | 1056 | | { |
| 165 | 1057 | | if (Statics.Inequate(A[i], B[i])) |
| 0 | 1058 | | { |
| 0 | 1059 | | return false; |
| | 1060 | | } |
| 165 | 1061 | | } |
| 54 | 1062 | | return true; |
| | 1063 | | } |
| 54 | 1064 | | } |
| | 1065 | |
|
| | 1066 | | /// <summary>Does a value non-equality check.</summary> |
| | 1067 | | /// <param name="a">The first vector to check for non-equality.</param> |
| | 1068 | | /// <param name="b">The second vector to check for non-equality.</param> |
| | 1069 | | /// <returns>True if values are not equal, false if not.</returns> |
| | 1070 | | public static bool NotEqual(Vector<T> a, Vector<T> b) |
| 0 | 1071 | | { |
| 0 | 1072 | | return !Equal(a, b); |
| 0 | 1073 | | } |
| | 1074 | |
|
| | 1075 | | /// <summary>Does an equality check by value. (warning for float errors)</summary> |
| | 1076 | | /// <param name="a">The first vector of the equality check.</param> |
| | 1077 | | /// <param name="b">The second vector of the equality check.</param> |
| | 1078 | | /// <returns>true if the values are equal, false if not.</returns> |
| | 1079 | | public static bool operator ==(Vector<T> a, Vector<T> b) |
| 54 | 1080 | | { |
| 54 | 1081 | | return Equal(a, b); |
| 54 | 1082 | | } |
| | 1083 | |
|
| | 1084 | | /// <summary>Does an anti-equality check by value. (warning for float errors)</summary> |
| | 1085 | | /// <param name="a">The first vector of the anit-equality check.</param> |
| | 1086 | | /// <param name="b">The second vector of the anti-equality check.</param> |
| | 1087 | | /// <returns>true if the values are not equal, false if they are.</returns> |
| | 1088 | | public static bool operator !=(Vector<T> a, Vector<T> b) |
| 0 | 1089 | | { |
| 0 | 1090 | | return !Equal(a, b); |
| 0 | 1091 | | } |
| | 1092 | |
|
| | 1093 | | /// <summary>Check for equality by value.</summary> |
| | 1094 | | /// <param name="b">The other vector of the equality check.</param> |
| | 1095 | | /// <returns>true if the values were equal, false if not.</returns> |
| | 1096 | | public bool Equal(Vector<T> b) |
| 0 | 1097 | | { |
| 0 | 1098 | | return this == b; |
| 0 | 1099 | | } |
| | 1100 | |
|
| | 1101 | | /// <summary>Check for non-equality by value.</summary> |
| | 1102 | | /// <param name="b">The other vector of the non-equality check.</param> |
| | 1103 | | /// <returns>true if the values were not equal, false if not.</returns> |
| | 1104 | | public bool NotEqual(Vector<T> b) |
| 0 | 1105 | | { |
| 0 | 1106 | | return this != b; |
| 0 | 1107 | | } |
| | 1108 | |
|
| | 1109 | | #endregion |
| | 1110 | |
|
| | 1111 | | #region Equal (+leniency) |
| | 1112 | |
|
| | 1113 | | /// <summary>Does a value equality check with leniency.</summary> |
| | 1114 | | /// <param name="a">The first vector to check for equality.</param> |
| | 1115 | | /// <param name="b">The second vector to check for equality.</param> |
| | 1116 | | /// <param name="leniency">How much the values can vary but still be considered equal.</param> |
| | 1117 | | /// <returns>True if values are equal, false if not.</returns> |
| | 1118 | | public static bool Equal(Vector<T> a, Vector<T> b, T leniency) |
| 8 | 1119 | | { |
| 8 | 1120 | | if (a is null) |
| 0 | 1121 | | { |
| 0 | 1122 | | if (b is null) |
| 0 | 1123 | | { |
| 0 | 1124 | | return true; |
| | 1125 | | } |
| | 1126 | | else |
| 0 | 1127 | | { |
| 0 | 1128 | | return false; |
| | 1129 | | } |
| | 1130 | | } |
| 8 | 1131 | | if (b is null) |
| 0 | 1132 | | { |
| 0 | 1133 | | return false; |
| | 1134 | | } |
| 8 | 1135 | | int Length = a.Dimensions; |
| 8 | 1136 | | if (Length != b.Dimensions) |
| 0 | 1137 | | { |
| 0 | 1138 | | return false; |
| | 1139 | | } |
| 8 | 1140 | | T[] A = a._vector; |
| 8 | 1141 | | T[] B = b._vector; |
| 40 | 1142 | | for (int i = 0; i < Length; i++) |
| 16 | 1143 | | { |
| 16 | 1144 | | if (!Statics.EqualToLeniency(A[i], B[i], leniency)) |
| 4 | 1145 | | { |
| 4 | 1146 | | return false; |
| | 1147 | | } |
| 12 | 1148 | | } |
| 4 | 1149 | | return true; |
| 8 | 1150 | | } |
| | 1151 | |
|
| | 1152 | | /// <summary>Checks for equality by value with some leniency.</summary> |
| | 1153 | | /// <param name="right">The other vector of the equality check.</param> |
| | 1154 | | /// <param name="leniency">The ammount the values can differ but still be considered equal.</param> |
| | 1155 | | /// <returns>true if the values were cinsidered equal, false if not.</returns> |
| | 1156 | | public bool Equal(Vector<T> right, T leniency) |
| 8 | 1157 | | { |
| 8 | 1158 | | return Equal(this, right, leniency); |
| 8 | 1159 | | } |
| | 1160 | |
|
| | 1161 | | #endregion |
| | 1162 | |
|
| | 1163 | | #endregion |
| | 1164 | |
|
| | 1165 | | #region Other Methods |
| | 1166 | |
|
| | 1167 | | #region Clone |
| | 1168 | |
|
| | 1169 | | /// <summary>Creates a copy of a vector.</summary> |
| | 1170 | | /// <param name="a">The vector to copy.</param> |
| | 1171 | | /// <returns>The copy of this vector.</returns> |
| | 1172 | | public static Vector<T> Clone(Vector<T> a) |
| 0 | 1173 | | { |
| 0 | 1174 | | if (a is null) throw new ArgumentNullException(nameof(a)); |
| 0 | 1175 | | return new Vector<T>(a); |
| 0 | 1176 | | } |
| | 1177 | |
|
| | 1178 | | /// <summary>Copies this vector.</summary> |
| | 1179 | | /// <returns>The copy of this vector.</returns> |
| | 1180 | | public Vector<T> Clone() |
| 0 | 1181 | | { |
| 0 | 1182 | | return Clone(this); |
| 0 | 1183 | | } |
| | 1184 | |
|
| | 1185 | | #endregion |
| | 1186 | |
|
| | 1187 | | #endregion |
| | 1188 | |
|
| | 1189 | | #region Casting Operators |
| | 1190 | |
|
| | 1191 | | /// <summary>Implicit conversions from Vector to T[].</summary> |
| | 1192 | | /// <param name="vector">The Vector to be converted to a T[].</param> |
| | 1193 | | /// <returns>The T[] of the vector.</returns> |
| | 1194 | | public static implicit operator T[](Vector<T> vector) |
| 0 | 1195 | | { |
| 0 | 1196 | | return vector._vector; |
| 0 | 1197 | | } |
| | 1198 | |
|
| | 1199 | | /// <summary>Implicit conversions from Vector to T[].</summary> |
| | 1200 | | /// <param name="array">The Vector to be converted to a T[].</param> |
| | 1201 | | /// <returns>The T[] of the vector.</returns> |
| | 1202 | | public static implicit operator Vector<T>(T[] array) |
| 0 | 1203 | | { |
| 0 | 1204 | | return new Vector<T>(array); |
| 0 | 1205 | | } |
| | 1206 | |
|
| | 1207 | | /// <summary>Converts a vector into a matrix.</summary> |
| | 1208 | | /// <param name="vector">The vector to convert.</param> |
| | 1209 | | /// <returns>The resulting matrix.</returns> |
| | 1210 | | public static explicit operator Matrix<T>(Vector<T> vector) |
| 0 | 1211 | | { |
| 0 | 1212 | | return new Matrix<T>(vector); |
| 0 | 1213 | | } |
| | 1214 | |
|
| | 1215 | | /// <summary>Implicitly converts a scalar into a one dimensional vector.</summary> |
| | 1216 | | /// <param name="scalar">The scalar value.</param> |
| | 1217 | | /// <returns>The one dimensional vector </returns> |
| | 1218 | | public static explicit operator Vector<T>(T scalar) |
| 0 | 1219 | | { |
| 0 | 1220 | | return new Vector<T>(scalar); |
| 0 | 1221 | | } |
| | 1222 | |
|
| | 1223 | | #endregion |
| | 1224 | |
|
| | 1225 | | #region Overrides |
| | 1226 | |
|
| | 1227 | | /// <summary>Computes a hash code from the values of this matrix.</summary> |
| | 1228 | | /// <returns>A hash code for the matrix.</returns> |
| | 1229 | | public override int GetHashCode() |
| 0 | 1230 | | { |
| 0 | 1231 | | int hashCode = default; |
| 0 | 1232 | | for (int i = 1; i < _vector.Length; i++) |
| 0 | 1233 | | { |
| 0 | 1234 | | hashCode = HashCode.Combine(hashCode, Hash(_vector[i])); |
| 0 | 1235 | | } |
| 0 | 1236 | | return hashCode; |
| 0 | 1237 | | } |
| | 1238 | |
|
| | 1239 | | /// <summary>Does an equality check by reference.</summary> |
| | 1240 | | /// <param name="right">The object to compare to.</param> |
| | 1241 | | /// <returns>True if the references are equal, false if not.</returns> |
| 0 | 1242 | | public override bool Equals(object? right) => right is Vector<T> vector && Equal(this, vector); |
| | 1243 | |
|
| | 1244 | | #endregion |
| | 1245 | | } |