/*////////////////////////////////////////////////////////////////////////////// // 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 > //////////////////////////////////////////////////////////////////////////////*/ #include "Math/Assembly.h" #include "Math/ContainerBox.h" #include "Math/Cylinder.h" #include #include #include namespace uLib { Assembly::Assembly() : ObjectsContext(), TRS(), m_BBoxMin(Vector3f::Zero()), m_BBoxMax(Vector3f::Zero()), m_ShowBoundingBox(false), m_GroupSelection(true) { } Assembly::Assembly(const Assembly ©) : ObjectsContext(copy), TRS(copy), m_BBoxMin(copy.m_BBoxMin), m_BBoxMax(copy.m_BBoxMax), m_ShowBoundingBox(copy.m_ShowBoundingBox), m_GroupSelection(copy.m_GroupSelection) {} Assembly::~Assembly() { for (auto const& [obj, conn] : m_ChildConnections) { conn.disconnect(); } m_ChildConnections.clear(); } void Assembly::AddObject(Object *obj) { if (auto *at = dynamic_cast(obj)) { at->SetParent(this); } ObjectsContext::AddObject(obj); // Connect to child updates to recompute AABB m_ChildConnections[obj] = Object::connect(obj, &Object::Updated, [this](){ this->ComputeBoundingBox(); this->Updated(); // Signal that assembly itself changed (AABB-wise) }); // Parent -> Child propagation for world matrix updates Object::connect(this, &Object::Updated, obj, &Object::Updated); this->ComputeBoundingBox(); } void Assembly::RemoveObject(Object *obj) { if (auto *at = dynamic_cast(obj)) { if (at->GetParent() == this) at->SetParent(nullptr); } auto itConn = m_ChildConnections.find(obj); if (itConn != m_ChildConnections.end()) { itConn->second.disconnect(); m_ChildConnections.erase(itConn); } ObjectsContext::RemoveObject(obj); this->ComputeBoundingBox(); } void Assembly::ComputeBoundingBox() { const auto &objects = this->GetObjects(); if (objects.empty()) { m_BBoxMin = Vector3f::Zero(); m_BBoxMax = Vector3f::Zero(); return; } float inf = std::numeric_limits::max(); m_BBoxMin = Vector3f(inf, inf, inf); m_BBoxMax = Vector3f(-inf, -inf, -inf); for (Object *obj : objects) { if (auto *box = dynamic_cast(obj)) { // ContainerBox: wm is matrix from unit cube [0,1] to local space // Since it is parented to 'this', GetMatrix() is sufficient. Matrix4f m = box->GetMatrix(); for (int i = 0; i < 8; ++i) { float x = (i & 1) ? 1.0f : 0.0f; float y = (i & 2) ? 1.0f : 0.0f; float z = (i & 4) ? 1.0f : 0.0f; Vector4f corner = m * Vector4f(x, y, z, 1.0f); for (int a = 0; a < 3; ++a) { m_BBoxMin(a) = std::min(m_BBoxMin(a), corner(a)); m_BBoxMax(a) = std::max(m_BBoxMax(a), corner(a)); } } } else if (auto *cyl = dynamic_cast(obj)) { // Cylinder: centered [-1, 1] radial, [-0.5, 0.5] height Matrix4f m = cyl->GetMatrix(); for (int i = 0; i < 8; ++i) { float x = (i & 1) ? 1.0f : -1.0f; float y = (i & 2) ? 0.5f : -0.5f; float z = (i & 4) ? 1.0f : -1.0f; Vector4f corner = m * Vector4f(x, y, z, 1.0f); for (int a = 0; a < 3; ++a) { m_BBoxMin(a) = std::min(m_BBoxMin(a), corner(a)); m_BBoxMax(a) = std::max(m_BBoxMax(a), corner(a)); } } } else if (auto *subAsm = dynamic_cast(obj)) { // Recursive AABB for nested assemblies subAsm->ComputeBoundingBox(); Vector3f subMin, subMax; subAsm->GetBoundingBox(subMin, subMax); Matrix4f m = subAsm->GetMatrix(); for (int i = 0; i < 8; ++i) { float x = (i & 1) ? subMax(0) : subMin(0); float y = (i & 2) ? subMax(1) : subMin(1); float z = (i & 4) ? subMax(2) : subMin(2); Vector4f corner = m * Vector4f(x, y, z, 1.0f); for (int a = 0; a < 3; ++a) { m_BBoxMin(a) = std::min(m_BBoxMin(a), corner(a)); m_BBoxMax(a) = std::max(m_BBoxMax(a), corner(a)); } } } } } void Assembly::GetBoundingBox(Vector3f &bbMin, Vector3f &bbMax) const { bbMin = m_BBoxMin; bbMax = m_BBoxMax; } ContainerBox Assembly::GetBoundingBoxAsContainer() const { ContainerBox bb; Vector3f size = m_BBoxMax - m_BBoxMin; bb.SetSize(size); bb.SetPosition(m_BBoxMin); return bb; } void Assembly::SetShowBoundingBox(bool show) { m_ShowBoundingBox = show; this->Updated(); } bool Assembly::GetShowBoundingBox() const { return m_ShowBoundingBox; } void Assembly::SetGroupSelection(bool group) { m_GroupSelection = group; } bool Assembly::GetGroupSelection() const { return m_GroupSelection; } } // namespace uLib