/*////////////////////////////////////////////////////////////////////////////// // CMT Cosmic Muon Tomography project ////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// Copyright (c) 2014, Universita' degli Studi di Padova, INFN sez. di Padova All rights reserved Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it > ------------------------------------------------------------------ This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. //////////////////////////////////////////////////////////////////////////////*/ #ifndef U_CYLINDER_H #define U_CYLINDER_H #include "Geometry.h" #include "Core/Object.h" #include "Math/Dense.h" #include "Math/Transform.h" namespace uLib { /** * @brief Represents a cylindrical volume. * * The cylinder orientation is defined by the Axis property (0=X, 1=Y, 2=Z). * By default, it is aligned with the Y axis (Axis=1). */ class Cylinder : public TRS { uLibTypeMacro(Cylinder, TRS) ULIB_DECLARE_PROPERTIES(Cylinder) public: /** * @brief PROPERTIES */ float Radius; float Height; int Axis; /** * @brief Default constructor. Aligns with Y by default. */ Cylinder() : m_LocalT(this), Radius(1.0), Height(1.0), Axis(1) { this->Sync(); } /** * @brief Constructor with radius and height. */ Cylinder(float radius, float height, int axis = 1) : m_LocalT(this), Radius(radius), Height(height), Axis(axis) { this->Sync(); } /** * @brief Copy constructor. */ Cylinder(const Cylinder ©) : m_LocalT(this), TRS(copy), Radius(copy.Radius), Height(copy.Height), Axis(copy.Axis) { this->Sync(); } /** * @brief Serialization template for property registration and persistence. */ template void serialize(ArchiveT & ar, const unsigned int version) { ar & HRP(Radius); ar & HRP(Height); ar & boost::serialization::make_hrp_enum("Axis", Axis, {"X", "Y", "Z"}); ar & NVP("TRS", boost::serialization::base_object(*this)); } /** Sets the radius of the cylinder */ inline void SetRadius(float r) { Radius = r; this->Sync(); } /** Gets the radius of the cylinder */ inline float GetRadius() const { return Radius; } /** Sets the height of the cylinder */ inline void SetHeight(float h) { Height = h; this->Sync(); } /** Gets the height of the cylinder */ inline float GetHeight() const { return Height; } /** Sets the main axis (0=X, 1=Y, 2=Z) */ inline void SetAxis(int axis) { Axis = axis; this->Sync(); } /** Gets the main axis */ inline int GetAxis() const { return Axis; } /** * @brief Returns the world transformation matrix. */ Matrix4f GetWorldMatrix() const { return m_LocalT.GetWorldMatrix(); } /** * @brief Returns the local transformation matrix. */ Matrix4f GetLocalMatrix() const { return m_LocalT.GetMatrix(); } /** * @brief Transforms local cylindrical coordinates to world space. * @param r Local radius. * @param theta Local angle in radians (around main axis). * @param h Local height along main axis. */ inline Vector4f GetWorldPoint(float r, float theta, float h) const { Vector3f p; if (Axis == 0) p = Vector3f(h, r * std::cos(theta), r * std::sin(theta)); else if (Axis == 1) p = Vector3f(r * std::cos(theta), h, r * std::sin(theta)); else p = Vector3f(r * std::cos(theta), r * std::sin(theta), h); return AffineTransform::GetWorldMatrix() * Vector4f(p.x(), p.y(), p.z(), 1.0f); } /** * @brief Transforms a world point to cylindrical local space. * @return Vector3f(r, theta, h) */ inline Vector3f GetCylindricalLocal(const Vector4f &world_v) const { Vector4f local_v = AffineTransform::GetWorldMatrix().inverse() * world_v; float r, theta, h; if (Axis == 0) { h = local_v.x(); r = std::sqrt(local_v.y() * local_v.y() + local_v.z() * local_v.z()); theta = std::atan2(local_v.z(), local_v.y()); } else if (Axis == 1) { h = local_v.y(); r = std::sqrt(local_v.x() * local_v.x() + local_v.z() * local_v.z()); theta = std::atan2(local_v.z(), local_v.x()); } else { h = local_v.z(); r = std::sqrt(local_v.x() * local_v.x() + local_v.y() * local_v.y()); theta = std::atan2(local_v.y(), local_v.x()); } return Vector3f(r, theta, h); } /** Translate using transformation chain */ using AffineTransform::Translate; /** Rotate using transformation chain */ using AffineTransform::Rotate; /** Scale using transformation chain */ using AffineTransform::Scale; signals: /** Signal emitted when properties change */ virtual void Updated() override { // 1. Synchronize local cylinder part (Radius/Height/Axis -> m_LocalT) this->Sync(); // 2. Synchronize TRS part (position/rotation/scaling -> m_T) and emit signal this->TRS::Updated(); } private: /** Synchronizes internal transformation with properties */ void Sync() { m_LocalT = AffineTransform(this); if (Axis == 0) m_LocalT.Scale(Vector3f(Height, Radius, Radius)); else if (Axis == 1) m_LocalT.Scale(Vector3f(Radius, Height, Radius)); else m_LocalT.Scale(Vector3f(Radius, Radius, Height)); } private: AffineTransform m_LocalT; }; } // namespace uLib #endif // U_CYLINDER_H