Browse Source

Quaternion: move type definition outside of module

netstandard
Christoph Ruegg 11 years ago
parent
commit
e6b9ee0763
  1. 2
      src/FSharp/FSharp.fsproj
  2. 161
      src/FSharp/Quaternion.fs
  3. 2
      src/FSharpUnitTests/FSharpUnitTests.fsproj
  4. 22
      src/FSharpUnitTests/QuaternionTests.fs

2
src/FSharp/FSharp.fsproj

@ -74,9 +74,9 @@
<Compile Include="Fit.fs" /> <Compile Include="Fit.fs" />
<Compile Include="FindRoots.fs" /> <Compile Include="FindRoots.fs" />
<Compile Include="RandomVariable.fs" /> <Compile Include="RandomVariable.fs" />
<Compile Include="Quaternion.fs" />
<None Include="MathNet.Numerics.fsx" /> <None Include="MathNet.Numerics.fsx" />
<None Include="MathNet.Numerics.IfSharp.fsx" /> <None Include="MathNet.Numerics.IfSharp.fsx" />
<Compile Include="Quaternion.fs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="mscorlib" /> <Reference Include="mscorlib" />

161
src/FSharp/Quaternion.fs

@ -1,28 +1,56 @@
module MathNet.Numerics.Quaternion // <copyright file="Quaternion.fs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com
//
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
//Reference: namespace MathNet.Numerics
//http://www.astro.rug.nl/software/kapteyn/_downloads/attitude.pdf
//http://www.mathworks.com/help/aeroblks/quaternionmultiplication.html
//http://www.mathworks.com/help/aeroblks/quaterniondivision.html
//https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#The_conjugation_operation
type Quaternion = type Quaternion =
{ {
w:float w:float
x:float x:float
y:float y:float
z:float z:float
} with } with
static member (+) (r: Quaternion, q: Quaternion) = static member (+) (r: Quaternion, q: Quaternion) =
{w=r.w+q.w;x=r.x+q.x;y=r.y+q.y;z=r.z+q.z} {w=r.w+q.w;x=r.x+q.x;y=r.y+q.y;z=r.z+q.z}
static member (-) (r: Quaternion, q: Quaternion) = static member (-) (r: Quaternion, q: Quaternion) =
{w=r.w-q.w;x=r.x-q.x;y=r.y-q.y;z=r.z-q.z} {w=r.w-q.w;x=r.x-q.x;y=r.y-q.y;z=r.z-q.z}
static member (*) (r: Quaternion, q: Quaternion) = static member (*) (r: Quaternion, q: Quaternion) =
let w = r.w*q.w - r.x*q.x - r.y*q.y - r.z*q.z let w = r.w*q.w - r.x*q.x - r.y*q.y - r.z*q.z
let x = r.w*q.x + r.x*q.w - r.y*q.z + r.z*q.y let x = r.w*q.x + r.x*q.w - r.y*q.z + r.z*q.y
let y = r.w*q.y + r.x*q.z + r.y*q.w - r.z*q.x let y = r.w*q.y + r.x*q.z + r.y*q.w - r.z*q.x
let z = r.w*q.z - r.x*q.y + r.y*q.x + r.z*q.w let z = r.w*q.z - r.x*q.y + r.y*q.x + r.z*q.w
{w=w;x=x;y=y;z=z} {w=w;x=x;y=y;z=z}
static member (/) (r: Quaternion, q: Quaternion) = static member (/) (r: Quaternion, q: Quaternion) =
let d = (r.w**2.0 + r.x**2.0 + r.y**2.0 + r.z**2.0) let d = (r.w**2.0 + r.x**2.0 + r.y**2.0 + r.z**2.0)
@ -31,60 +59,71 @@ type Quaternion =
let y = (r.w*q.y + r.x*q.z - r.y*q.w - r.z*q.x) / d let y = (r.w*q.y + r.x*q.z - r.y*q.w - r.z*q.x) / d
let z = (r.w*q.z - r.x*q.y + r.y*q.x - r.z*q.w) / d let z = (r.w*q.z - r.x*q.y + r.y*q.x - r.z*q.w) / d
{w=w;x=x;y=y;z=z} {w=w;x=x;y=y;z=z}
static member (/) (q:Quaternion, a) = static member (/) (q:Quaternion, a) =
{w=q.w/a; x=q.x/a;y=q.y/a;z=q.z/a} {w=q.w/a; x=q.x/a;y=q.y/a;z=q.z/a}
let norm q =
q.w**2.0 + q.x**2.0 + q.y**2.0 + q.z**2.0 [<RequireQualifiedAccess; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Quaternion =
let normalize q =
let invNorm = 1.0 / (norm q |> sqrt) //Reference:
{w=q.w*invNorm;x=q.x*invNorm;y=q.y*invNorm;z=q.z*invNorm} //http://www.astro.rug.nl/software/kapteyn/_downloads/attitude.pdf
//http://www.mathworks.com/help/aeroblks/quaternionmultiplication.html
let conjugate q = //http://www.mathworks.com/help/aeroblks/quaterniondivision.html
{w=q.w; x= -q.x; y= -q.y; z= -q.z} //https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#The_conjugation_operation
let inverse q = let norm q =
conjugate q / norm q q.w**2.0 + q.x**2.0 + q.y**2.0 + q.z**2.0
//create a new quaternion let normalize q =
//angle in radians let invNorm = 1.0 / (norm q |> sqrt)
//http://www.astro.rug.nl/software/kapteyn/_downloads/attitude.pdf {w=q.w*invNorm;x=q.x*invNorm;y=q.y*invNorm;z=q.z*invNorm}
//6.12 Unit Quaternion Axis-Angle
// _ _ let conjugate q =
// qa (α, n) := | cos α/2 | {w=q.w; x= -q.x; y= -q.y; z= -q.z}
// | n sin α/2 |
// - - let inverse q =
let create (angle:float) (x:float) (y:float) (z:float) = conjugate q / norm q
//axis needs to be unit vector
let vNorm = x**2.0+y**2.0+z**2.0 //create a new quaternion
let invNorm = 1.0 / (vNorm |> sqrt) //angle in radians
let x' = x*invNorm //http://www.astro.rug.nl/software/kapteyn/_downloads/attitude.pdf
let y' = y*invNorm //6.12 Unit Quaternion Axis-Angle
let z' = z*invNorm // _ _
// qa (α, n) := | cos α/2 |
let halfAngle = angle * 0.5 // | n sin α/2 |
let s = halfAngle |> sin // - -
let c = halfAngle |> cos let create (angle:float) (x:float) (y:float) (z:float) =
{w=c; x=x'*s; y=y'*s; z=z'*s} //axis needs to be unit vector
let vNorm = x**2.0+y**2.0+z**2.0
//dot product let invNorm = 1.0 / (vNorm |> sqrt)
let dot q1 q2 = let x' = x*invNorm
q1.w*q2.w + q1.x * q2.x + q1.y * q2.y + q1.z * q2.z let y' = y*invNorm
let z' = z*invNorm
//rotate a vector(x,y,z) by a quaternion
// p is a pure quaternion(i.e w=0.0) let halfAngle = angle * 0.5
// p' = qpq**-1.0 let s = halfAngle |> sin
// https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#The_conjugation_operation let c = halfAngle |> cos
let rotate q1 x y z = {w=c; x=x'*s; y=y'*s; z=z'*s}
let q = normalize q1 //ensure unit quaternion
let p = {w=0.0; x=x; y=y; z=z} //dot product
q * p * inverse q let dot q1 q2 =
q1.w*q2.w + q1.x * q2.x + q1.y * q2.y + q1.z * q2.z
/// <summary>
/// Concatenates two Quaternions; the result represents the value1 rotation followed by the value2 rotation. //rotate a vector(x,y,z) by a quaternion
/// </summary> // p is a pure quaternion(i.e w=0.0)
/// <param name="value1">The first Quaternion rotation in the series.</param> // p' = qpq**-1.0
/// <param name="value2">The second Quaternion rotation in the series.</param> // https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#The_conjugation_operation
/// <returns>A new Quaternion representing the concatenation of the value1 rotation followed by the value2 rotation.</returns> let rotate q1 x y z =
let concat (q:Quaternion) (q':Quaternion) = q' * q //concat rotation is actually q' * q instead of q * q'. let q = normalize q1 //ensure unit quaternion
let p = {w=0.0; x=x; y=y; z=z}
q * p * inverse q
/// <summary>
/// Concatenates two Quaternions; the result represents the value1 rotation followed by the value2 rotation.
/// </summary>
/// <param name="value1">The first Quaternion rotation in the series.</param>
/// <param name="value2">The second Quaternion rotation in the series.</param>
/// <returns>A new Quaternion representing the concatenation of the value1 rotation followed by the value2 rotation.</returns>
let concat (q:Quaternion) (q':Quaternion) = q' * q //concat rotation is actually q' * q instead of q * q'.

2
src/FSharpUnitTests/FSharpUnitTests.fsproj

@ -85,9 +85,9 @@
<Compile Include="PokerTests.fs" /> <Compile Include="PokerTests.fs" />
<Compile Include="FitTests.fs" /> <Compile Include="FitTests.fs" />
<Compile Include="FindRootsTests.fs" /> <Compile Include="FindRootsTests.fs" />
<Compile Include="QuaternionTests.fs" />
<None Include="paket.references" /> <None Include="paket.references" />
<None Include="App.config" /> <None Include="App.config" />
<Compile Include="QuaternionTests.fs" />
</ItemGroup> </ItemGroup>
<PropertyGroup> <PropertyGroup>
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath> <FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>

22
src/FSharpUnitTests/QuaternionTests.fs

@ -3,7 +3,7 @@
open System open System
open NUnit.Framework open NUnit.Framework
open FsUnit open FsUnit
open MathNet.Numerics.Quaternion open MathNet.Numerics
module QuaternionTests = module QuaternionTests =
@ -17,15 +17,15 @@ module QuaternionTests =
[<Test>] [<Test>]
let ``Quaternion.create`` () = let ``Quaternion.create`` () =
let fourtyFiveDegreesInRadians = 45.0 * Math.PI / 180.0 let fourtyFiveDegreesInRadians = 45.0 * Math.PI / 180.0
create fourtyFiveDegreesInRadians 1.0 0.0 0.0 |> Quaternion.create fourtyFiveDegreesInRadians 1.0 0.0 0.0 |>
should equal {w = 0.92387953251128674; x = 0.38268343236508978; y = 0.0; z = 0.0;} should equal {w = 0.92387953251128674; x = 0.38268343236508978; y = 0.0; z = 0.0;}
[<Test>] [<Test>]
let ``Quaternion.create normalizes input vector`` () = let ``Quaternion.create normalizes input vector`` () =
let fourtyFiveDegreesInRadians = 45.0 * Math.PI / 180.0 let fourtyFiveDegreesInRadians = 45.0 * Math.PI / 180.0
create fourtyFiveDegreesInRadians 100.0 0.0 0.0 |> Quaternion.create fourtyFiveDegreesInRadians 100.0 0.0 0.0 |>
should equal <| should equal <|
create fourtyFiveDegreesInRadians 1.0 0.0 0.0 Quaternion.create fourtyFiveDegreesInRadians 1.0 0.0 0.0
[<Test>] [<Test>]
let ``Quaternion.+`` () = let ``Quaternion.+`` () =
@ -40,30 +40,30 @@ module QuaternionTests =
r * q |> should equal {w = -8.0; x = -16.0; y = -24.0; z = -2.0;} r * q |> should equal {w = -8.0; x = -16.0; y = -24.0; z = -2.0;}
[<Test>] [<Test>]
let ``Quaternion.* q*r`` () = let ``Quaternion.* q*r`` () =
q * r |> should equal {w = -8.0; x = 6.0; y = -4.0; z = -28.0;} q * r |> should equal {w = -8.0; x = 6.0; y = -4.0; z = -28.0;}
//http://www.mathworks.com/help/aerotbx/ug/quatnorm.html //http://www.mathworks.com/help/aerotbx/ug/quatnorm.html
[<Test>] [<Test>]
let ``Quaternion.Norm`` () = let ``Quaternion.Norm`` () =
norm n' |> should equal 0.75 Quaternion.norm n' |> should equal 0.75
//http://www.mathworks.com/help/aerotbx/ug/quatnormalize.html //http://www.mathworks.com/help/aerotbx/ug/quatnormalize.html
[<Test>] [<Test>]
let ``Quaternion.Normalize`` () = let ``Quaternion.Normalize`` () =
normalize n |> should equal {w= 0.70710678118654746; x= 0.0; y= 0.70710678118654746; z= 0.0} Quaternion.normalize n |> should equal {w= 0.70710678118654746; x= 0.0; y= 0.70710678118654746; z= 0.0}
//http://www.mathworks.com/help/aerotbx/ug/quatinv.html //http://www.mathworks.com/help/aerotbx/ug/quatinv.html
[<Test>] [<Test>]
let ``Quaternion.Inverse`` () = let ``Quaternion.Inverse`` () =
inverse n |> should equal {w= 0.5;x= 0.0;y= -0.5;z= 0.0} Quaternion.inverse n |> should equal {w= 0.5;x= 0.0;y= -0.5;z= 0.0}
//http://www.mathworks.com/help/aerotbx/ug/quatconj.html //http://www.mathworks.com/help/aerotbx/ug/quatconj.html
[<Test>] [<Test>]
let ``Quaternion.Conjugate`` () = let ``Quaternion.Conjugate`` () =
conjugate n |> should equal {w= 1.0;x= 0.0;y= -1.0;z= 0.0} Quaternion.conjugate n |> should equal {w= 1.0;x= 0.0;y= -1.0;z= 0.0}
//http://www.mathworks.com/help/aerotbx/ug/quatrotate.html //http://www.mathworks.com/help/aerotbx/ug/quatrotate.html
[<Test>] [<Test>]
let ``Quaternion.Rotate`` () = let ``Quaternion.Rotate`` () =
rotate n 1.0 1.0 1.0 |> should equal {w= 0.0;x= -1.0;y= 1.0;z= 1.0} Quaternion.rotate n 1.0 1.0 1.0 |> should equal {w= 0.0;x= -1.0;y= 1.0;z= 1.0}

Loading…
Cancel
Save