Program Listing for File rotation_impl.hpp
↰ Return to documentation for file (include/tf2_2d/rotation_impl.hpp
)
/*
* Software License Agreement (BSD License)
*
* Copyright (c) 2019, Locus Robotics
* All rights reserved.
*
* 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 the copyright holder 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 HOLDER 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 TF2_2D__ROTATION_IMPL_HPP_
#define TF2_2D__ROTATION_IMPL_HPP_
#include <Eigen/Core>
#include <tf2/LinearMath/MinMax.h>
#include <cmath>
#include <tf2_2d/vector2.hpp>
namespace tf2_2d
{
inline Rotation::Rotation()
{
setZero();
}
inline Rotation::Rotation(const tf2Scalar angle)
{
setValue(angle);
}
inline Rotation::Rotation(const tf2Scalar angle, tf2Scalar cos_angle, tf2Scalar sin_angle)
: angle_(angle),
cos_angle_(cos_angle),
sin_angle_(sin_angle)
{
}
inline Rotation Rotation::operator-() const
{
return inverse();
}
inline Rotation & Rotation::operator+=(const Rotation & rhs)
{
setValue(angle_ + rhs.angle_);
return *this;
}
inline Rotation & Rotation::operator-=(const Rotation & rhs)
{
setValue(angle_ - rhs.angle_);
return *this;
}
inline Rotation & Rotation::operator*=(const tf2Scalar rhs)
{
setValue(angle_ * rhs);
return *this;
}
inline Rotation & Rotation::operator/=(const tf2Scalar rhs)
{
tf2FullAssert(rhs != tf2Scalar(0.0));
return *this *= tf2Scalar(1.0) / rhs;
}
inline bool Rotation::operator==(const Rotation & other) const
{
return angle_ == other.angle_;
}
inline bool Rotation::operator!=(const Rotation & other) const
{
return !operator==(other);
}
inline tf2Scalar Rotation::distance2(const Rotation & other) const
{
tf2Scalar d = distance(other);
return d * d;
}
inline tf2Scalar Rotation::distance(const Rotation & other) const
{
return (other - *this).angle();
}
inline Vector2 Rotation::rotate(const Vector2 & vec) const
{
populateTrigCache();
return Vector2(
vec.x() * cos_angle_ - vec.y() * sin_angle_,
vec.x() * sin_angle_ + vec.y() * cos_angle_);
}
inline Vector2 Rotation::unrotate(const Vector2 & vec) const
{
// Populate the cache before inverse() is called.
// The cache is propagated to inverse() temporary object, and we get
// the benefit of having the cache populated for future calls using this object.
populateTrigCache();
return inverse().rotate(vec);
}
inline Rotation Rotation::inverse() const
{
// Use trig identities to keep the trig cache populated
return Rotation(-angle_, cos_angle_, -sin_angle_);
}
inline Rotation Rotation::absolute() const
{
// A little effort to keep the trig cache populated
if (angle_ < 0) {
return inverse();
} else {
return *this;
}
}
inline Rotation Rotation::lerp(const Rotation & other, const tf2Scalar ratio) const
{
return Rotation(angle_ + ratio * (other - *this).angle());
}
inline const tf2Scalar & Rotation::getAngle() const
{
return angle_;
}
inline void Rotation::setAngle(const tf2Scalar angle)
{
setValue(angle);
}
inline void Rotation::setMax(const Rotation & other)
{
if (other.angle_ > angle_) {
*this = other;
}
}
inline void Rotation::setMin(const Rotation & other)
{
if (other.angle_ < angle_) {
*this = other;
}
}
inline void Rotation::setValue(const tf2Scalar angle)
{
angle_ = angle;
cos_angle_ = 0.0;
sin_angle_ = 0.0;
wrap();
}
inline void Rotation::setZero()
{
angle_ = 0.0;
cos_angle_ = 1.0;
sin_angle_ = 0.0;
}
inline bool Rotation::isZero() const
{
return angle_ == 0.0;
}
inline bool Rotation::fuzzyZero() const
{
// Squaring to make it consistent with the Vector2 fuzzyZero check
return (angle_ * angle_) < TF2SIMD_EPSILON;
}
inline Eigen::Matrix2d Rotation::getRotationMatrix() const
{
populateTrigCache();
Eigen::Matrix2d matrix;
matrix << cos_angle_, -sin_angle_, sin_angle_, cos_angle_;
return matrix;
}
inline Eigen::Matrix3d Rotation::getHomogeneousMatrix() const
{
populateTrigCache();
Eigen::Matrix3d matrix;
matrix << cos_angle_, -sin_angle_, 0, sin_angle_, cos_angle_, 0, 0, 0, 1;
return matrix;
}
inline Rotation & Rotation::wrap()
{
// Handle the 2*Pi roll-over
angle_ -= TF2SIMD_2_PI * std::floor((angle_ + TF2SIMD_PI) / TF2SIMD_2_PI);
return *this;
}
inline void Rotation::populateTrigCache() const
{
if ((cos_angle_ == 0) && (sin_angle_ == 0)) {
cos_angle_ = tf2Cos(angle_);
sin_angle_ = tf2Sin(angle_);
}
}
inline Rotation operator+(Rotation lhs, const Rotation & rhs)
{
lhs += rhs;
return lhs;
}
inline Rotation operator-(Rotation lhs, const Rotation & rhs)
{
lhs -= rhs;
return lhs;
}
inline Rotation operator*(Rotation lhs, const tf2Scalar rhs)
{
lhs *= rhs;
return lhs;
}
inline Rotation operator*(const tf2Scalar lhs, Rotation rhs)
{
rhs *= lhs;
return rhs;
}
inline Rotation operator/(Rotation lhs, const tf2Scalar rhs)
{
lhs /= rhs;
return lhs;
}
inline Vector2 operator*(const Rotation & lhs, const Vector2 & rhs)
{
return lhs.rotate(rhs);
}
inline std::ostream & operator<<(std::ostream & stream, const Rotation & rotation)
{
return stream << "angle: " << rotation.angle();
}
} // namespace tf2_2d
#endif // TF2_2D__ROTATION_IMPL_HPP_