@@ -226,12 +226,27 @@ impl<T, U> Vector2D<T, U>
226
226
where
227
227
T : Trig + Copy + Sub < T , Output = T > ,
228
228
{
229
- /// Returns the angle between this vector and the x axis between -PI and PI.
229
+ /// Returns the signed angle between this vector and the x axis.
230
+ ///
231
+ /// The returned angle is between -PI and PI.
230
232
pub fn angle_from_x_axis ( & self ) -> Angle < T > {
231
233
Angle :: radians ( Trig :: fast_atan2 ( self . y , self . x ) )
232
234
}
233
235
}
234
236
237
+ impl < T , U > Vector2D < T , U >
238
+ where
239
+ T : Copy + Mul < T , Output = T > + Add < T , Output = T > + Sub < T , Output = T >
240
+ + Trig + Copy + Sub < T , Output = T > ,
241
+ {
242
+ /// Returns the signed angle between this vector and another vector.
243
+ ///
244
+ /// The returned angle is between -PI and PI.
245
+ pub fn angle_to ( & self , other : Self ) -> Angle < T > {
246
+ Angle :: radians ( Trig :: fast_atan2 ( self . cross ( other) , self . dot ( other) ) )
247
+ }
248
+ }
249
+
235
250
impl < T , U > Vector2D < T , U >
236
251
where
237
252
T : Copy + Mul < T , Output = T > + Add < T , Output = T > + Sub < T , Output = T > ,
@@ -283,6 +298,52 @@ where
283
298
{
284
299
self . square_length ( ) . sqrt ( )
285
300
}
301
+
302
+ /// Returns this vector projected onto another one.
303
+ ///
304
+ /// Projecting onto a nil vector will cause a division by zero.
305
+ #[ inline]
306
+ pub fn project_onto_vector ( & self , onto : Self ) -> Self
307
+ where
308
+ T : Div < T , Output = T >
309
+ {
310
+ onto * ( self . dot ( onto) / onto. square_length ( ) )
311
+ }
312
+ }
313
+
314
+ impl < T , U > Vector2D < T , U >
315
+ where
316
+ T : Copy + Mul < T , Output = T > + Add < T , Output = T > + Sub < T , Output = T >
317
+ + PartialOrd + Float
318
+ {
319
+ /// Return this vector capped to a maximum length.
320
+ #[ inline]
321
+ pub fn with_max_length ( & self , max_length : T ) -> Self {
322
+ let square_length = self . square_length ( ) ;
323
+ if square_length > max_length * max_length {
324
+ return ( * self ) * ( max_length / square_length. sqrt ( ) ) ;
325
+ }
326
+
327
+ * self
328
+ }
329
+
330
+ /// Return this vector with a minimum length applied.
331
+ #[ inline]
332
+ pub fn with_min_length ( & self , min_length : T ) -> Self {
333
+ let square_length = self . square_length ( ) ;
334
+ if square_length < min_length * min_length {
335
+ return ( * self ) * ( min_length / square_length. sqrt ( ) ) ;
336
+ }
337
+
338
+ * self
339
+ }
340
+
341
+ /// Return this vector with minimum and maximum lengths applied.
342
+ #[ inline]
343
+ pub fn clamp_length ( & self , min : T , max : T ) -> Self {
344
+ debug_assert ! ( min <= max) ;
345
+ self . with_min_length ( min) . with_max_length ( max)
346
+ }
286
347
}
287
348
288
349
impl < T , U > Vector2D < T , U >
@@ -299,6 +360,18 @@ where
299
360
}
300
361
}
301
362
363
+ impl < T , U > Vector2D < T , U >
364
+ where
365
+ T : Copy + One + Mul < T , Output = T > + Add < T , Output = T > + Sub < T , Output = T > ,
366
+ {
367
+ /// Returns a reflection vector using an incident ray and a surface normal.
368
+ #[ inline]
369
+ pub fn reflect ( & self , normal : Self ) -> Self {
370
+ let two = T :: one ( ) + T :: one ( ) ;
371
+ * self - normal * two * self . dot ( normal)
372
+ }
373
+ }
374
+
302
375
impl < T : Copy + Add < T , Output = T > , U > Add for Vector2D < T , U > {
303
376
type Output = Self ;
304
377
fn add ( self , other : Self ) -> Self {
@@ -768,6 +841,20 @@ where
768
841
}
769
842
}
770
843
844
+ impl < T , U > Vector3D < T , U >
845
+ where
846
+ T : Copy + Mul < T , Output = T > + Add < T , Output = T > + Sub < T , Output = T >
847
+ + Trig + Copy + Sub < T , Output = T >
848
+ + Float
849
+ {
850
+ /// Returns the positive angle between this vector and another vector.
851
+ ///
852
+ /// The returned angle is between 0 and PI.
853
+ pub fn angle_to ( & self , other : Self ) -> Angle < T > {
854
+ Angle :: radians ( Trig :: fast_atan2 ( self . cross ( other) . length ( ) , self . dot ( other) ) )
855
+ }
856
+ }
857
+
771
858
impl < T : Mul < T , Output = T > + Add < T , Output = T > + Sub < T , Output = T > + Copy , U >
772
859
Vector3D < T , U > {
773
860
// Dot product.
@@ -821,6 +908,52 @@ impl<T: Mul<T, Output = T> + Add<T, Output = T> + Sub<T, Output = T> + Copy, U>
821
908
{
822
909
self . square_length ( ) . sqrt ( )
823
910
}
911
+
912
+ /// Returns this vector projected onto another one.
913
+ ///
914
+ /// Projecting onto a nil vector will cause a division by zero.
915
+ #[ inline]
916
+ pub fn project_onto_vector ( & self , onto : Self ) -> Self
917
+ where
918
+ T : Div < T , Output = T >
919
+ {
920
+ onto * ( self . dot ( onto) / onto. square_length ( ) )
921
+ }
922
+ }
923
+
924
+ impl < T , U > Vector3D < T , U >
925
+ where
926
+ T : Copy + Mul < T , Output = T > + Add < T , Output = T > + Sub < T , Output = T >
927
+ + PartialOrd + Float
928
+ {
929
+ /// Return this vector capped to a maximum length.
930
+ #[ inline]
931
+ pub fn with_max_length ( & self , max_length : T ) -> Self {
932
+ let square_length = self . square_length ( ) ;
933
+ if square_length > max_length * max_length {
934
+ return ( * self ) * ( max_length / square_length. sqrt ( ) ) ;
935
+ }
936
+
937
+ * self
938
+ }
939
+
940
+ /// Return this vector with a minimum length applied.
941
+ #[ inline]
942
+ pub fn with_min_length ( & self , min_length : T ) -> Self {
943
+ let square_length = self . square_length ( ) ;
944
+ if square_length < min_length * min_length {
945
+ return ( * self ) * ( min_length / square_length. sqrt ( ) ) ;
946
+ }
947
+
948
+ * self
949
+ }
950
+
951
+ /// Return this vector with minimum and maximum lengths applied.
952
+ #[ inline]
953
+ pub fn clamp_length ( & self , min : T , max : T ) -> Self {
954
+ debug_assert ! ( min <= max) ;
955
+ self . with_min_length ( min) . with_max_length ( max)
956
+ }
824
957
}
825
958
826
959
impl < T , U > Vector3D < T , U >
@@ -837,6 +970,18 @@ where
837
970
}
838
971
}
839
972
973
+ impl < T , U > Vector3D < T , U >
974
+ where
975
+ T : Copy + One + Mul < T , Output = T > + Add < T , Output = T > + Sub < T , Output = T > ,
976
+ {
977
+ /// Returns a reflection vector using an incident ray and a surface normal.
978
+ #[ inline]
979
+ pub fn reflect ( & self , normal : Self ) -> Self {
980
+ let two = T :: one ( ) + T :: one ( ) ;
981
+ * self - normal * two * self . dot ( normal)
982
+ }
983
+ }
984
+
840
985
impl < T : Copy + Add < T , Output = T > , U > Add for Vector3D < T , U > {
841
986
type Output = Self ;
842
987
#[ inline]
@@ -1458,6 +1603,7 @@ mod vector2d {
1458
1603
1459
1604
assert_eq ! ( result, vec2( 2.0 , 3.0 ) ) ;
1460
1605
}
1606
+
1461
1607
#[ test]
1462
1608
pub fn test_angle_from_x_axis ( ) {
1463
1609
use core:: f32:: consts:: FRAC_PI_2 ;
@@ -1472,6 +1618,69 @@ mod vector2d {
1472
1618
assert ! ( up. angle_from_x_axis( ) . get( ) . approx_eq( & -FRAC_PI_2 ) ) ;
1473
1619
}
1474
1620
1621
+ #[ test]
1622
+ pub fn test_angle_to ( ) {
1623
+ use core:: f32:: consts:: FRAC_PI_2 ;
1624
+ use approxeq:: ApproxEq ;
1625
+
1626
+ let right: Vec2 = vec2 ( 10.0 , 0.0 ) ;
1627
+ let right2: Vec2 = vec2 ( 1.0 , 0.0 ) ;
1628
+ let up: Vec2 = vec2 ( 0.0 , -1.0 ) ;
1629
+ let up_left: Vec2 = vec2 ( -1.0 , -1.0 ) ;
1630
+
1631
+ assert ! ( right. angle_to( right2) . get( ) . approx_eq( & 0.0 ) ) ;
1632
+ assert ! ( right. angle_to( up) . get( ) . approx_eq( & -FRAC_PI_2 ) ) ;
1633
+ assert ! ( up. angle_to( right) . get( ) . approx_eq( & FRAC_PI_2 ) ) ;
1634
+ assert ! ( up_left. angle_to( up) . get( ) . approx_eq_eps( & ( 0.5 * FRAC_PI_2 ) , & 0.0005 ) ) ;
1635
+ }
1636
+
1637
+ #[ test]
1638
+ pub fn test_with_max_length ( ) {
1639
+ use approxeq:: ApproxEq ;
1640
+
1641
+ let v1: Vec2 = vec2 ( 0.5 , 0.5 ) ;
1642
+ let v2: Vec2 = vec2 ( 1.0 , 0.0 ) ;
1643
+ let v3: Vec2 = vec2 ( 0.1 , 0.2 ) ;
1644
+ let v4: Vec2 = vec2 ( 2.0 , -2.0 ) ;
1645
+ let v5: Vec2 = vec2 ( 1.0 , 2.0 ) ;
1646
+ let v6: Vec2 = vec2 ( -1.0 , 3.0 ) ;
1647
+
1648
+ assert_eq ! ( v1. with_max_length( 1.0 ) , v1) ;
1649
+ assert_eq ! ( v2. with_max_length( 1.0 ) , v2) ;
1650
+ assert_eq ! ( v3. with_max_length( 1.0 ) , v3) ;
1651
+ assert_eq ! ( v4. with_max_length( 10.0 ) , v4) ;
1652
+ assert_eq ! ( v5. with_max_length( 10.0 ) , v5) ;
1653
+ assert_eq ! ( v6. with_max_length( 10.0 ) , v6) ;
1654
+
1655
+ let v4_clamped = v4. with_max_length ( 1.0 ) ;
1656
+ assert ! ( v4_clamped. length( ) . approx_eq( & 1.0 ) ) ;
1657
+ assert ! ( v4_clamped. normalize( ) . approx_eq( & v4. normalize( ) ) ) ;
1658
+
1659
+ let v5_clamped = v5. with_max_length ( 1.5 ) ;
1660
+ assert ! ( v5_clamped. length( ) . approx_eq( & 1.5 ) ) ;
1661
+ assert ! ( v5_clamped. normalize( ) . approx_eq( & v5. normalize( ) ) ) ;
1662
+
1663
+ let v6_clamped = v6. with_max_length ( 2.5 ) ;
1664
+ assert ! ( v6_clamped. length( ) . approx_eq( & 2.5 ) ) ;
1665
+ assert ! ( v6_clamped. normalize( ) . approx_eq( & v6. normalize( ) ) ) ;
1666
+ }
1667
+
1668
+ #[ test]
1669
+ pub fn test_project_onto_vector ( ) {
1670
+ use approxeq:: ApproxEq ;
1671
+
1672
+ let v1: Vec2 = vec2 ( 1.0 , 2.0 ) ;
1673
+ let x: Vec2 = vec2 ( 1.0 , 0.0 ) ;
1674
+ let y: Vec2 = vec2 ( 0.0 , 1.0 ) ;
1675
+
1676
+ assert ! ( v1. project_onto_vector( x) . approx_eq( & vec2( 1.0 , 0.0 ) ) ) ;
1677
+ assert ! ( v1. project_onto_vector( y) . approx_eq( & vec2( 0.0 , 2.0 ) ) ) ;
1678
+ assert ! ( v1. project_onto_vector( -x) . approx_eq( & vec2( 1.0 , 0.0 ) ) ) ;
1679
+ assert ! ( v1. project_onto_vector( x * 10.0 ) . approx_eq( & vec2( 1.0 , 0.0 ) ) ) ;
1680
+ assert ! ( v1. project_onto_vector( v1 * 2.0 ) . approx_eq( & v1) ) ;
1681
+ assert ! ( v1. project_onto_vector( -v1) . approx_eq( & v1) ) ;
1682
+ }
1683
+
1475
1684
#[ cfg( feature = "mint" ) ]
1476
1685
#[ test]
1477
1686
pub fn test_mint ( ) {
@@ -1521,6 +1730,17 @@ mod vector2d {
1521
1730
let p: default:: Vector2D < i32 > = vec2 ( 1 , 2 ) ;
1522
1731
assert_eq ! ( p. yx( ) , vec2( 2 , 1 ) ) ;
1523
1732
}
1733
+
1734
+ #[ test]
1735
+ pub fn test_reflect ( ) {
1736
+ use approxeq:: ApproxEq ;
1737
+ let a: Vec2 = vec2 ( 1.0 , 3.0 ) ;
1738
+ let n1: Vec2 = vec2 ( 0.0 , -1.0 ) ;
1739
+ let n2: Vec2 = vec2 ( 1.0 , -1.0 ) . normalize ( ) ;
1740
+
1741
+ assert ! ( a. reflect( n1) . approx_eq( & vec2( 1.0 , -3.0 ) ) ) ;
1742
+ assert ! ( a. reflect( n2) . approx_eq( & vec2( 3.0 , 1.0 ) ) ) ;
1743
+ }
1524
1744
}
1525
1745
1526
1746
#[ cfg( test) ]
@@ -1624,6 +1844,82 @@ mod vector3d {
1624
1844
1625
1845
assert_eq ! ( v1, v2) ;
1626
1846
}
1847
+
1848
+ #[ test]
1849
+ pub fn test_reflect ( ) {
1850
+ use approxeq:: ApproxEq ;
1851
+ let a: Vec3 = vec3 ( 1.0 , 3.0 , 2.0 ) ;
1852
+ let n1: Vec3 = vec3 ( 0.0 , -1.0 , 0.0 ) ;
1853
+ let n2: Vec3 = vec3 ( 0.0 , 1.0 , 1.0 ) . normalize ( ) ;
1854
+
1855
+ assert ! ( a. reflect( n1) . approx_eq( & vec3( 1.0 , -3.0 , 2.0 ) ) ) ;
1856
+ assert ! ( a. reflect( n2) . approx_eq( & vec3( 1.0 , -2.0 , -3.0 ) ) ) ;
1857
+ }
1858
+
1859
+ #[ test]
1860
+ pub fn test_angle_to ( ) {
1861
+ use core:: f32:: consts:: FRAC_PI_2 ;
1862
+ use approxeq:: ApproxEq ;
1863
+
1864
+ let right: Vec3 = vec3 ( 10.0 , 0.0 , 0.0 ) ;
1865
+ let right2: Vec3 = vec3 ( 1.0 , 0.0 , 0.0 ) ;
1866
+ let up: Vec3 = vec3 ( 0.0 , -1.0 , 0.0 ) ;
1867
+ let up_left: Vec3 = vec3 ( -1.0 , -1.0 , 0.0 ) ;
1868
+
1869
+ assert ! ( right. angle_to( right2) . get( ) . approx_eq( & 0.0 ) ) ;
1870
+ assert ! ( right. angle_to( up) . get( ) . approx_eq( & FRAC_PI_2 ) ) ;
1871
+ assert ! ( up. angle_to( right) . get( ) . approx_eq( & FRAC_PI_2 ) ) ;
1872
+ assert ! ( up_left. angle_to( up) . get( ) . approx_eq_eps( & ( 0.5 * FRAC_PI_2 ) , & 0.0005 ) ) ;
1873
+ }
1874
+
1875
+ #[ test]
1876
+ pub fn test_with_max_length ( ) {
1877
+ use approxeq:: ApproxEq ;
1878
+
1879
+ let v1: Vec3 = vec3 ( 0.5 , 0.5 , 0.0 ) ;
1880
+ let v2: Vec3 = vec3 ( 1.0 , 0.0 , 0.0 ) ;
1881
+ let v3: Vec3 = vec3 ( 0.1 , 0.2 , 0.3 ) ;
1882
+ let v4: Vec3 = vec3 ( 2.0 , -2.0 , 2.0 ) ;
1883
+ let v5: Vec3 = vec3 ( 1.0 , 2.0 , -3.0 ) ;
1884
+ let v6: Vec3 = vec3 ( -1.0 , 3.0 , 2.0 ) ;
1885
+
1886
+ assert_eq ! ( v1. with_max_length( 1.0 ) , v1) ;
1887
+ assert_eq ! ( v2. with_max_length( 1.0 ) , v2) ;
1888
+ assert_eq ! ( v3. with_max_length( 1.0 ) , v3) ;
1889
+ assert_eq ! ( v4. with_max_length( 10.0 ) , v4) ;
1890
+ assert_eq ! ( v5. with_max_length( 10.0 ) , v5) ;
1891
+ assert_eq ! ( v6. with_max_length( 10.0 ) , v6) ;
1892
+
1893
+ let v4_clamped = v4. with_max_length ( 1.0 ) ;
1894
+ assert ! ( v4_clamped. length( ) . approx_eq( & 1.0 ) ) ;
1895
+ assert ! ( v4_clamped. normalize( ) . approx_eq( & v4. normalize( ) ) ) ;
1896
+
1897
+ let v5_clamped = v5. with_max_length ( 1.5 ) ;
1898
+ assert ! ( v5_clamped. length( ) . approx_eq( & 1.5 ) ) ;
1899
+ assert ! ( v5_clamped. normalize( ) . approx_eq( & v5. normalize( ) ) ) ;
1900
+
1901
+ let v6_clamped = v6. with_max_length ( 2.5 ) ;
1902
+ assert ! ( v6_clamped. length( ) . approx_eq( & 2.5 ) ) ;
1903
+ assert ! ( v6_clamped. normalize( ) . approx_eq( & v6. normalize( ) ) ) ;
1904
+ }
1905
+
1906
+ #[ test]
1907
+ pub fn test_project_onto_vector ( ) {
1908
+ use approxeq:: ApproxEq ;
1909
+
1910
+ let v1: Vec3 = vec3 ( 1.0 , 2.0 , 3.0 ) ;
1911
+ let x: Vec3 = vec3 ( 1.0 , 0.0 , 0.0 ) ;
1912
+ let y: Vec3 = vec3 ( 0.0 , 1.0 , 0.0 ) ;
1913
+ let z: Vec3 = vec3 ( 0.0 , 0.0 , 1.0 ) ;
1914
+
1915
+ assert ! ( v1. project_onto_vector( x) . approx_eq( & vec3( 1.0 , 0.0 , 0.0 ) ) ) ;
1916
+ assert ! ( v1. project_onto_vector( y) . approx_eq( & vec3( 0.0 , 2.0 , 0.0 ) ) ) ;
1917
+ assert ! ( v1. project_onto_vector( z) . approx_eq( & vec3( 0.0 , 0.0 , 3.0 ) ) ) ;
1918
+ assert ! ( v1. project_onto_vector( -x) . approx_eq( & vec3( 1.0 , 0.0 , 0.0 ) ) ) ;
1919
+ assert ! ( v1. project_onto_vector( x * 10.0 ) . approx_eq( & vec3( 1.0 , 0.0 , 0.0 ) ) ) ;
1920
+ assert ! ( v1. project_onto_vector( v1 * 2.0 ) . approx_eq( & v1) ) ;
1921
+ assert ! ( v1. project_onto_vector( -v1) . approx_eq( & v1) ) ;
1922
+ }
1627
1923
}
1628
1924
1629
1925
#[ cfg( test) ]
0 commit comments