172 lines
5.4 KiB
C++
172 lines
5.4 KiB
C++
/*//////////////////////////////////////////////////////////////////////////////
|
|
// 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 <limits>
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
|
|
namespace uLib {
|
|
|
|
Assembly::Assembly()
|
|
: ObjectsContext(),
|
|
TRS(),
|
|
m_BBoxMin(Vector3f::Zero()),
|
|
m_BBoxMax(Vector3f::Zero()),
|
|
m_ShowBoundingBox(false),
|
|
m_GroupSelection(true) {
|
|
ULIB_ACTIVATE_PROPERTIES(*this);
|
|
}
|
|
|
|
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<AffineTransform *>(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<AffineTransform *>(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<float>::max();
|
|
m_BBoxMin = Vector3f(inf, inf, inf);
|
|
m_BBoxMax = Vector3f(-inf, -inf, -inf);
|
|
|
|
for (Object *obj : objects) {
|
|
if (auto *box = dynamic_cast<ContainerBox *>(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<Cylinder *>(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<Assembly *>(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
|