Skip to content

Commit

Permalink
Builds on my machine
Browse files Browse the repository at this point in the history
  • Loading branch information
Atraxus committed Feb 3, 2025
1 parent 32e7914 commit 02bf34a
Show file tree
Hide file tree
Showing 19 changed files with 286 additions and 383 deletions.
195 changes: 112 additions & 83 deletions Intern/rayx-core/src/Beamline/Beamline.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
#include "Beamline.h"

#include <stdexcept>
#include <sstream>

#include "Design/DesignSource.h"
#include "Design/DesignElement.h"
#include "Design/DesignSource.h"
#include "Debug/Instrumentor.h"

namespace RAYX {

// Move constructor
Group::Group(Group&& other) noexcept
: m_position(std::move(other.m_position)), m_orientation(std::move(other.m_orientation)), children(std::move(other.children)) {}

Expand All @@ -20,162 +23,188 @@ Group& Group::operator=(Group&& other) noexcept {
return *this;
}

// Implementation of Group's getNodeType
NodeType Group::getNodeType() const {
// A Group is inherently of NodeType::Group
return NodeType::Group;
}

// Implementation of getNode to access a child node by index
const BeamlineNode& Group::getNode(size_t index) const {
if (index >= children.size()) {
throw std::out_of_range("Index out of range in Group::getNode");
}
return children[index];
}

void Group::traverse(const std::function<void(const BeamlineNode&)>& callback) const {
// Apply the callback to each child
// Deep-copy (clone) implementation.
Group Group::clone() const {
Group copy;
copy.setPosition(m_position);
copy.setOrientation(m_orientation);
// For each child, clone it and add a new shared pointer.
for (const auto& child : children) {
callback(child);
// If the child is a Group, recursively traverse it
if (std::holds_alternative<Group>(child)) {
std::get<Group>(child).traverse(callback);
}
std::visit(
[&copy](auto& ptr) {
using T = std::decay_t<decltype(ptr)>;
if constexpr (std::is_same_v<T, std::shared_ptr<DesignElement>>) {
copy.addChild(BeamlineNode(std::make_shared<DesignElement>(ptr->clone())));
} else if constexpr (std::is_same_v<T, std::shared_ptr<DesignSource>>) {
copy.addChild(BeamlineNode(std::make_shared<DesignSource>(ptr->clone())));
} else if constexpr (std::is_same_v<T, std::shared_ptr<Group>>) {
copy.addChild(BeamlineNode(std::make_shared<Group>(ptr->clone())));
}
},
child);
}
return copy;
}

// Add a child node (move semantics)
// A Group is always a Group.
NodeType Group::getNodeType() const { return NodeType::Group; }

// Add a child node.
void Group::addChild(BeamlineNode&& child) { children.push_back(std::move(child)); }

MaterialTables Group::calcMinimalMaterialTables() const {
std::vector<const DesignElement*> elements = getElements();

auto elements = getElements();
std::array<bool, 92> relevantMaterials{};
relevantMaterials.fill(false);

for (const auto* e : elements) {
int material = static_cast<int>(e->getMaterial()); // in [1, 92]
if (1 <= material && material <= 92) {
for (const auto& elemPtr : elements) {
int material = static_cast<int>(elemPtr->getMaterial()); // assuming getMaterial() exists
if (material >= 1 && material <= 92) {
relevantMaterials[material - 1] = true;
}
}

return loadMaterialTables(relevantMaterials);
}

void Group::accumulateLightSourcesWorldPositions(const Group& group, const glm::dvec4& parentPos, const glm::dmat4& parentOri,
std::vector<glm::dvec4>& positions) {
glm::dvec4 currentPos = parentOri * group.getPosition() + parentPos;
glm::dmat4 currentOri = parentOri * group.getOrientation();

traverseGroup(group, [&](const BeamlineNode& node) {
if (std::holds_alternative<std::shared_ptr<DesignSource>>(node)) {
const auto& src = std::get<std::shared_ptr<DesignSource>>(node);
glm::dvec4 worldPos = currentOri * src->getPosition() + currentPos;
positions.push_back(worldPos);
} else if (std::holds_alternative<std::shared_ptr<Group>>(node)) {
const auto& childGroup = std::get<std::shared_ptr<Group>>(node);
accumulateLightSourcesWorldPositions(*childGroup, currentPos, currentOri, positions);
}
// DesignElements are ignored.
});
}

std::vector<OpticalElement> Group::compileElements() const {
std::vector<OpticalElement> elements;

// We start at the "world" identity if top-level
auto recurse = [&](auto& self, const Group& grp, const glm::dvec4& parentPos, const glm::dmat4& parentOri) -> void {
// Compute *this group�s* global transform by applying parent transform
glm::dvec4 thisGroupPos = parentOri * grp.getPosition() + parentPos;
glm::dmat4 thisGroupOri = parentOri * grp.getOrientation();

// Recurse children
for (const auto& child : grp.children) {
if (std::holds_alternative<DesignElement>(child)) {
// Pass parent's global transform (thisGroupPos, thisGroupOri)
elements.push_back(std::get<DesignElement>(child).compile(thisGroupPos, thisGroupOri));
} else if (std::holds_alternative<Group>(child)) {
// Recurse deeper
self(self, std::get<Group>(child), thisGroupPos, thisGroupOri);
if (std::holds_alternative<std::shared_ptr<DesignElement>>(child)) {
const auto& de = std::get<std::shared_ptr<DesignElement>>(child);
elements.push_back(de->compile(thisGroupPos, thisGroupOri));
} else if (std::holds_alternative<std::shared_ptr<Group>>(child)) {
self(self, *std::get<std::shared_ptr<Group>>(child), thisGroupPos, thisGroupOri);
}
// Sources are ignored for optical element compilation.
}
};

// Start recursion with identity
recurse(recurse, *this, glm::dvec4(0, 0, 0, 1), glm::dmat4(1.0));
return elements;
}

std::vector<Ray> Group::compileSources(int thread_count) const {
RAYX_PROFILE_FUNCTION_STDOUT();

std::vector<Ray> rays;

// Recursive traversal with group transformations
auto traverseWithTransforms = [&rays, thread_count](const Group& group, const glm::dvec4& parentPosition, const glm::dmat4& parentOrientation,
const auto& self) -> void {
// Accumulate group transformations
glm::dvec4 currentPosition = parentOrientation * group.getPosition() + parentPosition;
glm::dmat4 currentOrientation = parentOrientation * group.getOrientation();

for (const auto& child : group.children) {
if (std::holds_alternative<DesignSource>(child)) {
// Compile the source with the accumulated transformations
auto sourceRays = std::get<DesignSource>(child).compile(thread_count, currentPosition, currentOrientation);
// Update source IDs for rays
if (std::holds_alternative<std::shared_ptr<DesignSource>>(child)) {
const auto& src = std::get<std::shared_ptr<DesignSource>>(child);
auto sourceRays = src->compile(thread_count, currentPosition, currentOrientation);
for (auto& ray : sourceRays) {
ray.m_sourceID = static_cast<uint32_t>(rays.size());
}
// Add rays to the main list
rays.insert(rays.end(), sourceRays.begin(), sourceRays.end());
} else if (std::holds_alternative<Group>(child)) {
// Recurse into the child group
self(std::get<Group>(child), currentPosition, currentOrientation, self);
} else if (std::holds_alternative<std::shared_ptr<Group>>(child)) {
self(*std::get<std::shared_ptr<Group>>(child), currentPosition, currentOrientation, self);
}
}
};

// Start traversal with identity transformations
traverseWithTransforms(*this, glm::dvec4(0, 0, 0, 1), glm::dmat4(1), traverseWithTransforms);

return rays;
}

// Retrieve all DesignElements (deep)
std::vector<const DesignElement*> Group::getElements() const {
std::vector<const DesignElement*> elements;
traverse([&elements](const BeamlineNode& node) {
if (std::holds_alternative<DesignElement>(node)) {
elements.push_back(&std::get<DesignElement>(node));
std::vector<std::shared_ptr<DesignElement>> Group::getElements() const {
std::vector<std::shared_ptr<DesignElement>> elements;
traverseGroup(*this, [&elements](const BeamlineNode& node) {
if (std::holds_alternative<std::shared_ptr<DesignElement>>(node)) {
elements.push_back(std::get<std::shared_ptr<DesignElement>>(node));
}
});
return elements;
}

// Retrieve all DesignSources (deep)
std::vector<const DesignSource*> Group::getSources() const {
std::vector<const DesignSource*> sources;
traverse([&sources](const BeamlineNode& node) {
if (std::holds_alternative<DesignSource>(node)) {
sources.push_back(&std::get<DesignSource>(node));
std::vector<std::shared_ptr<DesignSource>> Group::getSources() const {
std::vector<std::shared_ptr<DesignSource>> sources;
traverseGroup(*this, [&sources](const BeamlineNode& node) {
if (std::holds_alternative<std::shared_ptr<DesignSource>>(node)) {
sources.push_back(std::get<std::shared_ptr<DesignSource>>(node));
}
});
return sources;
}

// Retrieve all Groups (deep)
std::vector<std::shared_ptr<Group>> Group::getGroups() const {
std::vector<std::shared_ptr<Group>> groups;
traverseGroup(*this, [&groups](const BeamlineNode& node) {
if (std::holds_alternative<std::shared_ptr<Group>>(node)) {
groups.push_back(std::get<std::shared_ptr<Group>>(node));
}
});
return groups;
}

size_t Group::numElements() const {
size_t count = 0;
traverse([&count](const BeamlineNode& node) {
if (std::holds_alternative<DesignElement>(node)) {
count++;
traverseGroup(*this, [&count](const BeamlineNode& node) {
if (std::holds_alternative<std::shared_ptr<DesignElement>>(node)) {
++count;
}
});
return count;
}

size_t Group::numSources() const {
size_t count = 0;
traverse([&count](const BeamlineNode& node) {
if (std::holds_alternative<DesignSource>(node)) {
count++;
traverseGroup(*this, [&count](const BeamlineNode& node) {
if (std::holds_alternative<std::shared_ptr<DesignSource>>(node)) {
++count;
}
});
return count;
}

// Retrieve all Groups (deep)
std::vector<const Group*> Group::getGroups() const {
std::vector<const Group*> groups;
traverse([&groups](const BeamlineNode& node) {
if (std::holds_alternative<Group>(node)) {
groups.push_back(&std::get<Group>(node));
// Non‑const overload.
template <typename Callback>
void traverseGroup(Group& group, Callback&& callback) {
// Iterate over the mutable children.
for (auto& child : group.getChildren()) {
callback(child);
// If the child is a Group, then recursively traverse it.
if (std::holds_alternative<std::shared_ptr<Group>>(child)) {
traverseGroup(*std::get<std::shared_ptr<Group>>(child), callback);
}
});
return groups;
}
}

// Const overload.
template <typename Callback>
void traverseGroup(const Group& group, Callback&& callback) {
// Iterate over the children (as read‑only).
for (const auto& child : group.getChildren()) {
callback(child);
// Even in a const context, our variant is defined as holding std::shared_ptr<Group>.
// We can still call traverseGroup on the pointed-to Group.
if (std::holds_alternative<std::shared_ptr<Group>>(child)) {
traverseGroup(*std::get<std::shared_ptr<Group>>(child), callback);
}
}
}

} // namespace RAYX
} // namespace RAYX
44 changes: 26 additions & 18 deletions Intern/rayx-core/src/Beamline/Beamline.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
namespace RAYX {

class Group;
using BeamlineNode = std::variant<DesignElement, DesignSource, Group>;
using BeamlineNode = std::variant<std::shared_ptr<DesignElement>, std::shared_ptr<DesignSource>, std::shared_ptr<Group>>;
enum class NodeType { OpticalElement, LightSource, Group };

class RAYX_API Group {
Expand All @@ -26,54 +26,62 @@ class RAYX_API Group {
Group(const Group&) = delete;
Group& operator=(const Group&) = delete;

NodeType getNodeType() const;
const BeamlineNode& getNode(size_t index) const;
// Clone returns a deep copy of the group and its children.
Group clone() const;

void traverse(const std::function<void(const BeamlineNode&)>& callback) const;
NodeType getNodeType() const;
const std::vector<BeamlineNode>& getChildren() const { return children; }

// Add a child (by move).
void addChild(BeamlineNode&& child);

// Returns the smallest possible MaterialTables which cover all materials of the elements in the group
// Other member functions.
MaterialTables calcMinimalMaterialTables() const;
// Compiles all elements and return vector of OpticalElements
static void accumulateLightSourcesWorldPositions(const Group& group, const glm::dvec4& parentPos, const glm::dmat4& parentOri,
std::vector<glm::dvec4>& positions);
std::vector<OpticalElement> compileElements() const;
std::vector<Ray> compileSources(int thread_count = 1) const;

// New methods for retrieving elements, sources, and groups
std::vector<const DesignElement*> getElements() const;
std::vector<const DesignSource*> getSources() const;
std::vector<const Group*> getGroups() const;
// Getters returning smart pointers.
std::vector<std::shared_ptr<DesignElement>> getElements() const;
std::vector<std::shared_ptr<DesignSource>> getSources() const;
std::vector<std::shared_ptr<Group>> getGroups() const;
size_t numElements() const;
size_t numSources() const;

// Getter & Setter
// Getters & setters for transforms.
const glm::dvec4& getPosition() const { return m_position; }
const glm::dmat4& getOrientation() const { return m_orientation; }

void setPosition(const glm::dvec4& pos) { m_position = pos; }
void setOrientation(const glm::dmat4& orientation) { m_orientation = orientation; }

private:
glm::dvec4 m_position = glm::dvec4(0, 0, 0, 1);
glm::dmat4 m_orientation = glm::dmat4(1);

std::vector<BeamlineNode> children; // Children of the node
std::vector<BeamlineNode> children;
};

using Beamline = Group; // Conceptually, a Beamline is a Group

// Utility function to determine node type
template <typename Callback>
void traverseGroup(Group& group, Callback&& callback);
template <typename Callback>
void traverseGroup(const Group& group, Callback&& callback);

// Utility function to determine node type.
inline NodeType getNodeType(const BeamlineNode& node) {
return std::visit(
[](auto&& element) -> NodeType {
using T = std::decay_t<decltype(element)>;
if constexpr (std::is_same_v<T, DesignElement>) {
if constexpr (std::is_same_v<T, std::shared_ptr<DesignElement>>) {
return NodeType::OpticalElement;
} else if constexpr (std::is_same_v<T, DesignSource>) {
} else if constexpr (std::is_same_v<T, std::shared_ptr<DesignSource>>) {
return NodeType::LightSource;
} else if constexpr (std::is_same_v<T, Group>) {
} else if constexpr (std::is_same_v<T, std::shared_ptr<Group>>) {
return NodeType::Group;
}
},
node);
}

} // namespace RAYX
Loading

0 comments on commit 02bf34a

Please sign in to comment.