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
57CompAssembly::CompAssembly(const CompAssembly &assem) : ICompAssembly(assem), Component(assem) { *this = assem; }
58
60 m_children = assem.m_children;
62
63 // Need to do a deep copy
64 comp_it it;
65 for (it = m_children.begin(); it != m_children.end(); ++it) {
66 *it = (*it)->clone();
67 // Move copied component object's parent from old to new CompAssembly
68 (*it)->setParent(this);
69 }
70
71 return *this;
72}
73
79 // Iterate over pointers in m_children, deleting them
80 for (auto &child : m_children) {
81 delete child;
82 }
83 m_children.clear();
84}
85
90IComponent *CompAssembly::clone() const { return new CompAssembly(*this); }
91
99 if (m_map)
100 throw std::runtime_error("CompAssembly::add() called for a parametrized CompAssembly.");
101
102 if (comp) {
103 comp->setParent(this);
104 m_children.emplace_back(comp);
105 }
106 return static_cast<int>(m_children.size());
107}
108
118 if (m_map)
119 throw std::runtime_error("CompAssembly::addCopy() called for a parametrized CompAssembly.");
120
121 if (comp) {
122 IComponent *newcomp = comp->clone();
123 newcomp->setParent(this);
124 m_children.emplace_back(newcomp);
125 }
126 return static_cast<int>(m_children.size());
127}
128
138int CompAssembly::addCopy(IComponent *comp, const std::string &n) {
139 if (m_map)
140 throw std::runtime_error("CompAssembly::addCopy() called for a parametrized CompAssembly.");
141
142 if (comp) {
143 IComponent *newcomp = comp->clone();
144 newcomp->setParent(this);
145 newcomp->setName(n);
146 m_children.emplace_back(newcomp);
147 }
148 return static_cast<int>(m_children.size());
149}
150
157 if (m_map)
158 throw std::runtime_error("CompAssembly::remove() called for a parameterized CompAssembly.");
159
160 // Look for the passed in component in the list of children
161 auto it = std::find(m_children.begin(), m_children.end(), comp);
162 if (it != m_children.end()) {
163 // If it's found, remove it from the list and then delete it
164 m_children.erase(it);
165 delete comp;
166 } else {
167 throw std::runtime_error("Component " + comp->getName() + " is not a child of this assembly.");
168 }
169
170 return static_cast<int>(m_children.size());
171}
172
177 if (m_map) {
178 auto compAss = dynamic_cast<const CompAssembly *>(m_base);
179 if (!compAss) {
180 throw std::logic_error("Failed to cast base component to CompAssembly");
181 }
182 return compAss->nelements();
183 } else
184 return static_cast<int>(m_children.size());
185}
186
197std::shared_ptr<IComponent> CompAssembly::getChild(const int i) const {
198 if (m_map) {
199 // Get the child of the base (unparametrized) assembly
200 auto child_base = dynamic_cast<const CompAssembly *>(m_base);
201 if (!child_base) {
202 throw std::logic_error("Failed to cast base component to CompAssembly");
203 }
204 // And build up a parametrized version of it using the factory, and return
205 // that
206 return ParComponentFactory::create(child_base->getChild(i), m_map);
207 } else {
208 if (i < 0 || i > static_cast<int>(m_children.size() - 1)) {
209 throw std::runtime_error("CompAssembly::getChild() range not valid");
210 }
211 return std::shared_ptr<IComponent>(m_children[i], NoDeleting());
212 }
213}
214
220std::shared_ptr<IComponent> CompAssembly::operator[](int i) const { return this->getChild(i); }
221
222//------------------------------------------------------------------------------------------------
229void CompAssembly::getChildren(std::vector<IComponent_const_sptr> &outVector, bool recursive) const {
230 for (int i = 0; i < this->nelements(); i++) {
231 std::shared_ptr<IComponent> comp = this->getChild(i);
232 if (comp) {
233 outVector.emplace_back(comp);
234 // Look deeper, on option.
235 if (recursive) {
236 std::shared_ptr<ICompAssembly> assemb = std::dynamic_pointer_cast<ICompAssembly>(comp);
237 if (assemb)
238 assemb->getChildren(outVector, recursive);
239 }
240 }
241 }
242}
243
262std::shared_ptr<const IComponent> CompAssembly::getComponentByName(const std::string &cname, int nlevels) const {
263 std::shared_ptr<const ICompAssembly> thisNode = std::shared_ptr<const ICompAssembly>(this, NoDeleting());
264
265 // If name has '/' in it, it is taken as part of a path name of the component.
266 // Steps may be skipped at a '/' from the path name,
267 // but if what follows the skip is not unique within what precedes it, only
268 // the first found is returned.
269 size_t cut = cname.find('/');
270 if (cut < cname.length()) {
271 auto otherNode = this->getComponentByName(cname.substr(0, cut), nlevels);
272 if (otherNode) {
273 std::shared_ptr<const ICompAssembly> asmb = std::dynamic_pointer_cast<const ICompAssembly>(otherNode);
274 return asmb->getComponentByName(cname.substr(cut + 1, std::string::npos), nlevels);
275 } else {
276 return std::shared_ptr<const IComponent>(); // Search failed
277 }
278 }
279
280 // Check the instrument name first
281 if (this->getName() == cname) {
282 return std::dynamic_pointer_cast<const ICompAssembly>(thisNode);
283 }
284 // Otherwise Search the instrument tree using a breadth-first search algorithm
285 // since most likely candidates
286 // are higher-level components
287 // I found some useful info here
288 // http://www.cs.bu.edu/teaching/c/tree/breadth-first/
289 std::deque<std::shared_ptr<const ICompAssembly>> nodeQueue{thisNode};
290 const bool limitSearch(nlevels > 0);
291 while (!nodeQueue.empty()) {
292 // get the next node in the queue
293 std::shared_ptr<const ICompAssembly> node = nodeQueue.front();
294 nodeQueue.pop_front();
295
296 // determine the depth
297 int depth(1);
298 if (limitSearch) {
299 auto parent = node->getParent();
300 while (parent && (this->getName() != parent->getName())) {
301 parent = parent->getParent();
302 depth++;
303 }
304 }
305
306 auto rectDet = std::dynamic_pointer_cast<const RectangularDetector>(node);
307 auto structDet = std::dynamic_pointer_cast<const StructuredDetector>(node);
308
309 if (bool(rectDet) && (node != thisNode)) {
310 // for rectangular detectors search the depth rather than siblings
311 // as there
312 // is a specific naming convention to speed things along
313 auto child = rectDet->getComponentByName(cname, nlevels);
314 if (child)
315 return child;
316 } else if (bool(structDet) && (node != thisNode)) {
317 auto child = rectDet->getComponentByName(cname, nlevels);
318 if (child != nullptr)
319 return child;
320 } else {
321 // loop over the children
322 int nchildren = node->nelements();
323 for (int i = 0; i < nchildren; ++i) {
324 std::shared_ptr<const IComponent> comp = (*node)[i];
325 if (comp->getName() == cname) {
326 return comp;
327 } else {
328 // only add things if max-recursion depth hasn't been reached
329 if ((!limitSearch) || (depth + 1 < nlevels)) {
330 // don't bother adding things to the queue that aren't
331 // assemblies
332 std::shared_ptr<const ICompAssembly> compAssembly = std::dynamic_pointer_cast<const ICompAssembly>(comp);
333 if (bool(compAssembly)) {
334 nodeQueue.emplace_back(compAssembly);
335 }
336 }
337 }
338 }
339 }
340 } // while-end
341
342 // If we have reached here then the search failed
343 return std::shared_ptr<const IComponent>();
344}
345
346//------------------------------------------------------------------------------------------------
353 if (m_map) {
354
355 if (hasComponentInfo()) {
356 assemblyBox = m_map->componentInfo().boundingBox(index(), &assemblyBox);
357 return;
358 }
359
360 // Loop over the children and define a box large enough for all of them
361 assemblyBox = BoundingBox(); // this makes assembly box always axis alighned
362 int nchildren = nelements();
363 for (int i = 0; i < nchildren; ++i) {
364 IComponent_sptr comp = this->operator[](i);
365 BoundingBox compBox;
366 comp->getBoundingBox(compBox);
367 assemblyBox.grow(compBox);
368 }
369 }
370
371 else {
372 // Not parametrized
373 if (!m_cachedBoundingBox) {
375 // Loop over the children and define a box large enough for all of them
376 for (auto child : m_children) {
377 BoundingBox compBox;
378 if (child) {
379 child->getBoundingBox(compBox);
380 m_cachedBoundingBox->grow(compBox);
381 }
382 }
383 }
384 // Use cached box
385 assemblyBox = *m_cachedBoundingBox;
386 }
387}
388
389//------------------------------------------------------------------------------------------------
397void CompAssembly::testIntersectionWithChildren(Track &testRay, std::deque<IComponent_const_sptr> &searchQueue) const {
398 int nchildren = this->nelements();
399 for (int i = 0; i < nchildren; ++i) {
400 std::shared_ptr<Geometry::IComponent> comp = this->getChild(i);
401 if (std::dynamic_pointer_cast<ICompAssembly>(comp)) {
402 searchQueue.emplace_back(comp);
403 }
404 // Check the physical object intersection
405 else if (auto *physicalObject = dynamic_cast<IObjComponent *>(comp.get())) {
406 physicalObject->interceptSurface(testRay);
407 } else {
408 }
409 }
410}
411
412//------------------------------------------------------------------------------------------------
419void CompAssembly::printChildren(std::ostream &os) const {
420 for (int i = 0; i < nelements(); i++) {
421 std::shared_ptr<IComponent> it = (*this)[i];
422 os << "Component " << i << " : **********\n";
423 it->printSelf(os);
424 }
425}
426
433void CompAssembly::printTree(std::ostream &os) const {
434 for (int i = 0; i < nelements(); i++) {
435 std::shared_ptr<IComponent> it = (*this)[i];
436 const CompAssembly *test = dynamic_cast<CompAssembly *>(it.get());
437 os << "Element " << i << " from " << nelements() << " in the assembly : ";
438 if (test) {
439 os << test->getName() << '\n';
440 os << "Children :******** \n";
441 test->printTree(os);
442 } else
443 os << it->getName() << '\n';
444 }
445}
446
453 if (!m_map || hasComponentInfo())
454 return Component::getPos();
455 else {
456 V3D pos;
457 if (!m_map->getCachedLocation(m_base, pos)) {
458 pos = Component::getPos();
460 }
461 return pos;
462 }
463}
464
471 if (!m_map || hasComponentInfo())
472 return Component::getRotation();
473 else {
474 Quat rot;
475 if (!m_map->getCachedRotation(m_base, rot)) {
478 }
479 return rot;
480 }
481}
482
484 // Generic Assembly registration call.
485 return visitor.registerComponentAssembly(*this);
486}
487
498std::ostream &operator<<(std::ostream &os, const CompAssembly &ass) {
499 ass.printSelf(os);
500 os << "************************\n";
501 os << "Number of children :" << ass.nelements() << '\n';
502 ass.printChildren(os);
503 return os;
504}
505
506} // namespace Mantid::Geometry
A simple structure that defines an axis-aligned cuboid shaped bounding box for a geometrical object.
Definition: BoundingBox.h:34
void grow(const BoundingBox &other)
Grow the bounding box so that it also encompasses the given box.
Class for Assembly of geometric components.
Definition: CompAssembly.h:31
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
Definition: CompAssembly.h:98
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.
Definition: CompAssembly.h:101
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.
Definition: CompAssembly.h:33
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.
Kernel::V3D getPos() const override
Gets the absolute position of the Parametrized CompAssembly This attempts to read the cached position...
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
Kernel::Quat getRotation() const override
Gets the absolute position of the Parametrized CompAssembly This attempts to read the cached position...
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:41
const ParameterMap * m_map
A pointer to const ParameterMap containing the parameters.
Definition: Component.h:307
size_t index() const
Helper for legacy access mode. Returns the index of the component.
Definition: Component.cpp:297
void printSelf(std::ostream &) const override
Prints a text representation of itself.
Definition: Component.cpp:509
Kernel::V3D getPos() const override
Get the position of the IComponent. Tree structure is traverse through the.
Definition: Component.cpp:325
std::string getName() const override
Get the IComponent name.
Definition: Component.cpp:173
const Component * m_base
The base component - this is the unmodified component (without the parameters).
Definition: Component.h:305
Kernel::Quat getRotation() const override
Get the absolute orientation of the IComponent.
Definition: Component.cpp:387
Class for Assembly of geometric components.
Definition: ICompAssembly.h:30
virtual int add(IComponent *)=0
Add a component to the assembly.
base class for Geometric IComponent
Definition: IComponent.h:51
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...
Definition: IObjComponent.h:37
Void deleter for shared pointers.
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.
bool getCachedRotation(const IComponent *comp, Kernel::Quat &rotation) const
Attempts to retrieve a rotation from the rotation cache.
bool getCachedLocation(const IComponent *comp, Kernel::V3D &location) const
Attempts to retrieve a location from the location cache.
void setCachedLocation(const IComponent *comp, const Kernel::V3D &location) const
Sets a cached location on the location cache.
void setCachedRotation(const IComponent *comp, const Kernel::Quat &rotation) const
Sets a cached rotation on the rotation cache.
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
Class for quaternions.
Definition: Quat.h:39
Class for 3D vectors.
Definition: V3D.h:34
std::shared_ptr< IComponent > IComponent_sptr
Typedef of a shared pointer to a IComponent.
Definition: IComponent.h:159
MANTID_GEOMETRY_DLL std::ostream & operator<<(std::ostream &stream, const PointGroup &self)
Returns a streamed representation of the PointGroup object.
Definition: PointGroup.cpp:312