Skip to content

Commit

Permalink
Add Vec.AngleBetweenSigned for 2D vectors
Browse files Browse the repository at this point in the history
  • Loading branch information
hyazinthh committed Nov 13, 2024
1 parent 3f701f3 commit 923808b
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 1 deletion.
1 change: 1 addition & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
- Added angle conversion utilities for ranges
- Added Ray3.Transformed overloads
- Added Ray3.Normalized
- Added Vec.AngleBetweenSigned for 2D vectors

### 5.3.5
- [Base] added IsEmpty/IsEmptyOrNull overloads for Array/ICollection with efficient implementation
Expand Down
26 changes: 26 additions & 0 deletions src/Aardvark.Base/Geometry/Types/Ray/Ray2_auto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ public readonly Ray2f Reversed
get => new Ray2f(Origin, -Direction);
}

/// <summary>
/// Returns the ray with its directional normalized.
/// </summary>
public readonly Ray2f Normalized => new(Origin, Direction.Normalized);

#endregion

#region Ray Arithmetics
Expand Down Expand Up @@ -217,6 +222,14 @@ public readonly float AngleBetweenFast(Ray2f r)
public readonly float AngleBetween(Ray2f r)
=> Direction.AngleBetween(r.Direction);

/// <summary>
/// Returns the signed angle between this and the given <see cref="Ray2f"/> in radians.
/// The direction vectors of the input rays have to be normalized.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly float AngleBetweenSigned(Ray2f r)
=> Direction.AngleBetweenSigned(r.Direction);

/// <summary>
/// Returns a signed value where left is negative and right positive.
/// The magnitude is equal to the float size of the triangle the ray + direction and p.
Expand Down Expand Up @@ -650,6 +663,11 @@ public readonly Ray2d Reversed
get => new Ray2d(Origin, -Direction);
}

/// <summary>
/// Returns the ray with its directional normalized.
/// </summary>
public readonly Ray2d Normalized => new(Origin, Direction.Normalized);

#endregion

#region Ray Arithmetics
Expand Down Expand Up @@ -744,6 +762,14 @@ public readonly double AngleBetweenFast(Ray2d r)
public readonly double AngleBetween(Ray2d r)
=> Direction.AngleBetween(r.Direction);

/// <summary>
/// Returns the signed angle between this and the given <see cref="Ray2d"/> in radians.
/// The direction vectors of the input rays have to be normalized.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly double AngleBetweenSigned(Ray2d r)
=> Direction.AngleBetweenSigned(r.Direction);

/// <summary>
/// Returns a signed value where left is negative and right positive.
/// The magnitude is equal to the double size of the triangle the ray + direction and p.
Expand Down
13 changes: 13 additions & 0 deletions src/Aardvark.Base/Geometry/Types/Ray/Ray2_template.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ public readonly __ray2t__ Reversed
get => new __ray2t__(Origin, -Direction);
}

/// <summary>
/// Returns the ray with its directional normalized.
/// </summary>
public readonly __ray2t__ Normalized => new(Origin, Direction.Normalized);

#endregion

#region Ray Arithmetics
Expand Down Expand Up @@ -233,6 +238,14 @@ public readonly __ftype__ AngleBetweenFast(__ray2t__ r)
public readonly __ftype__ AngleBetween(__ray2t__ r)
=> Direction.AngleBetween(r.Direction);

/// <summary>
/// Returns the signed angle between this and the given <see cref="__ray2t__"/> in radians.
/// The direction vectors of the input rays have to be normalized.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly __ftype__ AngleBetweenSigned(__ray2t__ r)
=> Direction.AngleBetweenSigned(r.Direction);

/// <summary>
/// Returns a signed value where left is negative and right positive.
/// The magnitude is equal to the __ftype__ size of the triangle the ray + direction and p.
Expand Down
22 changes: 22 additions & 0 deletions src/Aardvark.Base/Math/Vectors/Vector_auto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20277,6 +20277,17 @@ public static float AngleBetween(this V2f x, V2f y)
return 2 * Fun.Atan2(b.Length, a.Length);
}

/// <summary>
/// Computes the signed angle between two given vectors in radians. The input vectors have to be normalized.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float AngleBetweenSigned(this V2f x, V2f y)
{
var a = x.X * y.Y - x.Y * y.X;
var b = x.X * y.X + x.Y * y.Y;
return Fun.Atan2(a, b);
}

#endregion

#region AnyTiny, AllTiny
Expand Down Expand Up @@ -26481,6 +26492,17 @@ public static double AngleBetween(this V2d x, V2d y)
return 2 * Fun.Atan2(b.Length, a.Length);
}

/// <summary>
/// Computes the signed angle between two given vectors in radians. The input vectors have to be normalized.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double AngleBetweenSigned(this V2d x, V2d y)
{
var a = x.X * y.Y - x.Y * y.X;
var b = x.X * y.X + x.Y * y.Y;
return Fun.Atan2(a, b);
}

#endregion

#region AnyTiny, AllTiny
Expand Down
13 changes: 13 additions & 0 deletions src/Aardvark.Base/Math/Vectors/Vector_template.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2376,6 +2376,19 @@ public static __ctype__ AngleBetween(this __vtype__ x, __vtype__ y)
return 2 * Fun.Atan2(b.Length, a.Length);
}

//# if (d == 2) {
/// <summary>
/// Computes the signed angle between two given vectors in radians. The input vectors have to be normalized.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static __ctype__ AngleBetweenSigned(this __vtype__ x, __vtype__ y)
{
var a = x.X * y.Y - x.Y * y.X;
var b = x.X * y.X + x.Y * y.Y;
return Fun.Atan2(a, b);
}

//# }
#endregion

//# }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
<Compile Include="SizeOfTests.fs" />
<Compile Include="TypeMetaTests.fs" />
<Compile Include="Program.fs" />
<None Include="paket.references" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Aardvark.Base.FSharp\Aardvark.Base.FSharp.fsproj" />
Expand Down
56 changes: 55 additions & 1 deletion src/Tests/Aardvark.Base.FSharp.Tests/Math/MathTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,48 @@ open Aardvark.Base

open NUnit.Framework
open FsUnit
open FsCheck
open FsCheck.NUnit
open System

module MathTests =

let equalWithin x eps = (new NUnit.Framework.Constraints.EqualConstraint(x)).Within(eps)

type RotationTestCase2D =
{
Src: V2d
Dst: V2d
Angle: float
}

module Gen =
let floatUnit =
gen {
let! n = Arb.generate<uint32>
return float n / float UInt32.MaxValue
}

let direction2d =
gen {
let! t = floatUnit
return Rot2d(t * Constant.PiTimesTwo) * V2d.XAxis
}

type Generator private () =
static member AngleTestCase =
gen {
let! t = Gen.floatUnit
let angle = (t - 0.5) * Constant.PiTimesTwo

let! src = Gen.direction2d
let rot = Rot2d angle
let dst = rot * src

return { Src = src; Dst = dst; Angle = angle }
}
|> Arb.fromGen

[<Test>]
let ``[Math] lerp`` () =
// Just making sure the parameter order is correct :S
Expand Down Expand Up @@ -50,4 +89,19 @@ module MathTests =
lerp (V2d(50)) (V2d(100)) 0.5 |> should equal (Fun.Lerp(0.5, V2d(50), V2d(100)))
lerp (V2d(50)) (V2d(100)) (V2d(0.5)) |> should equal (Fun.Lerp(V2d(0.5), V2d(50), V2d(100)))

lerp (C4d(50.0)) (C4d(100.0)) 0.5 |> should equal (Fun.Lerp(0.5, C4d(50.0), C4d(100.0)))
lerp (C4d(50.0)) (C4d(100.0)) 0.5 |> should equal (Fun.Lerp(0.5, C4d(50.0), C4d(100.0)))

[<Property(Arbitrary = [| typeof<Generator> |])>]
let ``[Math] AngleBetween 2D`` (input: RotationTestCase2D) =
let result = Vec.AngleBetween(input.Src, input.Dst)
result |> should be (equalWithin (abs input.Angle) 0.00001)

[<Property(Arbitrary = [| typeof<Generator> |])>]
let ``[Math] AngleBetweenFast 2D`` (input: RotationTestCase2D) =
let result = Vec.AngleBetweenFast(input.Src, input.Dst)
result |> should be (equalWithin (abs input.Angle) 0.00001)

[<Property(Arbitrary = [| typeof<Generator> |])>]
let ``[Math] AngleBetweenSigned 2D`` (input: RotationTestCase2D) =
let result = Vec.AngleBetweenSigned(input.Src, input.Dst)
result |> should be (equalWithin input.Angle 0.00001)

0 comments on commit 923808b

Please sign in to comment.