Mantid
Loading...
Searching...
No Matches
ObjCompAssembly.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 +
14#include "MantidKernel/Logger.h"
15#include "MantidKernel/Matrix.h"
16#include <algorithm>
17#include <ostream>
18#include <stdexcept>
19#include <utility>
20
21namespace {
22Mantid::Kernel::Logger g_log("ObjCompAssembly");
23}
24
25namespace Mantid::Geometry {
27using Kernel::Quat;
28using Kernel::V3D;
29
35
45ObjCompAssembly::ObjCompAssembly(const std::string &n, IComponent *reference) : ObjComponent(n, reference) {
46 if (reference) {
47 auto *test = dynamic_cast<ICompAssembly *>(reference);
48 if (test)
49 test->add(this);
50 }
51}
52
57 : ICompAssembly(assem), IObjComponent(assem), ObjComponent(assem) {
58 *this = assem;
59}
60
62 m_group = assem.m_group;
63
64 // Need to do a deep copy
65 comp_it it;
66 for (it = m_group.begin(); it != m_group.end(); ++it) {
67 auto *c = dynamic_cast<ObjComponent *>((*it)->clone());
68 if (!c) {
70 "ObjCompAssembly cannot contain components of non-ObjComponent type");
71 }
72 *it = c;
73 // Move copied component object's parent from old to new ObjCompAssembly
74 (*it)->setParent(this);
75 }
76
77 return *this;
78}
79
83 // Iterate over pointers in group, deleting them
84 // std::vector<IComponent*>::iterator it;
85 for (auto &component : m_group) {
86 delete component;
87 }
88 m_group.clear();
89}
90
95IComponent *ObjCompAssembly::clone() const { return new ObjCompAssembly(*this); }
96
104 if (m_map)
105 throw std::runtime_error("ObjCompAssembly::add() called on a Parametrized object.");
106
107 if (comp) {
108 auto *c = dynamic_cast<ObjComponent *>(comp);
109 if (!c) {
111 "ObjCompAssembly cannot contain components of non-ObjComponent type");
112 }
113 comp->setParent(this);
114 m_group.emplace_back(c);
115 }
116 return static_cast<int>(m_group.size());
117}
118
128 if (m_map)
129 throw std::runtime_error("ObjCompAssembly::addCopy() called on a Parametrized object.");
130
131 if (comp) {
132 IComponent *newcomp = comp->clone();
133 auto *c = dynamic_cast<ObjComponent *>(newcomp);
134 if (!c) {
136 "ObjCompAssembly cannot contain components of non-ObjComponent type");
137 }
138 newcomp->setParent(this);
139 m_group.emplace_back(c);
140 }
141 return static_cast<int>(m_group.size());
142}
143
153int ObjCompAssembly::addCopy(IComponent *comp, const std::string &n) {
154 if (m_map)
155 throw std::runtime_error("ObjCompAssembly::addCopy() called on a Parametrized object.");
156
157 if (comp) {
158 IComponent *newcomp = comp->clone();
159 auto *c = dynamic_cast<ObjComponent *>(newcomp);
160 if (!c) {
162 "ObjCompAssembly cannot contain components of non-ObjComponent type");
163 }
164 newcomp->setParent(this);
165 newcomp->setName(n);
166 m_group.emplace_back(c);
167 }
168 return static_cast<int>(m_group.size());
169}
170
175 if (m_map) {
176 auto objCompAss = dynamic_cast<const ObjCompAssembly *>(m_base);
177 if (!objCompAss) {
178 throw std::logic_error("Failed to cast base component to ObjCompAssembly");
179 }
180 return objCompAss->nelements();
181 } else
182 return static_cast<int>(m_group.size());
183}
184
194std::shared_ptr<IComponent> ObjCompAssembly::operator[](int i) const {
195 if (i < 0 || i > nelements() - 1) {
196 throw std::runtime_error("ObjCompAssembly::operator[] range not valid");
197 }
198
199 if (m_map) {
200 auto child_base = dynamic_cast<const ObjCompAssembly *>(m_base);
201 if (!child_base) {
202 throw std::logic_error("Failed to cast base component to ObjCompAssembly");
203 }
204 return ParComponentFactory::create(child_base->operator[](i), m_map);
205 } else {
206 // Unparamterized - return the normal one
207 return std::shared_ptr<IComponent>(m_group[i], NoDeleting());
208 }
209}
210
211//------------------------------------------------------------------------------------------------
218void ObjCompAssembly::getChildren(std::vector<IComponent_const_sptr> &outVector, bool recursive) const {
219 for (int i = 0; i < this->nelements(); i++) {
220 std::shared_ptr<IComponent> comp = this->getChild(i);
221 if (comp) {
222 outVector.emplace_back(comp);
223 // Look deeper, on option.
224 if (recursive) {
225 std::shared_ptr<ICompAssembly> assemb = std::dynamic_pointer_cast<ICompAssembly>(comp);
226 if (assemb)
227 assemb->getChildren(outVector, recursive);
228 }
229 }
230 }
231}
232
240std::shared_ptr<const IComponent> ObjCompAssembly::getComponentByName(const std::string &cname, int nlevels) const {
241 int nchildren = this->nelements();
242 if (nlevels > 1)
243 g_log.debug() << "only implemented for children\n";
244 for (int i = 0; i < nchildren; ++i) {
245 std::shared_ptr<Geometry::IComponent> comp = this->getChild(i);
246 if (comp->getName() == cname)
247 return comp;
248 }
249 return std::shared_ptr<const IComponent>();
250}
251
258void ObjCompAssembly::printChildren(std::ostream &os) const {
259 // std::vector<IComponent*>::const_iterator it;
260 int i = 0;
261 for (i = 0; i < this->nelements(); i++) {
262 os << "Component " << i << " : **********\n";
263 this->operator[](i)->printSelf(os);
264 }
265}
266
273void ObjCompAssembly::printTree(std::ostream &os) const {
274 // std::vector<IComponent*>::const_iterator it;
275 int i = 0;
276 for (i = 0; i < this->nelements(); i++) {
277 std::shared_ptr<const ObjCompAssembly> test = std::dynamic_pointer_cast<const ObjCompAssembly>(this->operator[](i));
278 os << "Element " << i << " in the assembly : ";
279 if (test) {
280 os << test->getName() << '\n';
281 os << "Children :******** \n";
282 test->printTree(os);
283 } else
284 os << this->operator[](i)->getName() << '\n';
285 }
286}
287
294 if (m_map && !hasComponentInfo()) {
295 V3D pos;
296 if (!m_map->getCachedLocation(m_base, pos)) {
297 pos = Component::getPos();
299 }
300 return pos;
301 } else
302 return Component::getPos();
303}
304
311 if (m_map && !hasComponentInfo()) {
312 Quat rot;
313 if (!m_map->getCachedRotation(m_base, rot)) {
316 }
317 return rot;
318 } else
319 return Component::getRotation();
320}
321
322//------------------------------------------------------------------------------------------------
331 std::deque<IComponent_const_sptr> &searchQueue) const {
332 int nchildren = this->nelements();
333 for (int i = 0; i < nchildren; ++i) {
334 std::shared_ptr<Geometry::IComponent> comp = this->getChild(i);
335 if (std::dynamic_pointer_cast<ICompAssembly>(comp)) {
336 searchQueue.emplace_back(comp);
337 }
338 // Check the physical object intersection
339 else if (const auto *physicalObject = dynamic_cast<IObjComponent *>(comp.get())) {
340 physicalObject->interceptSurface(testRay);
341 } else {
342 }
343 }
344}
345
347 // Generic Assembly registration call.
348 return visitor.registerObjComponentAssembly(*this);
349}
350
358std::shared_ptr<IObject> ObjCompAssembly::createOutline() {
359 if (m_group.empty()) {
360 throw Kernel::Exception::InstrumentDefinitionError("Empty ObjCompAssembly");
361 }
362
363 if (nelements() < 2) {
364 g_log.warning("Creating outline with fewer than 2 elements. The outline "
365 "displayed may be inaccurate.");
366 }
367
368 // Get information about the shape and size of a detector
369 std::string detectorType;
371 std::vector<Kernel::V3D> vectors;
372 double radius, height, innerRadius;
373 std::shared_ptr<const IObject> obj = m_group.front()->shape();
374 if (!obj) {
375 throw Kernel::Exception::InstrumentDefinitionError("Found ObjComponent without shape");
376 }
377 obj->GetObjectGeom(otype, vectors, innerRadius, radius, height);
379 detectorType = "box";
380 } else if (otype == detail::ShapeInfo::GeometryShape::CYLINDER) {
381 detectorType = "cylinder";
382 } else {
383 throw std::runtime_error("IDF \"outline\" option is only allowed for assemblies containing "
384 "components of types \"box\" or \"cylinder\".");
385 }
386
387 // Calculate the dimensions of the outline object
388
389 // find the 'moments of inertia' of the assembly
390 double Ixx = 0, Iyy = 0, Izz = 0, Ixy = 0, Ixz = 0, Iyz = 0;
391 V3D Cmass; // 'center of mass' of the assembly
392 for (const_comp_it it = m_group.begin(); it != m_group.end(); ++it) {
393 V3D p = (**it).getRelativePos();
394 Cmass += p;
395 }
396 Cmass /= nelements();
397 for (const_comp_it it = m_group.begin(); it != m_group.end(); ++it) {
398 V3D p = (**it).getRelativePos();
399 double x = p.X() - Cmass.X(), x2 = x * x;
400 double y = p.Y() - Cmass.Y(), y2 = y * y;
401 double z = p.Z() - Cmass.Z(), z2 = z * z;
402 Ixx += y2 + z2;
403 Iyy += x2 + z2;
404 Izz += y2 + x2;
405 Ixy -= x * y;
406 Ixz -= x * z;
407 Iyz -= y * z;
408 }
409 // principal axes of the outline shape
410 // vz defines the line through all pixel centres
411 V3D vx, vy, vz;
412
413 if (Ixx == 0) // pixels along x axis
414 {
415 vx = V3D(0, 1, 0);
416 vy = V3D(0, 0, 1);
417 vz = V3D(1, 0, 0);
418 } else if (Iyy == 0) // pixels along y axis
419 {
420 vx = V3D(0, 0, 1);
421 vy = V3D(1, 0, 0);
422 vz = V3D(0, 1, 0);
423 } else if (Izz == 0) // pixels along z axis
424 {
425 vx = V3D(1, 0, 0);
426 vy = V3D(0, 1, 0);
427 vz = V3D(0, 0, 1);
428 } else {
429 // Either the detectors are not perfectrly aligned or
430 // vz is parallel to neither of the 3 axis x,y,z
431 // This code is unfinished
432 DblMatrix II(3, 3), Vec(3, 3), D(3, 3);
433 II[0][0] = Ixx;
434 II[0][1] = Ixy;
435 II[0][2] = Ixz;
436 II[1][0] = Ixy;
437 II[1][1] = Iyy;
438 II[1][2] = Iyz;
439 II[2][0] = Ixz;
440 II[2][1] = Iyz;
441 II[2][2] = Izz;
442 g_log.debug() << "Inertia matrix: " << II << II.determinant() << '\n';
443 II.Diagonalise(Vec, D);
444 g_log.debug() << "Vectors: " << Vec << '\n';
445 g_log.debug() << "Moments: " << D << '\n';
446 vx = V3D(Vec[0][0], Vec[1][0], Vec[2][0]);
447 vy = V3D(Vec[0][1], Vec[1][1], Vec[2][1]);
448 vz = V3D(Vec[0][2], Vec[1][2], Vec[2][2]);
449 }
450
451 // find assembly sizes along the principal axes
452 double hx, hy, hz; // sizes along x,y, and z axis
453
454 // maximum displacements from the mass centre along axis vx,vy, and vz
455 // in positive (p) and negative (n) directions.
456 // positive displacements are positive numbers and negative ones are negative
457 double hxn = 0, hyn = 0, hzn = 0;
458 double hxp = 0, hyp = 0, hzp = 0;
459 for (const_comp_it it = m_group.begin(); it != m_group.end(); ++it) {
460 // displacement vector of a detector
461 V3D p = (**it).getRelativePos() - Cmass;
462 // its projection on the vx axis
463 double h = p.scalar_prod(vx);
464 if (h > hxp)
465 hxp = h;
466 if (h < hxn)
467 hxn = h;
468 // its projection on the vy axis
469 h = p.scalar_prod(vy);
470 if (h > hyp)
471 hyp = h;
472 if (h < hyn)
473 hyn = h;
474 // its projection on the vz axis
475 h = p.scalar_prod(vz);
476 if (h > hzp)
477 hzp = h;
478 if (h < hzn)
479 hzn = h;
480 }
481
482 // calc the assembly sizes
483 hx = hxp - hxn;
484 hy = hyp - hyn;
485 hz = hzp - hzn;
486 // hx and hy must be practically zero
487 if (hx > 1e-3 || hy > 1e-3) // arbitrary numbers
488 {
489 throw Kernel::Exception::InstrumentDefinitionError("Detectors of a ObjCompAssembly do not lie on a staraight line");
490 }
491
492 // determine the order of the detectors to make sure that the texture
493 // coordinates are correct
494 bool firstAtBottom; // first detector is at the bottom of the outline shape
495 // the bottom end is the one with the negative displacement from the centre
496 firstAtBottom = ((**m_group.begin()).getRelativePos() - Cmass).scalar_prod(vz) < 0;
497
498 // form the input string for the ShapeFactory
499 std::ostringstream obj_str;
500 if (detectorType == "box") {
501 hx = hy = 0;
502 height = 0;
503 V3D p0 = vectors[0];
504 for (size_t i = 1; i < vectors.size(); ++i) {
505 V3D p = vectors[i] - p0;
506 double h = fabs(p.scalar_prod(vx));
507 if (h > hx)
508 hx = h;
509 h = fabs(p.scalar_prod(vy));
510 if (h > hy)
511 hy = h;
512 height = fabs(p.scalar_prod(vz));
513 if (h > height)
514 height = h;
515 }
516
517 vx *= hx / 2;
518 vy *= hy / 2;
519 vz *= hzp + height / 2;
520
521 if (!firstAtBottom) {
522 vz = vz * (-1);
523 }
524
525 // define the outline shape as cuboid
526 V3D p_lfb = Cmass - vx - vy - vz;
527 V3D p_lft = Cmass - vx - vy + vz;
528 V3D p_lbb = Cmass - vx + vy - vz;
529 V3D p_rfb = Cmass + vx - vy - vz;
530 obj_str << "<cuboid id=\"shape\">";
531 obj_str << "<left-front-bottom-point ";
532 obj_str << "x=\"" << p_lfb.X();
533 obj_str << "\" y=\"" << p_lfb.Y();
534 obj_str << "\" z=\"" << p_lfb.Z();
535 obj_str << "\" />";
536 obj_str << "<left-front-top-point ";
537 obj_str << "x=\"" << p_lft.X();
538 obj_str << "\" y=\"" << p_lft.Y();
539 obj_str << "\" z=\"" << p_lft.Z();
540 obj_str << "\" />";
541 obj_str << "<left-back-bottom-point ";
542 obj_str << "x=\"" << p_lbb.X();
543 obj_str << "\" y=\"" << p_lbb.Y();
544 obj_str << "\" z=\"" << p_lbb.Z();
545 obj_str << "\" />";
546 obj_str << "<right-front-bottom-point ";
547 obj_str << "x=\"" << p_rfb.X();
548 obj_str << "\" y=\"" << p_rfb.Y();
549 obj_str << "\" z=\"" << p_rfb.Z();
550 obj_str << "\" />";
551 obj_str << "</cuboid>";
552
553 } else if (detectorType == "cylinder") {
554 // the outline is one detector height short
555 hz += height;
556 // shift Cmass to the end of the cylinder where the first detector is
557 if (firstAtBottom) {
558 Cmass += vz * hzn;
559 } else {
560 hzp += height;
561 Cmass += vz * hzp;
562 // inverse the vz axis
563 vz = vz * (-1);
564 }
565 obj_str << "<cylinder id=\"stick\">";
566 obj_str << "<centre-of-bottom-base ";
567 obj_str << "x=\"" << Cmass.X();
568 obj_str << "\" y=\"" << Cmass.Y();
569 obj_str << "\" z=\"" << Cmass.Z();
570 obj_str << "\" />";
571 obj_str << "<axis x=\"" << vz.X() << "\" y=\"" << vz.Y() << "\" z=\"" << vz.Z() << "\" /> ";
572 obj_str << "<radius val=\"" << radius << "\" />";
573 obj_str << "<height val=\"" << hz << "\" />";
574 obj_str << "</cylinder>";
575 }
576
577 if (!obj_str.str().empty()) {
578 std::shared_ptr<IObject> s = ShapeFactory().createShape(obj_str.str());
579 setOutline(s);
580 return s;
581 }
582 return std::shared_ptr<IObject>();
583}
584
589void ObjCompAssembly::setOutline(std::shared_ptr<const IObject> obj) { m_shape = std::move(obj); }
590
600std::ostream &operator<<(std::ostream &os, const ObjCompAssembly &ass) {
601 ass.printSelf(os);
602 os << "************************\n";
603 os << "Number of children :" << ass.nelements() << '\n';
604 ass.printChildren(os);
605 return os;
606}
607
608} // namespace Mantid::Geometry
double height
Definition GetAllEi.cpp:155
#define fabs(x)
Definition Matrix.cpp:22
double obj
the value of the quadratic function
ComponentVisitor : Visitor for IComponents.
virtual size_t registerObjComponentAssembly(const ObjCompAssembly &obj)=0
const ParameterMap * m_map
A pointer to const ParameterMap containing the parameters.
Definition Component.h:316
Kernel::V3D getPos() const override
Get the position of the IComponent. Tree structure is traverse through the.
const Component * m_base
The base component - this is the unmodified component (without the parameters).
Definition Component.h:314
Kernel::Quat getRotation() const override
Get the absolute orientation of the IComponent.
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 void printSelf(std::ostream &) const =0
Prints a text representation of itself.
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 Kernel::V3D getRelativePos() const =0
Get the position relative to the parent IComponent (absolute if no parent)
virtual void setName(const std::string &)=0
Set the IComponent name.
Object Component class, this class brings together the physical attributes of the component to the po...
Class for Assembly of geometric components.
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.
int nelements() const override
Return the number of elements in the assembly.
size_t registerContents(class Mantid::Geometry::ComponentVisitor &visitor) const override
void printChildren(std::ostream &) const override
Print information about all children.
IComponent * clone() const override
Make a clone of the present component.
void getChildren(std::vector< IComponent_const_sptr > &outVector, bool recursive) const override
Get all children.
void setOutline(std::shared_ptr< const IObject > obj)
Sets the outline shape for this assembly.
std::vector< ObjComponent * >::iterator comp_it
Iterator type.
std::vector< ObjComponent * >::const_iterator const_comp_it
Const iterator type.
void testIntersectionWithChildren(Track &, std::deque< IComponent_const_sptr > &) const override
Test the intersection of the ray with the children of the component assembly
std::shared_ptr< IComponent > getChild(const int i) const override
Get a pointer to the ith component within the assembly. Easier to use than.
void printTree(std::ostream &) const override
Print information about all the elements in the tree to a stream Loops through all components in the ...
ObjCompAssembly(const IComponent *base, const ParameterMap *map)
Empty constructor.
int addCopy(IComponent *) override
Add a copy (clone) of a component.
Kernel::Quat getRotation() const override
Gets the absolute position of the Parametrized ObjCompAssembly This attempts to read the cached posit...
~ObjCompAssembly() override
Destructor.
std::vector< ObjComponent * > m_group
the group of child components
ObjCompAssembly & operator=(const ObjCompAssembly &)
int add(IComponent *) override
Add a component to the assembly.
Kernel::V3D getPos() const override
Gets the absolute position of the Parametrized ObjCompAssembly This attempts to read the cached posit...
std::shared_ptr< IObject > createOutline()
Set the outline of the assembly.
std::shared_ptr< IComponent > operator[](int i) const override
Get a pointer to the ith component in the assembly.
Object Component class, this class brings together the physical attributes of the component to the po...
std::shared_ptr< const IObject > m_shape
The physical geometry representation.
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.
Class originally intended to be used with the DataHandling 'LoadInstrument' algorithm.
std::shared_ptr< CSGObject > createShape(Poco::XML::Element *pElem)
Creates a geometric object from a DOM-element-node pointing to an element whose child nodes contain t...
Defines a track as a start point and a direction.
Definition Track.h:165
Exception for errors associated with the instrument definition.
Definition Exception.h:220
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition Logger.h:51
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
Class for quaternions.
Definition Quat.h:39
Class for 3D vectors.
Definition V3D.h:34
constexpr double scalar_prod(const V3D &v) const noexcept
Calculates the cross product.
Definition V3D.h:280
constexpr double X() const noexcept
Get x.
Definition V3D.h:238
constexpr double Y() const noexcept
Get y.
Definition V3D.h:239
constexpr double Z() const noexcept
Get z.
Definition V3D.h:240
This functor is used as the deleter object of a shared_ptr to effectively erase ownership Raw pointer...
Definition IComponent.h:173
Kernel::Logger g_log("DetermineSpinStateOrder")
Mantid::Kernel::Logger g_log("Goniometer")
MANTID_GEOMETRY_DLL std::ostream & operator<<(std::ostream &stream, const PointGroup &self)
Returns a streamed representation of the PointGroup object.
Mantid::Kernel::Matrix< double > DblMatrix
Definition Matrix.h:206