blob: 19668b9325633f79e50374ef1cb0d36ad5f6dfe7 [file] [log] [blame]
// Ceres Solver - A fast non-linear least squares minimizer
// Copyright 2022 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of Google Inc. nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#ifndef CERES_PUBLIC_INTERNAL_EULER_ANGLES_H_
#define CERES_PUBLIC_INTERNAL_EULER_ANGLES_H_
#include <type_traits>
namespace ceres {
namespace internal {
// The EulerSystem struct represents an Euler Angle Convention in compile time.
// It acts like a trait structure and is also used as a tag for dispatching
// Euler angle conversion function templates
//
// Internally, it implements the convention laid out in "Euler angle
// conversion", Ken Shoemake, Graphics Gems IV, where a choice of axis for the
// first rotation (out of 3) and 3 binary choices compactly specify all 24
// rotation conventions
//
// - InnerAxis: Axis for the first rotation. This is specified by struct tags
// axis::X, axis::Y, and axis::Z
//
// - Parity: Defines the parity of the axis permutation. The axis sequence has
// Even parity if the second axis of rotation is 'greater-than' the first axis
// of rotation according to the order X<Y<Z<X, otherwise it has Odd parity.
// This is specified by struct tags Even and Odd
//
// - AngleConvention: Defines whether Proper Euler Angles (originally defined
// by Euler, which has the last axis repeated, i.e. ZYZ, ZXZ, etc), or
// Tait-Bryan Angles (introduced by the nautical and aerospace fields, i.e.
// using ZYX for roll-pitch-yaw) are used. This is specified by struct Tags
// ProperEuler and TaitBryan.
//
// - FrameConvention: Defines whether the three rotations are be in a global
// frame of reference (extrinsic) or in a body centred frame of reference
// (intrinsic). This is specified by struct tags Extrinsic and Intrinsic
namespace axis {
struct X : std::integral_constant<int, 0> {};
struct Y : std::integral_constant<int, 1> {};
struct Z : std::integral_constant<int, 2> {};
} // namespace axis
struct Even;
struct Odd;
struct ProperEuler;
struct TaitBryan;
struct Extrinsic;
struct Intrinsic;
template <typename InnerAxisType,
typename ParityType,
typename AngleConventionType,
typename FrameConventionType>
struct EulerSystem {
static constexpr bool kIsParityOdd = std::is_same_v<ParityType, Odd>;
static constexpr bool kIsProperEuler =
std::is_same_v<AngleConventionType, ProperEuler>;
static constexpr bool kIsIntrinsic =
std::is_same_v<FrameConventionType, Intrinsic>;
static constexpr int kAxes[3] = {
InnerAxisType::value,
(InnerAxisType::value + 1 + static_cast<int>(kIsParityOdd)) % 3,
(InnerAxisType::value + 2 - static_cast<int>(kIsParityOdd)) % 3};
};
} // namespace internal
// Define human readable aliases to the type of the tags
using ExtrinsicXYZ = internal::EulerSystem<internal::axis::X,
internal::Even,
internal::TaitBryan,
internal::Extrinsic>;
using ExtrinsicXYX = internal::EulerSystem<internal::axis::X,
internal::Even,
internal::ProperEuler,
internal::Extrinsic>;
using ExtrinsicXZY = internal::EulerSystem<internal::axis::X,
internal::Odd,
internal::TaitBryan,
internal::Extrinsic>;
using ExtrinsicXZX = internal::EulerSystem<internal::axis::X,
internal::Odd,
internal::ProperEuler,
internal::Extrinsic>;
using ExtrinsicYZX = internal::EulerSystem<internal::axis::Y,
internal::Even,
internal::TaitBryan,
internal::Extrinsic>;
using ExtrinsicYZY = internal::EulerSystem<internal::axis::Y,
internal::Even,
internal::ProperEuler,
internal::Extrinsic>;
using ExtrinsicYXZ = internal::EulerSystem<internal::axis::Y,
internal::Odd,
internal::TaitBryan,
internal::Extrinsic>;
using ExtrinsicYXY = internal::EulerSystem<internal::axis::Y,
internal::Odd,
internal::ProperEuler,
internal::Extrinsic>;
using ExtrinsicZXY = internal::EulerSystem<internal::axis::Z,
internal::Even,
internal::TaitBryan,
internal::Extrinsic>;
using ExtrinsicZXZ = internal::EulerSystem<internal::axis::Z,
internal::Even,
internal::ProperEuler,
internal::Extrinsic>;
using ExtrinsicZYX = internal::EulerSystem<internal::axis::Z,
internal::Odd,
internal::TaitBryan,
internal::Extrinsic>;
using ExtrinsicZYZ = internal::EulerSystem<internal::axis::Z,
internal::Odd,
internal::ProperEuler,
internal::Extrinsic>;
/* Rotating axes */
using IntrinsicZYX = internal::EulerSystem<internal::axis::X,
internal::Even,
internal::TaitBryan,
internal::Intrinsic>;
using IntrinsicXYX = internal::EulerSystem<internal::axis::X,
internal::Even,
internal::ProperEuler,
internal::Intrinsic>;
using IntrinsicYZX = internal::EulerSystem<internal::axis::X,
internal::Odd,
internal::TaitBryan,
internal::Intrinsic>;
using IntrinsicXZX = internal::EulerSystem<internal::axis::X,
internal::Odd,
internal::ProperEuler,
internal::Intrinsic>;
using IntrinsicXZY = internal::EulerSystem<internal::axis::Y,
internal::Even,
internal::TaitBryan,
internal::Intrinsic>;
using IntrinsicYZY = internal::EulerSystem<internal::axis::Y,
internal::Even,
internal::ProperEuler,
internal::Intrinsic>;
using IntrinsicZXY = internal::EulerSystem<internal::axis::Y,
internal::Odd,
internal::TaitBryan,
internal::Intrinsic>;
using IntrinsicYXY = internal::EulerSystem<internal::axis::Y,
internal::Odd,
internal::ProperEuler,
internal::Intrinsic>;
using IntrinsicYXZ = internal::EulerSystem<internal::axis::Z,
internal::Even,
internal::TaitBryan,
internal::Intrinsic>;
using IntrinsicZXZ = internal::EulerSystem<internal::axis::Z,
internal::Even,
internal::ProperEuler,
internal::Intrinsic>;
using IntrinsicXYZ = internal::EulerSystem<internal::axis::Z,
internal::Odd,
internal::TaitBryan,
internal::Intrinsic>;
using IntrinsicZYZ = internal::EulerSystem<internal::axis::Z,
internal::Odd,
internal::ProperEuler,
internal::Intrinsic>;
} // namespace ceres
#endif // CERES_PUBLIC_INTERNAL_EULER_ANGLES_H_