add assembly

This commit is contained in:
AndreaRigoni
2026-03-25 22:48:04 +00:00
parent 422113a0e9
commit 2c5d6842c3
18 changed files with 800 additions and 171 deletions

146
src/Math/Assembly.cpp Normal file
View File

@@ -0,0 +1,146 @@
/*//////////////////////////////////////////////////////////////////////////////
// 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(),
AffineTransform(),
m_BBoxMin(Vector3f::Zero()),
m_BBoxMax(Vector3f::Zero()),
m_ShowBoundingBox(false),
m_GroupSelection(true) {}
Assembly::Assembly(const Assembly &copy)
: ObjectsContext(copy),
AffineTransform(copy),
m_BBoxMin(copy.m_BBoxMin),
m_BBoxMax(copy.m_BBoxMax),
m_ShowBoundingBox(copy.m_ShowBoundingBox),
m_GroupSelection(copy.m_GroupSelection) {}
Assembly::~Assembly() {}
void Assembly::AddObject(Object *obj) {
if (auto *at = dynamic_cast<AffineTransform *>(obj)) {
at->SetParent(this);
}
ObjectsContext::AddObject(obj);
}
void Assembly::RemoveObject(Object *obj) {
if (auto *at = dynamic_cast<AffineTransform *>(obj)) {
if (at->GetParent() == this)
at->SetParent(nullptr);
}
ObjectsContext::RemoveObject(obj);
}
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);
Matrix4f invAsm = this->GetWorldMatrix().inverse();
for (Object *obj : objects) {
if (auto *box = dynamic_cast<ContainerBox *>(obj)) {
// ContainerBox: wm is matrix from unit cube [0,1] to assembly base
Matrix4f m = invAsm * box->GetWorldMatrix();
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 = invAsm * cyl->GetWorldMatrix();
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 = invAsm * subAsm->GetWorldMatrix();
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

109
src/Math/Assembly.h Normal file
View File

@@ -0,0 +1,109 @@
/*//////////////////////////////////////////////////////////////////////////////
// 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_ASSEMBLY_H
#define U_ASSEMBLY_H
#include "Core/ObjectsContext.h"
#include "Math/ContainerBox.h"
#include "Math/Transform.h"
namespace uLib {
/**
* @brief Assembly groups geometric objects (ContainerBox, Cylinder, etc.)
* under a common transformation.
*
* Assembly derives from ObjectsContext so objects can be added/removed
* dynamically. It also inherits AffineTransform to provide a group-level
* transformation that is applied on top of each child's own transform.
*
* A bounding box is automatically computed from all contained objects and
* can be queried or shown/hidden through the VTK puppet.
*/
class Assembly : public ObjectsContext, public AffineTransform {
public:
virtual const char *GetClassName() const override { return "Assembly"; }
Assembly();
Assembly(const Assembly &copy);
virtual ~Assembly();
virtual void AddObject(Object* obj) override;
virtual void RemoveObject(Object* obj) override;
/**
* @brief Recomputes the axis-aligned bounding box enclosing all children.
* Stores the result internally.
*/
void ComputeBoundingBox();
/**
* @brief Returns the bounding box as min/max corners (in assembly-local
* coordinates).
*/
void GetBoundingBox(Vector3f &bbMin, Vector3f &bbMax) const;
/**
* @brief Returns the bounding box as a ContainerBox (positioned
* at bbMin, sized bbMax-bbMin, parented to this transform).
*/
ContainerBox GetBoundingBoxAsContainer() const;
/**
* @brief Controls whether the bounding box wireframe should be shown
* in the viewer (used by the VTK puppet).
*/
void SetShowBoundingBox(bool show);
bool GetShowBoundingBox() const;
/**
* @brief Controls selection behavior.
* If true (default), clicking any child within the assembly will select
* the assembly itself. If false, individual children can be picked.
*/
void SetGroupSelection(bool group);
bool GetGroupSelection() const;
signals:
virtual void Updated() override {
if (m_InUpdated) return; // break signal recursion
m_InUpdated = true;
this->ComputeBoundingBox();
ULIB_SIGNAL_EMIT(Assembly::Updated);
m_InUpdated = false;
}
private:
Vector3f m_BBoxMin;
Vector3f m_BBoxMax;
bool m_ShowBoundingBox;
bool m_GroupSelection;
bool m_InUpdated = false;
};
} // namespace uLib
#endif // U_ASSEMBLY_H

View File

@@ -1,6 +1,7 @@
set(HEADERS ContainerBox.h
Cylinder.h
Assembly.h
Dense.h
Geometry.h
Transform.h
@@ -33,6 +34,7 @@ set(SOURCES VoxRaytracer.cpp
VoxImage.cpp
TriangleMesh.cpp
QuadMesh.cpp
Assembly.cpp
Dense.cpp
Structured2DGrid.cpp
Structured4DGrid.cpp

View File

@@ -69,6 +69,8 @@ public:
m_Parent(NULL)
{}
virtual ~AffineTransform() {}
AffineTransform(AffineTransform *parent) :
m_T(Matrix4f::Identity()),
m_Parent(parent)