/
Vector3.cs
1218 lines (1131 loc) · 49.8 KB
/
Vector3.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.InteropServices;
#nullable enable
namespace Godot
{
/// <summary>
/// 3-element structure that can be used to represent positions in 3D space or any other pair of numeric values.
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Vector3 : IEquatable<Vector3>
{
/// <summary>
/// Enumerated index values for the axes.
/// Returned by <see cref="MaxAxisIndex"/> and <see cref="MinAxisIndex"/>.
/// </summary>
public enum Axis
{
/// <summary>
/// The vector's X axis.
/// </summary>
X = 0,
/// <summary>
/// The vector's Y axis.
/// </summary>
Y,
/// <summary>
/// The vector's Z axis.
/// </summary>
Z
}
/// <summary>
/// The vector's X component. Also accessible by using the index position <c>[0]</c>.
/// </summary>
public real_t X;
/// <summary>
/// The vector's Y component. Also accessible by using the index position <c>[1]</c>.
/// </summary>
public real_t Y;
/// <summary>
/// The vector's Z component. Also accessible by using the index position <c>[2]</c>.
/// </summary>
public real_t Z;
/// <summary>
/// Access vector components using their index.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="index"/> is not 0, 1 or 2.
/// </exception>
/// <value>
/// <c>[0]</c> is equivalent to <see cref="X"/>,
/// <c>[1]</c> is equivalent to <see cref="Y"/>,
/// <c>[2]</c> is equivalent to <see cref="Z"/>.
/// </value>
public real_t this[int index]
{
readonly get
{
switch (index)
{
case 0:
return X;
case 1:
return Y;
case 2:
return Z;
default:
throw new ArgumentOutOfRangeException(nameof(index));
}
}
set
{
switch (index)
{
case 0:
X = value;
return;
case 1:
Y = value;
return;
case 2:
Z = value;
return;
default:
throw new ArgumentOutOfRangeException(nameof(index));
}
}
}
/// <summary>
/// Helper method for deconstruction into a tuple.
/// </summary>
public readonly void Deconstruct(out real_t x, out real_t y, out real_t z)
{
x = X;
y = Y;
z = Z;
}
internal void Normalize()
{
real_t lengthsq = LengthSquared();
if (lengthsq == 0)
{
X = Y = Z = 0f;
}
else
{
real_t length = Mathf.Sqrt(lengthsq);
X /= length;
Y /= length;
Z /= length;
}
}
/// <summary>
/// Returns a new vector with all components in absolute values (i.e. positive).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Abs(real_t)"/> called on each component.</returns>
public readonly Vector3 Abs()
{
return new Vector3(Mathf.Abs(X), Mathf.Abs(Y), Mathf.Abs(Z));
}
/// <summary>
/// Returns the unsigned minimum angle to the given vector, in radians.
/// </summary>
/// <param name="to">The other vector to compare this vector to.</param>
/// <returns>The unsigned angle between the two vectors, in radians.</returns>
public readonly real_t AngleTo(Vector3 to)
{
return Mathf.Atan2(Cross(to).Length(), Dot(to));
}
/// <summary>
/// Returns this vector "bounced off" from a plane defined by the given normal.
/// </summary>
/// <param name="normal">The normal vector defining the plane to bounce off. Must be normalized.</param>
/// <returns>The bounced vector.</returns>
public readonly Vector3 Bounce(Vector3 normal)
{
return -Reflect(normal);
}
/// <summary>
/// Returns a new vector with all components rounded up (towards positive infinity).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Ceil(real_t)"/> called on each component.</returns>
public readonly Vector3 Ceil()
{
return new Vector3(Mathf.Ceil(X), Mathf.Ceil(Y), Mathf.Ceil(Z));
}
/// <summary>
/// Returns a new vector with all components clamped between the
/// components of <paramref name="min"/> and <paramref name="max"/> using
/// <see cref="Mathf.Clamp(real_t, real_t, real_t)"/>.
/// </summary>
/// <param name="min">The vector with minimum allowed values.</param>
/// <param name="max">The vector with maximum allowed values.</param>
/// <returns>The vector with all components clamped.</returns>
public readonly Vector3 Clamp(Vector3 min, Vector3 max)
{
return new Vector3
(
Mathf.Clamp(X, min.X, max.X),
Mathf.Clamp(Y, min.Y, max.Y),
Mathf.Clamp(Z, min.Z, max.Z)
);
}
/// <summary>
/// Returns a new vector with all components clamped between the
/// <paramref name="min"/> and <paramref name="max"/> using
/// <see cref="Mathf.Clamp(real_t, real_t, real_t)"/>.
/// </summary>
/// <param name="min">The minimum allowed value.</param>
/// <param name="max">The maximum allowed value.</param>
/// <returns>The vector with all components clamped.</returns>
public readonly Vector3 Clamp(real_t min, real_t max)
{
return new Vector3
(
Mathf.Clamp(X, min, max),
Mathf.Clamp(Y, min, max),
Mathf.Clamp(Z, min, max)
);
}
/// <summary>
/// Returns the cross product of this vector and <paramref name="with"/>.
/// </summary>
/// <param name="with">The other vector.</param>
/// <returns>The cross product vector.</returns>
public readonly Vector3 Cross(Vector3 with)
{
return new Vector3
(
(Y * with.Z) - (Z * with.Y),
(Z * with.X) - (X * with.Z),
(X * with.Y) - (Y * with.X)
);
}
/// <summary>
/// Performs a cubic interpolation between vectors <paramref name="preA"/>, this vector,
/// <paramref name="b"/>, and <paramref name="postB"/>, by the given amount <paramref name="weight"/>.
/// </summary>
/// <param name="b">The destination vector.</param>
/// <param name="preA">A vector before this vector.</param>
/// <param name="postB">A vector after <paramref name="b"/>.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated vector.</returns>
public readonly Vector3 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, real_t weight)
{
return new Vector3
(
Mathf.CubicInterpolate(X, b.X, preA.X, postB.X, weight),
Mathf.CubicInterpolate(Y, b.Y, preA.Y, postB.Y, weight),
Mathf.CubicInterpolate(Z, b.Z, preA.Z, postB.Z, weight)
);
}
/// <summary>
/// Performs a cubic interpolation between vectors <paramref name="preA"/>, this vector,
/// <paramref name="b"/>, and <paramref name="postB"/>, by the given amount <paramref name="weight"/>.
/// It can perform smoother interpolation than <see cref="CubicInterpolate"/>
/// by the time values.
/// </summary>
/// <param name="b">The destination vector.</param>
/// <param name="preA">A vector before this vector.</param>
/// <param name="postB">A vector after <paramref name="b"/>.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <param name="t"></param>
/// <param name="preAT"></param>
/// <param name="postBT"></param>
/// <returns>The interpolated vector.</returns>
public readonly Vector3 CubicInterpolateInTime(Vector3 b, Vector3 preA, Vector3 postB, real_t weight, real_t t, real_t preAT, real_t postBT)
{
return new Vector3
(
Mathf.CubicInterpolateInTime(X, b.X, preA.X, postB.X, weight, t, preAT, postBT),
Mathf.CubicInterpolateInTime(Y, b.Y, preA.Y, postB.Y, weight, t, preAT, postBT),
Mathf.CubicInterpolateInTime(Z, b.Z, preA.Z, postB.Z, weight, t, preAT, postBT)
);
}
/// <summary>
/// Returns the point at the given <paramref name="t"/> on a one-dimensional Bezier curve defined by this vector
/// and the given <paramref name="control1"/>, <paramref name="control2"/>, and <paramref name="end"/> points.
/// </summary>
/// <param name="control1">Control point that defines the bezier curve.</param>
/// <param name="control2">Control point that defines the bezier curve.</param>
/// <param name="end">The destination vector.</param>
/// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated vector.</returns>
public readonly Vector3 BezierInterpolate(Vector3 control1, Vector3 control2, Vector3 end, real_t t)
{
return new Vector3
(
Mathf.BezierInterpolate(X, control1.X, control2.X, end.X, t),
Mathf.BezierInterpolate(Y, control1.Y, control2.Y, end.Y, t),
Mathf.BezierInterpolate(Z, control1.Z, control2.Z, end.Z, t)
);
}
/// <summary>
/// Returns the derivative at the given <paramref name="t"/> on the Bezier curve defined by this vector
/// and the given <paramref name="control1"/>, <paramref name="control2"/>, and <paramref name="end"/> points.
/// </summary>
/// <param name="control1">Control point that defines the bezier curve.</param>
/// <param name="control2">Control point that defines the bezier curve.</param>
/// <param name="end">The destination value for the interpolation.</param>
/// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting value of the interpolation.</returns>
public readonly Vector3 BezierDerivative(Vector3 control1, Vector3 control2, Vector3 end, real_t t)
{
return new Vector3(
Mathf.BezierDerivative(X, control1.X, control2.X, end.X, t),
Mathf.BezierDerivative(Y, control1.Y, control2.Y, end.Y, t),
Mathf.BezierDerivative(Z, control1.Z, control2.Z, end.Z, t)
);
}
/// <summary>
/// Returns the normalized vector pointing from this vector to <paramref name="to"/>.
/// </summary>
/// <param name="to">The other vector to point towards.</param>
/// <returns>The direction from this vector to <paramref name="to"/>.</returns>
public readonly Vector3 DirectionTo(Vector3 to)
{
return new Vector3(to.X - X, to.Y - Y, to.Z - Z).Normalized();
}
/// <summary>
/// Returns the squared distance between this vector and <paramref name="to"/>.
/// This method runs faster than <see cref="DistanceTo"/>, so prefer it if
/// you need to compare vectors or need the squared distance for some formula.
/// </summary>
/// <param name="to">The other vector to use.</param>
/// <returns>The squared distance between the two vectors.</returns>
public readonly real_t DistanceSquaredTo(Vector3 to)
{
return (to - this).LengthSquared();
}
/// <summary>
/// Returns the distance between this vector and <paramref name="to"/>.
/// </summary>
/// <seealso cref="DistanceSquaredTo(Vector3)"/>
/// <param name="to">The other vector to use.</param>
/// <returns>The distance between the two vectors.</returns>
public readonly real_t DistanceTo(Vector3 to)
{
return (to - this).Length();
}
/// <summary>
/// Returns the dot product of this vector and <paramref name="with"/>.
/// </summary>
/// <param name="with">The other vector to use.</param>
/// <returns>The dot product of the two vectors.</returns>
public readonly real_t Dot(Vector3 with)
{
return (X * with.X) + (Y * with.Y) + (Z * with.Z);
}
/// <summary>
/// Returns a new vector with all components rounded down (towards negative infinity).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Floor(real_t)"/> called on each component.</returns>
public readonly Vector3 Floor()
{
return new Vector3(Mathf.Floor(X), Mathf.Floor(Y), Mathf.Floor(Z));
}
/// <summary>
/// Returns the inverse of this vector. This is the same as <c>new Vector3(1 / v.X, 1 / v.Y, 1 / v.Z)</c>.
/// </summary>
/// <returns>The inverse of this vector.</returns>
public readonly Vector3 Inverse()
{
return new Vector3(1 / X, 1 / Y, 1 / Z);
}
/// <summary>
/// Returns <see langword="true"/> if this vector is finite, by calling
/// <see cref="Mathf.IsFinite(real_t)"/> on each component.
/// </summary>
/// <returns>Whether this vector is finite or not.</returns>
public readonly bool IsFinite()
{
return Mathf.IsFinite(X) && Mathf.IsFinite(Y) && Mathf.IsFinite(Z);
}
/// <summary>
/// Returns <see langword="true"/> if the vector is normalized, and <see langword="false"/> otherwise.
/// </summary>
/// <returns>A <see langword="bool"/> indicating whether or not the vector is normalized.</returns>
public readonly bool IsNormalized()
{
return Mathf.Abs(LengthSquared() - 1.0f) < Mathf.Epsilon;
}
/// <summary>
/// Returns the length (magnitude) of this vector.
/// </summary>
/// <seealso cref="LengthSquared"/>
/// <returns>The length of this vector.</returns>
public readonly real_t Length()
{
real_t x2 = X * X;
real_t y2 = Y * Y;
real_t z2 = Z * Z;
return Mathf.Sqrt(x2 + y2 + z2);
}
/// <summary>
/// Returns the squared length (squared magnitude) of this vector.
/// This method runs faster than <see cref="Length"/>, so prefer it if
/// you need to compare vectors or need the squared length for some formula.
/// </summary>
/// <returns>The squared length of this vector.</returns>
public readonly real_t LengthSquared()
{
real_t x2 = X * X;
real_t y2 = Y * Y;
real_t z2 = Z * Z;
return x2 + y2 + z2;
}
/// <summary>
/// Returns the result of the linear interpolation between
/// this vector and <paramref name="to"/> by amount <paramref name="weight"/>.
/// </summary>
/// <param name="to">The destination vector for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting vector of the interpolation.</returns>
public readonly Vector3 Lerp(Vector3 to, real_t weight)
{
return new Vector3
(
Mathf.Lerp(X, to.X, weight),
Mathf.Lerp(Y, to.Y, weight),
Mathf.Lerp(Z, to.Z, weight)
);
}
/// <summary>
/// Returns the vector with a maximum length by limiting its length to <paramref name="length"/>.
/// </summary>
/// <param name="length">The length to limit to.</param>
/// <returns>The vector with its length limited.</returns>
public readonly Vector3 LimitLength(real_t length = 1.0f)
{
Vector3 v = this;
real_t l = Length();
if (l > 0 && length < l)
{
v /= l;
v *= length;
}
return v;
}
/// <summary>
/// Returns the result of the component-wise maximum between
/// this vector and <paramref name="with"/>.
/// Equivalent to <c>new Vector3(Mathf.Max(X, with.X), Mathf.Max(Y, with.Y), Mathf.Max(Z, with.Z))</c>.
/// </summary>
/// <param name="with">The other vector to use.</param>
/// <returns>The resulting maximum vector.</returns>
public readonly Vector3 Max(Vector3 with)
{
return new Vector3
(
Mathf.Max(X, with.X),
Mathf.Max(Y, with.Y),
Mathf.Max(Z, with.Z)
);
}
/// <summary>
/// Returns the result of the component-wise maximum between
/// this vector and <paramref name="with"/>.
/// Equivalent to <c>new Vector3(Mathf.Max(X, with), Mathf.Max(Y, with), Mathf.Max(Z, with))</c>.
/// </summary>
/// <param name="with">The other value to use.</param>
/// <returns>The resulting maximum vector.</returns>
public readonly Vector3 Max(real_t with)
{
return new Vector3
(
Mathf.Max(X, with),
Mathf.Max(Y, with),
Mathf.Max(Z, with)
);
}
/// <summary>
/// Returns the result of the component-wise minimum between
/// this vector and <paramref name="with"/>.
/// Equivalent to <c>new Vector3(Mathf.Min(X, with.X), Mathf.Min(Y, with.Y), Mathf.Min(Z, with.Z))</c>.
/// </summary>
/// <param name="with">The other vector to use.</param>
/// <returns>The resulting minimum vector.</returns>
public readonly Vector3 Min(Vector3 with)
{
return new Vector3
(
Mathf.Min(X, with.X),
Mathf.Min(Y, with.Y),
Mathf.Min(Z, with.Z)
);
}
/// <summary>
/// Returns the axis of the vector's highest value. See <see cref="Axis"/>.
/// If all components are equal, this method returns <see cref="Axis.X"/>.
/// </summary>
/// <returns>The index of the highest axis.</returns>
public readonly Axis MaxAxisIndex()
{
return X < Y ? (Y < Z ? Axis.Z : Axis.Y) : (X < Z ? Axis.Z : Axis.X);
}
/// <summary>
/// Returns the axis of the vector's lowest value. See <see cref="Axis"/>.
/// If all components are equal, this method returns <see cref="Axis.Z"/>.
/// </summary>
/// <returns>The index of the lowest axis.</returns>
public readonly Axis MinAxisIndex()
{
return X < Y ? (X < Z ? Axis.X : Axis.Z) : (Y < Z ? Axis.Y : Axis.Z);
}
/// <summary>
/// Moves this vector toward <paramref name="to"/> by the fixed <paramref name="delta"/> amount.
/// </summary>
/// <param name="to">The vector to move towards.</param>
/// <param name="delta">The amount to move towards by.</param>
/// <returns>The resulting vector.</returns>
public readonly Vector3 MoveToward(Vector3 to, real_t delta)
{
Vector3 v = this;
Vector3 vd = to - v;
real_t len = vd.Length();
if (len <= delta || len < Mathf.Epsilon)
return to;
return v + (vd / len * delta);
}
/// <summary>
/// Returns the vector scaled to unit length. Equivalent to <c>v / v.Length()</c>.
/// </summary>
/// <returns>A normalized version of the vector.</returns>
public readonly Vector3 Normalized()
{
Vector3 v = this;
v.Normalize();
return v;
}
/// <summary>
/// Returns the outer product with <paramref name="with"/>.
/// </summary>
/// <param name="with">The other vector.</param>
/// <returns>A <see cref="Basis"/> representing the outer product matrix.</returns>
public readonly Basis Outer(Vector3 with)
{
return new Basis(
X * with.X, X * with.Y, X * with.Z,
Y * with.X, Y * with.Y, Y * with.Z,
Z * with.X, Z * with.Y, Z * with.Z
);
}
/// <summary>
/// Returns a vector composed of the <see cref="Mathf.PosMod(real_t, real_t)"/> of this vector's components
/// and <paramref name="mod"/>.
/// </summary>
/// <param name="mod">A value representing the divisor of the operation.</param>
/// <returns>
/// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="mod"/>.
/// </returns>
public readonly Vector3 PosMod(real_t mod)
{
Vector3 v;
v.X = Mathf.PosMod(X, mod);
v.Y = Mathf.PosMod(Y, mod);
v.Z = Mathf.PosMod(Z, mod);
return v;
}
/// <summary>
/// Returns a vector composed of the <see cref="Mathf.PosMod(real_t, real_t)"/> of this vector's components
/// and <paramref name="modv"/>'s components.
/// </summary>
/// <param name="modv">A vector representing the divisors of the operation.</param>
/// <returns>
/// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="modv"/>'s components.
/// </returns>
public readonly Vector3 PosMod(Vector3 modv)
{
Vector3 v;
v.X = Mathf.PosMod(X, modv.X);
v.Y = Mathf.PosMod(Y, modv.Y);
v.Z = Mathf.PosMod(Z, modv.Z);
return v;
}
/// <summary>
/// Returns a new vector resulting from projecting this vector onto the given vector <paramref name="onNormal"/>.
/// The resulting new vector is parallel to <paramref name="onNormal"/>.
/// See also <see cref="Slide(Vector3)"/>.
/// Note: If the vector <paramref name="onNormal"/> is a zero vector, the components of the resulting new vector will be <see cref="real_t.NaN"/>.
/// </summary>
/// <param name="onNormal">The vector to project onto.</param>
/// <returns>The projected vector.</returns>
public readonly Vector3 Project(Vector3 onNormal)
{
return onNormal * (Dot(onNormal) / onNormal.LengthSquared());
}
/// <summary>
/// Returns this vector reflected from a plane defined by the given <paramref name="normal"/>.
/// </summary>
/// <param name="normal">The normal vector defining the plane to reflect from. Must be normalized.</param>
/// <returns>The reflected vector.</returns>
public readonly Vector3 Reflect(Vector3 normal)
{
#if DEBUG
if (!normal.IsNormalized())
{
throw new ArgumentException("Argument is not normalized.", nameof(normal));
}
#endif
return (2.0f * Dot(normal) * normal) - this;
}
/// <summary>
/// Rotates this vector around a given <paramref name="axis"/> vector by <paramref name="angle"/> (in radians).
/// The <paramref name="axis"/> vector must be a normalized vector.
/// </summary>
/// <param name="axis">The vector to rotate around. Must be normalized.</param>
/// <param name="angle">The angle to rotate by, in radians.</param>
/// <returns>The rotated vector.</returns>
public readonly Vector3 Rotated(Vector3 axis, real_t angle)
{
#if DEBUG
if (!axis.IsNormalized())
{
throw new ArgumentException("Argument is not normalized.", nameof(axis));
}
#endif
return new Basis(axis, angle) * this;
}
/// <summary>
/// Returns this vector with all components rounded to the nearest integer,
/// with halfway cases rounded towards the nearest multiple of two.
/// </summary>
/// <returns>The rounded vector.</returns>
public readonly Vector3 Round()
{
return new Vector3(Mathf.Round(X), Mathf.Round(Y), Mathf.Round(Z));
}
/// <summary>
/// Returns a vector with each component set to one or negative one, depending
/// on the signs of this vector's components, or zero if the component is zero,
/// by calling <see cref="Mathf.Sign(real_t)"/> on each component.
/// </summary>
/// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns>
public readonly Vector3 Sign()
{
Vector3 v;
v.X = Mathf.Sign(X);
v.Y = Mathf.Sign(Y);
v.Z = Mathf.Sign(Z);
return v;
}
/// <summary>
/// Returns the signed angle to the given vector, in radians.
/// The sign of the angle is positive in a counter-clockwise
/// direction and negative in a clockwise direction when viewed
/// from the side specified by the <paramref name="axis"/>.
/// </summary>
/// <param name="to">The other vector to compare this vector to.</param>
/// <param name="axis">The reference axis to use for the angle sign.</param>
/// <returns>The signed angle between the two vectors, in radians.</returns>
public readonly real_t SignedAngleTo(Vector3 to, Vector3 axis)
{
Vector3 crossTo = Cross(to);
real_t unsignedAngle = Mathf.Atan2(crossTo.Length(), Dot(to));
real_t sign = crossTo.Dot(axis);
return (sign < 0) ? -unsignedAngle : unsignedAngle;
}
/// <summary>
/// Returns the result of the spherical linear interpolation between
/// this vector and <paramref name="to"/> by amount <paramref name="weight"/>.
///
/// This method also handles interpolating the lengths if the input vectors
/// have different lengths. For the special case of one or both input vectors
/// having zero length, this method behaves like <see cref="Lerp(Vector3, real_t)"/>.
/// </summary>
/// <param name="to">The destination vector for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting vector of the interpolation.</returns>
public readonly Vector3 Slerp(Vector3 to, real_t weight)
{
real_t startLengthSquared = LengthSquared();
real_t endLengthSquared = to.LengthSquared();
if (startLengthSquared == 0.0 || endLengthSquared == 0.0)
{
// Zero length vectors have no angle, so the best we can do is either lerp or throw an error.
return Lerp(to, weight);
}
real_t startLength = Mathf.Sqrt(startLengthSquared);
real_t resultLength = Mathf.Lerp(startLength, Mathf.Sqrt(endLengthSquared), weight);
real_t angle = AngleTo(to);
return Rotated(Cross(to).Normalized(), angle * weight) * (resultLength / startLength);
}
/// <summary>
/// Returns a new vector resulting from sliding this vector along a plane with normal <paramref name="normal"/>.
/// The resulting new vector is perpendicular to <paramref name="normal"/>, and is equivalent to this vector minus its projection on <paramref name="normal"/>.
/// See also <see cref="Project(Vector3)"/>.
/// Note: The vector <paramref name="normal"/> must be normalized. See also <see cref="Normalized()"/>.
/// </summary>
/// <param name="normal">The normal vector of the plane to slide on.</param>
/// <returns>The slid vector.</returns>
public readonly Vector3 Slide(Vector3 normal)
{
return this - (normal * Dot(normal));
}
/// <summary>
/// Returns a new vector with each component snapped to the nearest multiple of the corresponding component in <paramref name="step"/>.
/// This can also be used to round to an arbitrary number of decimals.
/// </summary>
/// <param name="step">A vector value representing the step size to snap to.</param>
/// <returns>The snapped vector.</returns>
public readonly Vector3 Snapped(Vector3 step)
{
return new Vector3
(
Mathf.Snapped(X, step.X),
Mathf.Snapped(Y, step.Y),
Mathf.Snapped(Z, step.Z)
);
}
/// <summary>
/// Returns a new vector with each component snapped to the nearest multiple of <paramref name="step"/>.
/// This can also be used to round to an arbitrary number of decimals.
/// </summary>
/// <param name="step">The step size to snap to.</param>
/// <returns>The snapped vector.</returns>
public readonly Vector3 Snapped(real_t step)
{
return new Vector3
(
Mathf.Snapped(X, step),
Mathf.Snapped(Y, step),
Mathf.Snapped(Z, step)
);
}
// Constants
private static readonly Vector3 _zero = new Vector3(0, 0, 0);
private static readonly Vector3 _one = new Vector3(1, 1, 1);
private static readonly Vector3 _inf = new Vector3(Mathf.Inf, Mathf.Inf, Mathf.Inf);
private static readonly Vector3 _up = new Vector3(0, 1, 0);
private static readonly Vector3 _down = new Vector3(0, -1, 0);
private static readonly Vector3 _right = new Vector3(1, 0, 0);
private static readonly Vector3 _left = new Vector3(-1, 0, 0);
private static readonly Vector3 _forward = new Vector3(0, 0, -1);
private static readonly Vector3 _back = new Vector3(0, 0, 1);
private static readonly Vector3 _modelLeft = new Vector3(1, 0, 0);
private static readonly Vector3 _modelRight = new Vector3(-1, 0, 0);
private static readonly Vector3 _modelTop = new Vector3(0, 1, 0);
private static readonly Vector3 _modelBottom = new Vector3(0, -1, 0);
private static readonly Vector3 _modelFront = new Vector3(0, 0, 1);
private static readonly Vector3 _modelRear = new Vector3(0, 0, -1);
/// <summary>
/// Zero vector, a vector with all components set to <c>0</c>.
/// </summary>
/// <value>Equivalent to <c>new Vector3(0, 0, 0)</c>.</value>
public static Vector3 Zero { get { return _zero; } }
/// <summary>
/// One vector, a vector with all components set to <c>1</c>.
/// </summary>
/// <value>Equivalent to <c>new Vector3(1, 1, 1)</c>.</value>
public static Vector3 One { get { return _one; } }
/// <summary>
/// Infinity vector, a vector with all components set to <see cref="Mathf.Inf"/>.
/// </summary>
/// <value>Equivalent to <c>new Vector3(Mathf.Inf, Mathf.Inf, Mathf.Inf)</c>.</value>
public static Vector3 Inf { get { return _inf; } }
/// <summary>
/// Up unit vector.
/// </summary>
/// <value>Equivalent to <c>new Vector3(0, 1, 0)</c>.</value>
public static Vector3 Up { get { return _up; } }
/// <summary>
/// Down unit vector.
/// </summary>
/// <value>Equivalent to <c>new Vector3(0, -1, 0)</c>.</value>
public static Vector3 Down { get { return _down; } }
/// <summary>
/// Right unit vector. Represents the local direction of right,
/// and the global direction of east.
/// </summary>
/// <value>Equivalent to <c>new Vector3(1, 0, 0)</c>.</value>
public static Vector3 Right { get { return _right; } }
/// <summary>
/// Left unit vector. Represents the local direction of left,
/// and the global direction of west.
/// </summary>
/// <value>Equivalent to <c>new Vector3(-1, 0, 0)</c>.</value>
public static Vector3 Left { get { return _left; } }
/// <summary>
/// Forward unit vector. Represents the local direction of forward,
/// and the global direction of north.
/// </summary>
/// <value>Equivalent to <c>new Vector3(0, 0, -1)</c>.</value>
public static Vector3 Forward { get { return _forward; } }
/// <summary>
/// Back unit vector. Represents the local direction of back,
/// and the global direction of south.
/// </summary>
/// <value>Equivalent to <c>new Vector3(0, 0, 1)</c>.</value>
public static Vector3 Back { get { return _back; } }
/// <summary>
/// Unit vector pointing towards the left side of imported 3D assets.
/// </summary>
public static Vector3 ModelLeft { get { return _modelLeft; } }
/// <summary>
/// Unit vector pointing towards the right side of imported 3D assets.
/// </summary>
public static Vector3 ModelRight { get { return _modelRight; } }
/// <summary>
/// Unit vector pointing towards the top side (up) of imported 3D assets.
/// </summary>
public static Vector3 ModelTop { get { return _modelTop; } }
/// <summary>
/// Unit vector pointing towards the bottom side (down) of imported 3D assets.
/// </summary>
public static Vector3 ModelBottom { get { return _modelBottom; } }
/// <summary>
/// Unit vector pointing towards the front side (facing forward) of imported 3D assets.
/// </summary>
public static Vector3 ModelFront { get { return _modelFront; } }
/// <summary>
/// Unit vector pointing towards the rear side (back) of imported 3D assets.
/// </summary>
public static Vector3 ModelRear { get { return _modelRear; } }
/// <summary>
/// Constructs a new <see cref="Vector3"/> with the given components.
/// </summary>
/// <param name="x">The vector's X component.</param>
/// <param name="y">The vector's Y component.</param>
/// <param name="z">The vector's Z component.</param>
public Vector3(real_t x, real_t y, real_t z)
{
X = x;
Y = y;
Z = z;
}
/// <summary>
/// Adds each component of the <see cref="Vector3"/>
/// with the components of the given <see cref="Vector3"/>.
/// </summary>
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>The added vector.</returns>
public static Vector3 operator +(Vector3 left, Vector3 right)
{
left.X += right.X;
left.Y += right.Y;
left.Z += right.Z;
return left;
}
/// <summary>
/// Subtracts each component of the <see cref="Vector3"/>
/// by the components of the given <see cref="Vector3"/>.
/// </summary>
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>The subtracted vector.</returns>
public static Vector3 operator -(Vector3 left, Vector3 right)
{
left.X -= right.X;
left.Y -= right.Y;
left.Z -= right.Z;
return left;
}
/// <summary>
/// Returns the negative value of the <see cref="Vector3"/>.
/// This is the same as writing <c>new Vector3(-v.X, -v.Y, -v.Z)</c>.
/// This operation flips the direction of the vector while
/// keeping the same magnitude.
/// With floats, the number zero can be either positive or negative.
/// </summary>
/// <param name="vec">The vector to negate/flip.</param>
/// <returns>The negated/flipped vector.</returns>
public static Vector3 operator -(Vector3 vec)
{
vec.X = -vec.X;
vec.Y = -vec.Y;
vec.Z = -vec.Z;
return vec;
}
/// <summary>
/// Multiplies each component of the <see cref="Vector3"/>
/// by the given <see cref="real_t"/>.
/// </summary>
/// <param name="vec">The vector to multiply.</param>
/// <param name="scale">The scale to multiply by.</param>
/// <returns>The multiplied vector.</returns>
public static Vector3 operator *(Vector3 vec, real_t scale)
{
vec.X *= scale;
vec.Y *= scale;
vec.Z *= scale;
return vec;
}
/// <summary>
/// Multiplies each component of the <see cref="Vector3"/>
/// by the given <see cref="real_t"/>.
/// </summary>
/// <param name="scale">The scale to multiply by.</param>
/// <param name="vec">The vector to multiply.</param>
/// <returns>The multiplied vector.</returns>
public static Vector3 operator *(real_t scale, Vector3 vec)
{
vec.X *= scale;
vec.Y *= scale;
vec.Z *= scale;
return vec;
}
/// <summary>
/// Multiplies each component of the <see cref="Vector3"/>
/// by the components of the given <see cref="Vector3"/>.
/// </summary>
/// <param name="left">The left vector.</param>
/// <param name="right">The right vector.</param>
/// <returns>The multiplied vector.</returns>
public static Vector3 operator *(Vector3 left, Vector3 right)
{
left.X *= right.X;
left.Y *= right.Y;
left.Z *= right.Z;
return left;
}
/// <summary>
/// Divides each component of the <see cref="Vector3"/>
/// by the given <see cref="real_t"/>.
/// </summary>
/// <param name="vec">The dividend vector.</param>
/// <param name="divisor">The divisor value.</param>
/// <returns>The divided vector.</returns>
public static Vector3 operator /(Vector3 vec, real_t divisor)
{
vec.X /= divisor;
vec.Y /= divisor;
vec.Z /= divisor;
return vec;
}
/// <summary>
/// Divides each component of the <see cref="Vector3"/>
/// by the components of the given <see cref="Vector3"/>.
/// </summary>
/// <param name="vec">The dividend vector.</param>
/// <param name="divisorv">The divisor vector.</param>
/// <returns>The divided vector.</returns>
public static Vector3 operator /(Vector3 vec, Vector3 divisorv)
{
vec.X /= divisorv.X;
vec.Y /= divisorv.Y;
vec.Z /= divisorv.Z;
return vec;
}
/// <summary>
/// Gets the remainder of each component of the <see cref="Vector3"/>
/// with the components of the given <see cref="real_t"/>.
/// This operation uses truncated division, which is often not desired
/// as it does not work well with negative numbers.
/// Consider using <see cref="PosMod(real_t)"/> instead
/// if you want to handle negative numbers.
/// </summary>
/// <example>
/// <code>
/// GD.Print(new Vector3(10, -20, 30) % 7); // Prints "(3, -6, 2)"
/// </code>
/// </example>
/// <param name="vec">The dividend vector.</param>
/// <param name="divisor">The divisor value.</param>
/// <returns>The remainder vector.</returns>
public static Vector3 operator %(Vector3 vec, real_t divisor)
{
vec.X %= divisor;
vec.Y %= divisor;
vec.Z %= divisor;
return vec;
}
/// <summary>