Mantid
Loading...
Searching...
No Matches
CompAssembly.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
15#include <algorithm>
16#include <ostream>
17#include <stdexcept>
18
19namespace Mantid::Geometry {
20
21using Kernel::Quat;
22using Kernel::V3D;
23
26CompAssembly::CompAssembly() : Component(), m_children(), m_cachedBoundingBox(nullptr) {}
27
33 : Component(base, map), m_children(), m_cachedBoundingBox(nullptr) {}
34
44CompAssembly::CompAssembly(const std::string &n, IComponent *reference)
45 : Component(n, reference), m_children(), m_cachedBoundingBox(nullptr) {
46 if (reference) {
47 auto *test = dynamic_cast<ICompAssembly *>(reference);
48 if (test) {
49 test->add(this);
50 }
51 }
52}
53
58 : ICompAssembly(assem), Component(assem), m_children(), m_cachedBoundingBox(nullptr) {
59 *this = assem;
60}
61
63 if (this == &assem)
64 return *this;
65 for (auto const *child : m_children) {
66 delete child;
67 }
68 // The bounding box is not copied: each assembly owns its cache, which is rebuilt on demand
70 m_cachedBoundingBox = nullptr;
71 m_children = assem.m_children;
72
73 // Need to do a deep copy
75 for (it = m_children.begin(); it != m_children.end(); ++it) {
76 *it = (*it)->clone();
77 // Move copied component object's parent from old to new CompAssembly
78 (*it)->setParent(this);
79 }
80
81 return *this;
82}
83
89 // Iterate over pointers in m_children, deleting them
90 for (auto &child : m_children) {
91 delete child;
92 }
93 m_children.clear();
94}
95
100IComponent *CompAssembly::clone() const { return new CompAssembly(*this); }
101
109 if (m_map)
110 throw std::runtime_error("CompAssembly::add() called for a parametrized CompAssembly.");
111
112 if (comp) {
113 comp->setParent(this);
114 m_children.emplace_back(std::move(comp));
115 }
116 return static_cast<int>(m_children.size());
117}
118
128 if (m_map)
129 throw std::runtime_error("CompAssembly::addCopy() called for a parametrized CompAssembly.");
130
131 if (comp) {
132 IComponent *newcomp = comp->clone();
133 newcomp->setParent(this);
134 m_children.emplace_back(newcomp);
135 }
136 return static_cast<int>(m_children.size());
137}
138
148int CompAssembly::addCopy(IComponent *comp, const std::string &n) {
149 if (m_map)
150 throw std::runtime_error("CompAssembly::addCopy() called for a parametrized CompAssembly.");
151
152 if (comp) {
153 IComponent *newcomp = comp->clone();
154 newcomp->setParent(this);
155 newcomp->setName(n);
156 m_children.emplace_back(newcomp);
157 }
158 return static_cast<int>(m_children.size());
159}
160
167 if (m_map)
168 throw std::runtime_error("CompAssembly::remove() called for a parameterized CompAssembly.");
169
170 // Look for the passed in component in the list of children
171 auto it = std::find(m_children.begin(), m_children.end(), comp);
172 if (it != m_children.end()) {
173 // If it's found, remove it from the list and then delete it
174 m_children.erase(it);
175 delete comp;
176 } else {
177 throw std::runtime_error("Component " + comp->getName() + " is not a child of this assembly.");
178 }
179
180 return static_cast<int>(m_children.size());
181}
182
187 if (m_map) {
188 auto compAss = dynamic_cast<const CompAssembly *>(m_base);
189 if (!compAss) {
190 throw std::logic_error("Failed to cast base component to CompAssembly");
191 }
192 return compAss->nelements();
193 } else
194 return static_cast<int>(m_children.size());
195}
196
207std::shared_ptr<IComponent> CompAssembly::getChild(const int i) const {
208 if (m_map) {
209 // Get the child of the base (unparametrized) assembly
210 auto child_base = dynamic_cast<const CompAssembly *>(m_base);
211 if (!child_base) {
212 throw std::logic_error("Failed to cast base component to CompAssembly");
213 }
214 // And build up a parametrized version of it using the factory, and return
215 // that
216 return ParComponentFactory::create(child_base->getChild(i), m_map);
217 } else {
218 if (i < 0 || i > static_cast<int>(m_children.size() - 1)) {
219 throw std::runtime_error("CompAssembly::getChild() range not valid");
220 }
221 return std::shared_ptr<IComponent>(m_children[i], NoDeleting());
222 }
223}
224
230std::shared_ptr<IComponent> CompAssembly::operator[](int i) const { return this->getChild(i); }
231
232//------------------------------------------------------------------------------------------------
239void CompAssembly::getChildren(std::vector<IComponent_const_sptr> &outVector, bool recursive) const {
240 for (int i = 0; i < this->nelements(); i++) {
241 std::shared_ptr<IComponent> comp = this->getChild(i);
242 if (comp) {
243 outVector.emplace_back(comp);
244 // Look deeper, on option.
245 if (recursive) {
246 std::shared_ptr<ICompAssembly> assemb = std::dynamic_pointer_cast<ICompAssembly>(comp);
247 if (assemb)
248 assemb->getChildren(outVector, recursive);
249 }
250 }
251 }
252}
253
272std::shared_ptr<const IComponent> CompAssembly::getComponentByName(const std::string &cname, int nlevels) const {
273 std::shared_ptr<const ICompAssembly> thisNode = std::shared_ptr<const ICompAssembly>(this, NoDeleting());
274
275 // If name has '/' in it, it is taken as part of a path name of the component.
276 // Steps may be skipped at a '/' from the path name,
277 // but if what follows the skip is not unique within what precedes it, only
278 // the first found is returned.
279 size_t cut = cname.find('/');
280 if (cut < cname.length()) {
281 auto otherNode = this->getComponentByName(cname.substr(0, cut), nlevels);
282 if (otherNode) {
283 std::shared_ptr<const ICompAssembly> asmb = std::dynamic_pointer_cast<const ICompAssembly>(otherNode);
284 return asmb->getComponentByName(cname.substr(cut + 1, std::string::npos), nlevels);
285 } else {
286 return std::shared_ptr<const IComponent>(); // Search failed
287 }
288 }
289
290 // Check the instrument name first
291 if (this->getName() == cname) {
292 return std::dynamic_pointer_cast<const ICompAssembly>(thisNode);
293 }
294 // Otherwise Search the instrument tree using a breadth-first search algorithm
295 // since most likely candidates
296 // are higher-level components
297 // I found some useful info here
298 // http://www.cs.bu.edu/teaching/c/tree/breadth-first/
299 std::deque<std::shared_ptr<const ICompAssembly>> nodeQueue{thisNode};
300 const bool limitSearch(nlevels > 0);
301 while (!nodeQueue.empty()) {
302 // get the next node in the queue
303 std::shared_ptr<const ICompAssembly> node = nodeQueue.front();
304 nodeQueue.pop_front();
305
306 // determine the depth
307 int depth(1);
308 if (limitSearch) {
309 auto parent = node->getParent();
310 while (parent && (this->getName() != parent->getName())) {
311 parent = parent->getParent();
312 depth++;
313 }
314 }
315
316 auto rectDet = std::dynamic_pointer_cast<const RectangularDetector>(node);
317 auto structDet = std::dynamic_pointer_cast<const StructuredDetector>(node);
318
319 if (bool(rectDet) && (node != thisNode)) {
320 // for rectangular detectors search the depth rather than siblings
321 // as there
322 // is a specific naming convention to speed things along
323 auto child = rectDet->getComponentByName(cname, nlevels);
324 if (child)
325 return child;
326 } else if (bool(structDet) && (node != thisNode)) {
327 auto child = structDet->getComponentByName(cname, nlevels);
328 if (child != nullptr)
329 return child;
330 } else {
331 // loop over the children
332 int nchildren = node->nelements();
333 for (int i = 0; i < nchildren; ++i) {
334 std::shared_ptr<const IComponent> comp = (*node)[i];
335 if (comp->getName() == cname) {
336 return comp;
337 } else {
338 // only add things if max-recursion depth hasn't been reached
339 if ((!limitSearch) || (depth + 1 < nlevels)) {
340 // don't bother adding things to the queue that aren't
341 // assemblies
342 std::shared_ptr<const ICompAssembly> compAssembly = std::dynamic_pointer_cast<const ICompAssembly>(comp);
343 if (bool(compAssembly)) {
344 nodeQueue.emplace_back(compAssembly);
345 }
346 }
347 }
348 }
349 }
350 } // while-end
351
352 // If we have reached here then the search failed
353 return std::shared_ptr<const IComponent>();
354}
355
356//------------------------------------------------------------------------------------------------
363 if (m_map) {
364
365 if (hasComponentInfo()) {
366 assemblyBox = m_map->componentInfo().boundingBox(index(), &assemblyBox);
367 return;
368 }
369
370 // Loop over the children and define a box large enough for all of them
371 assemblyBox = BoundingBox(); // this makes assembly box always axis alighned
372 int nchildren = nelements();
373 for (int i = 0; i < nchildren; ++i) {
374 IComponent_sptr comp = this->operator[](i);
375 BoundingBox compBox;
376 comp->getBoundingBox(compBox);
377 assemblyBox.grow(compBox);
378 }
379 }
380
381 else {
382 // Not parametrized
383 if (!m_cachedBoundingBox) {
385 // Loop over the children and define a box large enough for all of them
386 for (auto const child : m_children) {
387 BoundingBox compBox;
388 if (child) {
389 child->getBoundingBox(compBox);
390 m_cachedBoundingBox->grow(compBox);
391 }
392 }
393 }
394 // Use cached box
395 assemblyBox = *m_cachedBoundingBox;
396 }
397}
398
399//------------------------------------------------------------------------------------------------
407void CompAssembly::testIntersectionWithChildren(Track &testRay, std::deque<IComponent_const_sptr> &searchQueue) const {
408 int nchildren = this->nelements();
409 for (int i = 0; i < nchildren; ++i) {
410 std::shared_ptr<Geometry::IComponent> comp = this->getChild(i);
411 if (std::dynamic_pointer_cast<ICompAssembly>(comp)) {
412 searchQueue.emplace_back(comp);
413 }
414 // Check the physical object intersection
415 else if (auto const *physicalObject = dynamic_cast<IObjComponent *>(comp.get())) {
416 physicalObject->interceptSurface(testRay);
417 } else {
418 }
419 }
420}
421
422//------------------------------------------------------------------------------------------------
429void CompAssembly::printChildren(std::ostream &os) const {
430 for (int i = 0; i < nelements(); i++) {
431 std::shared_ptr<IComponent> it = (*this)[i];
432 os << "Component " << i << " : **********\n";
433 it->printSelf(os);
434 }
435}
436
443void CompAssembly::printTree(std::ostream &os) const {
444 for (int i = 0; i < nelements(); i++) {
445 std::shared_ptr<IComponent> it = (*this)[i];
446 const CompAssembly *test = dynamic_cast<CompAssembly *>(it.get());
447 os << "Element " << i << " from " << nelements() << " in the assembly : ";
448 if (test) {
449 os << test->getName() << '\n';
450 os << "Children :******** \n";
451 test->printTree(os);
452 } else
453 os << it->getName() << '\n';
454 }
455}
456
458 // Generic Assembly registration call.
459 return visitor.registerComponentAssembly(*this);
460}
461
472std::ostream &operator<<(std::ostream &os, const CompAssembly &ass) {
473 ass.printSelf(os);
474 os << "************************\n";
475 os << "Number of children :" << ass.nelements() << '\n';
476 ass.printChildren(os);
477 return os;
478}
479
480} // namespace Mantid::Geometry
A simple structure that defines an axis-aligned cuboid shaped bounding box for a geometrical object.
Definition BoundingBox.h:33
void grow(const BoundingBox &other)
Grow the bounding box so that it also encompasses the given box.
Class for Assembly of geometric components.
void printChildren(std::ostream &) const override
Print information about all children.
std::shared_ptr< IComponent > operator[](int i) const override
Get a pointer to the ith component in the assembly.
std::vector< IComponent * > m_children
the group of child components
void getChildren(std::vector< IComponent_const_sptr > &outVector, bool recursive) const override
Returns a vector of all children contained.
void printTree(std::ostream &) const override
Print information about all the elements in the tree to a stream Loops through all components in the ...
BoundingBox * m_cachedBoundingBox
A cached bounding box.
void getBoundingBox(BoundingBox &assemblyBox) const override
Get the bounding box for this component and store it in the given argument.
int add(IComponent *) override
Add a component to the assembly.
std::vector< IComponent * >::iterator comp_it
Iterator type.
int addCopy(IComponent *) override
AddCopy method.
std::shared_ptr< const IComponent > getComponentByName(const std::string &cname, int nlevels=0) const override
Returns a pointer to the first component of assembly encountered with the given name.
std::shared_ptr< IComponent > getChild(const int i) const override
Get a pointer to the ith component within the assembly. Easier to use than.
int remove(IComponent *)
Remove a component from the assembly.
void testIntersectionWithChildren(Track &testRay, std::deque< IComponent_const_sptr > &searchQueue) const override
Test the intersection of the ray with the children of the component assembly, for InstrumentRayTracer
CompAssembly()
Empty constructor.
int nelements() const override
Return the number of elements in the assembly.
~CompAssembly() override
Destructor.
CompAssembly & operator=(const CompAssembly &other)
virtual size_t registerContents(class ComponentVisitor &componentVisitor) const override
IComponent * clone() const override
Make a clone of the present component.
BoundingBox boundingBox(const size_t componentIndex, const BoundingBox *reference=nullptr, const bool excludeMonitors=false) const
Compute the bounding box for the component with componentIndex taking into account all sub components...
ComponentVisitor : Visitor for IComponents.
virtual size_t registerComponentAssembly(const ICompAssembly &assembly)=0
Component is a wrapper for a Component which can modify some of its parameters, e....
Definition Component.h:42
const ParameterMap * m_map
A pointer to const ParameterMap containing the parameters.
Definition Component.h:318
size_t index() const
Helper for legacy access mode. Returns the index of the component.
void printSelf(std::ostream &) const override
Prints a text representation of itself.
std::string getName() const override
Get the IComponent name.
const Component * m_base
The base component - this is the unmodified component (without the parameters).
Definition Component.h:316
Class for Assembly of geometric components.
virtual int add(IComponent *)=0
Add a component to the assembly.
base class for Geometric IComponent
Definition IComponent.h:53
virtual IComponent * clone() const =0
Return a clone to the current object.
virtual void setParent(IComponent *)=0
Assign a parent IComponent. Previous parent link is lost.
virtual void setName(const std::string &)=0
Set the IComponent name.
virtual std::string getName() const =0
Get the IComponent name.
Object Component class, this class brings together the physical attributes of the component to the po...
static std::shared_ptr< IComponent > create(const std::shared_ptr< const IComponent > &base, const ParameterMap *map)
Create a parameterized component from the given base component and ParameterMap.
Parameter map iterator typedef.
const Geometry::ComponentInfo & componentInfo() const
Only for use by ExperimentInfo. Returns a reference to the ComponentInfo.
Defines a track as a start point and a direction.
Definition Track.h:165
This functor is used as the deleter object of a shared_ptr to effectively erase ownership Raw pointer...
Definition IComponent.h:171
std::shared_ptr< IComponent > IComponent_sptr
Typedef of a shared pointer to a IComponent.
Definition IComponent.h:163
MANTID_GEOMETRY_DLL std::ostream & operator<<(std::ostream &stream, const PointGroup &self)
Returns a streamed representation of the PointGroup object.