Skip to content

Commit 2e0f059

Browse files
authored
Merge pull request #472 from open-ephys/tait-bryan
Add TaitBryanAngles type
2 parents ce80d27 + c836b64 commit 2e0f059

File tree

4 files changed

+171
-7
lines changed

4 files changed

+171
-7
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System;
2+
using Bonsai;
3+
using Bonsai.Design.Visualizers;
4+
using OpenEphys.Onix1.Design;
5+
6+
[assembly: TypeVisualizer(typeof(TaitBryanAnglesVisualizer), Target = typeof(OpenEphys.Onix1.TaitBryanAngles))]
7+
8+
namespace OpenEphys.Onix1.Design
9+
{
10+
/// <summary>
11+
/// Provides a type visualizer that displays a sequence of <see cref="TaitBryanAngles"/>
12+
/// values as a time series.
13+
/// </summary>
14+
public class TaitBryanAnglesVisualizer : TimeSeriesVisualizer
15+
{
16+
17+
/// <summary>
18+
/// Initializes a new instance of the <see cref="TaitBryanAnglesVisualizer"/> class.
19+
/// </summary>
20+
public TaitBryanAnglesVisualizer()
21+
: base(numSeries: 3)
22+
{
23+
}
24+
25+
/// <inheritdoc/>
26+
public override void Show(object value)
27+
{
28+
var v = (TaitBryanAngles)value;
29+
AddValue(DateTime.Now, v.Yaw, v.Pitch, v.Roll);
30+
}
31+
}
32+
}

OpenEphys.Onix1/Bno055DataFrame.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ internal unsafe Bno055DataFrame(ulong clock, Bno055Payload* payload)
4040
internal unsafe Bno055DataFrame(ulong clock, Bno055DataPayload* payload)
4141
: base(clock)
4242
{
43-
EulerAngle = new Vector3(
44-
x: Bno055.EulerAngleScale * payload->EulerAngle[0],
45-
y: Bno055.EulerAngleScale * payload->EulerAngle[1],
46-
z: Bno055.EulerAngleScale * payload->EulerAngle[2]);
43+
EulerAngle = new TaitBryanAngles(
44+
yaw: Bno055.EulerAngleScale * payload->EulerAngle[0],
45+
pitch: Bno055.EulerAngleScale * payload->EulerAngle[1],
46+
roll: Bno055.EulerAngleScale * payload->EulerAngle[2]);
4747
Quaternion = new Quaternion(
4848
w: Bno055.QuaternionScale * payload->Quaternion[0],
4949
x: Bno055.QuaternionScale * payload->Quaternion[1],
@@ -62,17 +62,16 @@ internal unsafe Bno055DataFrame(ulong clock, Bno055DataPayload* payload)
6262
}
6363

6464
/// <summary>
65-
/// Gets the 3D orientation in Euler angle format with units of degrees.
65+
/// Gets the 3D orientation in as Euler angles using the Tait-Bryan formalism.
6666
/// </summary>
6767
/// <remarks>
68-
/// The Tait-Bryan formalism is used:
6968
/// <list type="bullet">
7069
/// <item><description>Yaw: 0 to 360 degrees.</description></item>
7170
/// <item><description>Roll: -180 to 180 degrees</description></item>
7271
/// <item><description>Pitch: -90 to 90 degrees</description></item>
7372
/// </list>
7473
/// </remarks>
75-
public Vector3 EulerAngle { get; }
74+
public TaitBryanAngles EulerAngle { get; }
7675

7776
/// <summary>
7877
/// Gets the 3D orientation represented as a Quaternion.

OpenEphys.Onix1/OpenEphys.Onix1.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<ItemGroup>
1414
<PackageReference Include="Bonsai.Core" Version="2.9.0" />
1515
<PackageReference Include="clroni" Version="6.2.0" />
16+
<PackageReference Include="Microsoft.Bcl.Numerics" Version="9.0.7" />
1617
<PackageReference Include="OpenCV.Net" Version="3.4.2" />
1718
<PackageReference Include="OpenEphys.ProbeInterface.NET" Version="0.3.0" />
1819
</ItemGroup>

OpenEphys.Onix1/TaitBryanAngles.cs

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
using System;
2+
using System.Numerics;
3+
4+
namespace OpenEphys.Onix1
5+
{
6+
/// <summary>
7+
/// Represents a vector that describes the orientation of a rigid body using a set of 3 ordered rotations
8+
/// about the object's principal axes.
9+
/// </summary>
10+
/// <remarks>
11+
/// Starting from a ENU (X: East, Y: North, Z: Up) coordinate system:
12+
/// <list type="bullet">
13+
/// <item><description>Yaw represents the bearing, which is the rotation about Z/Up.</description></item>
14+
/// <item><description>Pitch represents the elevation, which is the rotation about Y' after application of Yaw
15+
/// to the ENU coordinates.</description></item>
16+
/// <item><description>Roll gives the bank angle, which is the rotation about X'' after application of Yaw and
17+
/// Pitch to the the ENU coordinates.</description></item>
18+
/// </list>
19+
/// </remarks>
20+
public struct TaitBryanAngles : IEquatable<TaitBryanAngles>
21+
{
22+
private Vector3 vector;
23+
24+
/// <summary>
25+
/// Gets or sets the Yaw.
26+
/// </summary>
27+
/// <remarks>Yaw represents the bearing.</remarks>
28+
public float Yaw
29+
{
30+
readonly get => vector.X;
31+
set => vector.X = value;
32+
}
33+
34+
/// <summary>
35+
/// Gets or sets the Pitch.
36+
/// </summary>
37+
/// <remarks>Pitch represents the elevation.</remarks>
38+
public float Pitch
39+
{
40+
readonly get => vector.Y;
41+
set => vector.Y = value;
42+
}
43+
44+
/// <summary>
45+
/// Gets or sets the Roll.
46+
/// </summary>
47+
/// <remarks>Roll represents the bank angle.</remarks>
48+
public float Roll
49+
{
50+
readonly get => vector.Z;
51+
set => vector.Z = value;
52+
}
53+
54+
/// <summary>
55+
/// Initializes a new instance of the <see cref="TaitBryanAngles"/> struct with the specified yaw, pitch,
56+
/// and roll values.
57+
/// </summary>
58+
/// <param name="yaw">The yaw angle (bearing/rotation about Z axis).</param>
59+
/// <param name="pitch">The pitch angle (elevation/rotation about Y' axis).</param>
60+
/// <param name="roll">The roll angle (bank/rotation about X'' axis).</param>
61+
public TaitBryanAngles(float yaw, float pitch, float roll)
62+
{
63+
vector = new Vector3(yaw, pitch, roll);
64+
}
65+
66+
/// <summary>
67+
/// Initializes a new instance of the <see cref="TaitBryanAngles"/> struct from an existing <see
68+
/// cref="Vector3"/>.
69+
/// </summary>
70+
/// <param name="other">The vector containing the yaw (X), pitch (Y), and roll (Z) values.</param>
71+
public TaitBryanAngles(Vector3 other)
72+
{
73+
vector = other;
74+
}
75+
76+
/// <summary>
77+
/// Initializes a new instance of the <see cref="TaitBryanAngles"/> struct from an existing
78+
/// instance.
79+
/// </summary>
80+
/// <param name="other">An existing TaitBryanAngles object to copy.</param>
81+
public TaitBryanAngles(TaitBryanAngles other)
82+
{
83+
vector = other;
84+
}
85+
86+
/// <summary>
87+
/// Implicitly converts a <see cref="TaitBryanAngles"/> to a <see cref="Vector3"/>.
88+
/// </summary>
89+
/// <param name="euler">The Tait-Bryan angles to convert.</param>
90+
/// <returns>A <see cref="Vector3"/> where X=Yaw, Y=Pitch, Z=Roll.</returns>
91+
public static implicit operator Vector3(TaitBryanAngles euler) => euler.vector;
92+
93+
/// <summary>
94+
/// Implicitly converts a <see cref="Vector3"/> to a <see cref="TaitBryanAngles"/>.
95+
/// </summary>
96+
/// <param name="vector">The vector to convert, where X=Yaw, Y=Pitch, Z=Roll.</param>
97+
/// <returns>A <see cref="TaitBryanAngles"/> instance.</returns>
98+
public static implicit operator TaitBryanAngles(Vector3 vector) => new(vector);
99+
100+
/// <summary>
101+
/// Determines whether two <see cref="TaitBryanAngles"/> instances are equal.
102+
/// </summary>
103+
/// <param name="left">The first instance to compare.</param>
104+
/// <param name="right">The second instance to compare.</param>
105+
/// <returns><c>true</c> if the instances are equal; otherwise, <c>false</c>.</returns>
106+
public static bool operator ==(TaitBryanAngles left, TaitBryanAngles right) => left.vector == right.vector;
107+
108+
/// <summary>
109+
/// Determines whether two <see cref="TaitBryanAngles"/> instances are not equal.
110+
/// </summary>
111+
/// <param name="left">The first instance to compare.</param>
112+
/// <param name="right">The second instance to compare.</param>
113+
/// <returns><c>true</c> if the instances are not equal; otherwise, <c>false</c>.</returns>
114+
public static bool operator !=(TaitBryanAngles left, TaitBryanAngles right) => left.vector != right.vector;
115+
116+
/// <inheritdoc cref = "Vector3.Equals(Vector3)"/>
117+
public bool Equals(TaitBryanAngles other) => vector.Equals(other.vector);
118+
119+
/// <inheritdoc cref = "Vector3.Equals(object)"/>
120+
public override bool Equals(object obj) => obj is TaitBryanAngles other && Equals(other);
121+
122+
/// <inheritdoc cref = "Vector3.GetHashCode"/>
123+
public override int GetHashCode() => vector.GetHashCode();
124+
125+
/// <summary>
126+
/// Returns a string that represents the current object.
127+
/// </summary>
128+
/// <returns>A string representation of the Tait-Bryan angles in the format "Yaw: {{Yaw}, Pitch: {Pitch},
129+
/// Roll: {Roll}".</returns>
130+
public override readonly string ToString() => $"Yaw: {Yaw}, Pitch: {Pitch}, Roll: {Roll}";
131+
}
132+
}

0 commit comments

Comments
 (0)