using Autodesk.AutoCAD.Geometry;
using static System.Math;
namespace Gile.AutoCAD.Geometry
{
/// <summary>
/// Defines the relations between a transformation matrix and Euler angles
/// (proper Euler angles using z-x'-z" convention).
/// </summary>
public class ProperEuler : EulerAngles
{
Matrix3d planeToWorld;
/// <summary>
/// Gets the normal of the plane.
/// </summary>
public Vector3d Normal => planeToWorld.CoordinateSystem3d.Zaxis;
/// <summary>
/// Gets the rotation on the plane;
/// </summary>
public double Rotation => phi;
/// <summary>
/// Create a new intance of ProperEuler.
/// </summary>
/// <param name="transform">Transformation matrix.</param>
public ProperEuler(Matrix3d transform) : base(transform)
{
theta = Acos(xform[2, 2] / xform.GetScale());
if (Abs(theta) < 1e-7)
{
theta = 0.0;
psi = Atan2(xform[1, 0], xform[1, 1]);
phi = 0.0;
}
else
{
psi = Atan2(xform[0, 2], -xform[1, 2]);
phi = Atan2(xform[2, 0], xform[2, 1]);
}
planeToWorld =
Matrix3d.Rotation(psi, Vector3d.ZAxis, Point3d.Origin) *
Matrix3d.Rotation(theta, Vector3d.XAxis, Point3d.Origin);
}
/// <summary>
/// Create a new intance of ProperEuler.
/// </summary>
/// <param name="alpha">Rotation angle around the Z axis.</param>
/// <param name="beta">Rotation angle around the X' axis.</param>
/// <param name="gamma">Rotation angle around the Z" axis.</param>
public ProperEuler(double alpha, double beta, double gamma) : base(alpha, beta, gamma)
{
planeToWorld =
Matrix3d.Rotation(alpha, Vector3d.ZAxis, Point3d.Origin) *
Matrix3d.Rotation(beta, Vector3d.XAxis, Point3d.Origin);
xform = planeToWorld *
Matrix3d.Rotation(gamma, Vector3d.ZAxis, Point3d.Origin);
}
/// <summary>
/// Create a new intance of ProperEuler.
/// </summary>
/// <param name="normal">Plane normal.</param>
/// <param name="rotation">Proper rotation.</param>
public ProperEuler(Vector3d normal, double rotation)
: this(Matrix3d.PlaneToWorld(normal) *
Matrix3d.Rotation(rotation, Vector3d.ZAxis, Point3d.Origin))
{ }
/// <summary>
/// Determines whether the specified object is equal to the current object.
/// </summary>
/// <param name="obj">The object to compare with the current object.</param>
/// <returns>true if the specified object is equal to the current object; otherwise, false.</returns>
public override bool Equals
(object obj
) => obj
is ProperEuler
&& base.Equals(obj
);
/// <summary>
/// Serves as hash function.
/// </summary>
/// <returns>A hash code for the current object.</returns>
public override int GetHashCode() => base.GetHashCode();
}
}