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
32public:
34 void operator()(void *p) { (void)p; }
35};
36
42
52ObjCompAssembly::ObjCompAssembly(const std::string &n, IComponent *reference) : ObjComponent(n, reference) {
53 if (reference) {
54 auto *test = dynamic_cast<ICompAssembly *>(reference);
55 if (test)
56 test->add(this);
57 }
58}
59
64 : ICompAssembly(assem), IObjComponent(assem), ObjComponent(assem) {
65 *this = assem;
66}
67
69 m_group = assem.m_group;
70
71 // Need to do a deep copy
72 comp_it it;
73 for (it = m_group.begin(); it != m_group.end(); ++it) {
74 auto *c = dynamic_cast<ObjComponent *>((*it)->clone());
75 if (!c) {
77 "ObjCompAssembly cannot contain components of non-ObjComponent type");
78 }
79 *it = c;
80 // Move copied component object's parent from old to new ObjCompAssembly
81 (*it)->setParent(this);
82 }
83
84 return *this;
85}
86
90 // Iterate over pointers in group, deleting them
91 // std::vector<IComponent*>::iterator it;
92 for (auto &component : m_group) {
93 delete component;
94 }
95 m_group.clear();
96}
97
102IComponent *ObjCompAssembly::clone() const { return new ObjCompAssembly(*this); }
103
111 if (m_map)
112 throw std::runtime_error("ObjCompAssembly::add() called on a Parametrized object.");
113
114 if (comp) {
115 auto *c = dynamic_cast<ObjComponent *>(comp);
116 if (!c) {
118 "ObjCompAssembly cannot contain components of non-ObjComponent type");
119 }
120 comp->setParent(this);
121 m_group.emplace_back(c);
122 }
123 return static_cast<int>(m_group.size());
124}
125
135 if (m_map)
136 throw std::runtime_error("ObjCompAssembly::addCopy() called on a Parametrized object.");
137
138 if (comp) {
139 IComponent *newcomp = comp->clone();
140 auto *c = dynamic_cast<ObjComponent *>(newcomp);
141 if (!c) {
143 "ObjCompAssembly cannot contain components of non-ObjComponent type");
144 }
145 newcomp->setParent(this);
146 m_group.emplace_back(c);
147 }
148 return static_cast<int>(m_group.size());
149}
150
160int ObjCompAssembly::addCopy(IComponent *comp, const std::string &n) {
161 if (m_map)
162 throw std::runtime_error("ObjCompAssembly::addCopy() called on a Parametrized object.");
163
164 if (comp) {
165 IComponent *newcomp = comp->clone();
166 auto *c = dynamic_cast<ObjComponent *>(newcomp);
167 if (!c) {
169 "ObjCompAssembly cannot contain components of non-ObjComponent type");
170 }
171 newcomp->setParent(this);
172 newcomp->setName(n);
173 m_group.emplace_back(c);
174 }
175 return static_cast<int>(m_group.size());
176}
177
182 if (m_map) {
183 auto objCompAss = dynamic_cast<const ObjCompAssembly *>(m_base);
184 if (!objCompAss) {
185 throw std::logic_error("Failed to cast base component to ObjCompAssembly");
186 }
187 return objCompAss->nelements();
188 } else
189 return static_cast<int>(m_group.size());
190}
191
201std::shared_ptr<IComponent> ObjCompAssembly::operator[](int i) const {
202 if (i < 0 || i > nelements() - 1) {
203 throw std::runtime_error("ObjCompAssembly::operator[] range not valid");
204 }
205
206 if (m_map) {
207 auto child_base = dynamic_cast<const ObjCompAssembly *>(m_base);
208 if (!child_base) {
209 throw std::logic_error("Failed to cast base component to ObjCompAssembly");
210 }
211 return ParComponentFactory::create(child_base->operator[](i), m_map);
212 } else {
213 // Unparamterized - return the normal one
214 return std::shared_ptr<IComponent>(m_group[i], NoDeleting());
215 }
216}
217
218//------------------------------------------------------------------------------------------------
225void ObjCompAssembly::getChildren(std::vector<IComponent_const_sptr> &outVector, bool recursive) const {
226 for (int i = 0; i < this->nelements(); i++) {
227 std::shared_ptr<IComponent> comp = this->getChild(i);
228 if (comp) {
229 outVector.emplace_back(comp);
230 // Look deeper, on option.
231 if (recursive) {
232 std::shared_ptr<ICompAssembly> assemb = std::dynamic_pointer_cast<ICompAssembly>(comp);
233 if (assemb)
234 assemb->getChildren(outVector, recursive);
235 }
236 }
237 }
238}
239
247std::shared_ptr<const IComponent> ObjCompAssembly::getComponentByName(const std::string &cname, int nlevels) const {
248 int nchildren = this->nelements();
249 if (nlevels > 1)
250 g_log.debug() << "only implemented for children\n";
251 for (int i = 0; i < nchildren; ++i) {
252 std::shared_ptr<Geometry::IComponent> comp = this->getChild(i);
253 if (comp->getName() == cname)
254 return comp;
255 }
256 return std::shared_ptr<const IComponent>();
257}
258
265void ObjCompAssembly::printChildren(std::ostream &os) const {
266 // std::vector<IComponent*>::const_iterator it;
267 int i = 0;
268 for (i = 0; i < this->nelements(); i++) {
269 os << "Component " << i << " : **********\n";
270 this->operator[](i)->printSelf(os);
271 }
272}
273
280void ObjCompAssembly::printTree(std::ostream &os) const {
281 // std::vector<IComponent*>::const_iterator it;
282 int i = 0;
283 for (i = 0; i < this->nelements(); i++) {
284 std::shared_ptr<const ObjCompAssembly> test = std::dynamic_pointer_cast<const ObjCompAssembly>(this->operator[](i));
285 os << "Element " << i << " in the assembly : ";
286 if (test) {
287 os << test->getName() << '\n';
288 os << "Children :******** \n";
289 test->printTree(os);
290 } else
291 os << this->operator[](i)->getName() << '\n';
292 }
293}
294
301 if (m_map && !hasComponentInfo()) {
302 V3D pos;
303 if (!m_map->getCachedLocation(m_base, pos)) {
304 pos = Component::getPos();
306 }
307 return pos;
308 } else
309 return Component::getPos();
310}
311
318 if (m_map && !hasComponentInfo()) {
319 Quat rot;
320 if (!m_map->getCachedRotation(m_base, rot)) {
323 }
324 return rot;
325 } else
326 return Component::getRotation();
327}
328
329//------------------------------------------------------------------------------------------------
338 std::deque<IComponent_const_sptr> &searchQueue) const {
339 int nchildren = this->nelements();
340 for (int i = 0; i < nchildren; ++i) {
341 std::shared_ptr<Geometry::IComponent> comp = this->getChild(i);
342 if (std::dynamic_pointer_cast<ICompAssembly>(comp)) {
343 searchQueue.emplace_back(comp);
344 }
345 // Check the physical object intersection
346 else if (auto *physicalObject = dynamic_cast<IObjComponent *>(comp.get())) {
347 physicalObject->interceptSurface(testRay);
348 } else {
349 }
350 }
351}
352
354 // Generic Assembly registration call.
355 return visitor.registerObjComponentAssembly(*this);
356}
357
365std::shared_ptr<IObject> ObjCompAssembly::createOutline() {
366 if (m_group.empty()) {
367 throw Kernel::Exception::InstrumentDefinitionError("Empty ObjCompAssembly");
368 }
369
370 if (nelements() < 2) {
371 g_log.warning("Creating outline with fewer than 2 elements. The outline "
372 "displayed may be inaccurate.");
373 }
374
375 // Get information about the shape and size of a detector
376 std::string type;
378 std::vector<Kernel::V3D> vectors;
379 double radius, height, innerRadius;
380 std::shared_ptr<const IObject> obj = m_group.front()->shape();
381 if (!obj) {
382 throw Kernel::Exception::InstrumentDefinitionError("Found ObjComponent without shape");
383 }
384 obj->GetObjectGeom(otype, vectors, innerRadius, radius, height);
386 type = "box";
387 } else if (otype == detail::ShapeInfo::GeometryShape::CYLINDER) {
388 type = "cylinder";
389 } else {
390 throw std::runtime_error("IDF \"outline\" option is only allowed for assemblies containing "
391 "components of types \"box\" or \"cylinder\".");
392 }
393
394 // Calculate the dimensions of the outline object
395
396 // find the 'moments of inertia' of the assembly
397 double Ixx = 0, Iyy = 0, Izz = 0, Ixy = 0, Ixz = 0, Iyz = 0;
398 V3D Cmass; // 'center of mass' of the assembly
399 for (const_comp_it it = m_group.begin(); it != m_group.end(); ++it) {
400 V3D p = (**it).getRelativePos();
401 Cmass += p;
402 }
403 Cmass /= nelements();
404 for (const_comp_it it = m_group.begin(); it != m_group.end(); ++it) {
405 V3D p = (**it).getRelativePos();
406 double x = p.X() - Cmass.X(), x2 = x * x;
407 double y = p.Y() - Cmass.Y(), y2 = y * y;
408 double z = p.Z() - Cmass.Z(), z2 = z * z;
409 Ixx += y2 + z2;
410 Iyy += x2 + z2;
411 Izz += y2 + x2;
412 Ixy -= x * y;
413 Ixz -= x * z;
414 Iyz -= y * z;
415 }
416 // principal axes of the outline shape
417 // vz defines the line through all pixel centres
418 V3D vx, vy, vz;
419
420 if (Ixx == 0) // pixels along x axis
421 {
422 vx = V3D(0, 1, 0);
423 vy = V3D(0, 0, 1);
424 vz = V3D(1, 0, 0);
425 } else if (Iyy == 0) // pixels along y axis
426 {
427 vx = V3D(0, 0, 1);
428 vy = V3D(1, 0, 0);
429 vz = V3D(0, 1, 0);
430 } else if (Izz == 0) // pixels along z axis
431 {
432 vx = V3D(1, 0, 0);
433 vy = V3D(0, 1, 0);
434 vz = V3D(0, 0, 1);
435 } else {
436 // Either the detectors are not perfectrly aligned or
437 // vz is parallel to neither of the 3 axis x,y,z
438 // This code is unfinished
439 DblMatrix II(3, 3), Vec(3, 3), D(3, 3);
440 II[0][0] = Ixx;
441 II[0][1] = Ixy;
442 II[0][2] = Ixz;
443 II[1][0] = Ixy;
444 II[1][1] = Iyy;
445 II[1][2] = Iyz;
446 II[2][0] = Ixz;
447 II[2][1] = Iyz;
448 II[2][2] = Izz;
449 g_log.debug() << "Inertia matrix: " << II << II.determinant() << '\n';
450 II.Diagonalise(Vec, D);
451 g_log.debug() << "Vectors: " << Vec << '\n';
452 g_log.debug() << "Moments: " << D << '\n';
453 vx = V3D(Vec[0][0], Vec[1][0], Vec[2][0]);
454 vy = V3D(Vec[0][1], Vec[1][1], Vec[2][1]);
455 vz = V3D(Vec[0][2], Vec[1][2], Vec[2][2]);
456 }
457
458 // find assembly sizes along the principal axes
459 double hx, hy, hz; // sizes along x,y, and z axis
460
461 // maximum displacements from the mass centre along axis vx,vy, and vz
462 // in positive (p) and negative (n) directions.
463 // positive displacements are positive numbers and negative ones are negative
464 double hxn = 0, hyn = 0, hzn = 0;
465 double hxp = 0, hyp = 0, hzp = 0;
466 for (const_comp_it it = m_group.begin(); it != m_group.end(); ++it) {
467 // displacement vector of a detector
468 V3D p = (**it).getRelativePos() - Cmass;
469 // its projection on the vx axis
470 double h = p.scalar_prod(vx);
471 if (h > hxp)
472 hxp = h;
473 if (h < hxn)
474 hxn = h;
475 // its projection on the vy axis
476 h = p.scalar_prod(vy);
477 if (h > hyp)
478 hyp = h;
479 if (h < hyn)
480 hyn = h;
481 // its projection on the vz axis
482 h = p.scalar_prod(vz);
483 if (h > hzp)
484 hzp = h;
485 if (h < hzn)
486 hzn = h;
487 }
488
489 // calc the assembly sizes
490 hx = hxp - hxn;
491 hy = hyp - hyn;
492 hz = hzp - hzn;
493 // hx and hy must be practically zero
494 if (hx > 1e-3 || hy > 1e-3) // arbitrary numbers
495 {
496 throw Kernel::Exception::InstrumentDefinitionError("Detectors of a ObjCompAssembly do not lie on a staraight line");
497 }
498
499 // determine the order of the detectors to make sure that the texture
500 // coordinates are correct
501 bool firstAtBottom; // first detector is at the bottom of the outline shape
502 // the bottom end is the one with the negative displacement from the centre
503 firstAtBottom = ((**m_group.begin()).getRelativePos() - Cmass).scalar_prod(vz) < 0;
504
505 // form the input string for the ShapeFactory
506 std::ostringstream obj_str;
507 if (type == "box") {
508 hx = hy = 0;
509 height = 0;
510 V3D p0 = vectors[0];
511 for (size_t i = 1; i < vectors.size(); ++i) {
512 V3D p = vectors[i] - p0;
513 double h = fabs(p.scalar_prod(vx));
514 if (h > hx)
515 hx = h;
516 h = fabs(p.scalar_prod(vy));
517 if (h > hy)
518 hy = h;
519 height = fabs(p.scalar_prod(vz));
520 if (h > height)
521 height = h;
522 }
523
524 vx *= hx / 2;
525 vy *= hy / 2;
526 vz *= hzp + height / 2;
527
528 if (!firstAtBottom) {
529 vz = vz * (-1);
530 }
531
532 // define the outline shape as cuboid
533 V3D p_lfb = Cmass - vx - vy - vz;
534 V3D p_lft = Cmass - vx - vy + vz;
535 V3D p_lbb = Cmass - vx + vy - vz;
536 V3D p_rfb = Cmass + vx - vy - vz;
537 obj_str << "<cuboid id=\"shape\">";
538 obj_str << "<left-front-bottom-point ";
539 obj_str << "x=\"" << p_lfb.X();
540 obj_str << "\" y=\"" << p_lfb.Y();
541 obj_str << "\" z=\"" << p_lfb.Z();
542 obj_str << "\" />";
543 obj_str << "<left-front-top-point ";
544 obj_str << "x=\"" << p_lft.X();
545 obj_str << "\" y=\"" << p_lft.Y();
546 obj_str << "\" z=\"" << p_lft.Z();
547 obj_str << "\" />";
548 obj_str << "<left-back-bottom-point ";
549 obj_str << "x=\"" << p_lbb.X();
550 obj_str << "\" y=\"" << p_lbb.Y();
551 obj_str << "\" z=\"" << p_lbb.Z();
552 obj_str << "\" />";
553 obj_str << "<right-front-bottom-point ";
554 obj_str << "x=\"" << p_rfb.X();
555 obj_str << "\" y=\"" << p_rfb.Y();
556 obj_str << "\" z=\"" << p_rfb.Z();
557 obj_str << "\" />";
558 obj_str << "</cuboid>";
559
560 } else if (type == "cylinder") {
561 // the outline is one detector height short
562 hz += height;
563 // shift Cmass to the end of the cylinder where the first detector is
564 if (firstAtBottom) {
565 Cmass += vz * hzn;
566 } else {
567 hzp += height;
568 Cmass += vz * hzp;
569 // inverse the vz axis
570 vz = vz * (-1);
571 }
572 obj_str << "<cylinder id=\"stick\">";
573 obj_str << "<centre-of-bottom-base ";
574 obj_str << "x=\"" << Cmass.X();
575 obj_str << "\" y=\"" << Cmass.Y();
576 obj_str << "\" z=\"" << Cmass.Z();
577 obj_str << "\" />";
578 obj_str << "<axis x=\"" << vz.X() << "\" y=\"" << vz.Y() << "\" z=\"" << vz.Z() << "\" /> ";
579 obj_str << "<radius val=\"" << radius << "\" />";
580 obj_str << "<height val=\"" << hz << "\" />";
581 obj_str << "</cylinder>";
582 }
583
584 if (!obj_str.str().empty()) {
585 std::shared_ptr<IObject> s = ShapeFactory().createShape(obj_str.str());
586 setOutline(s);
587 return s;
588 }
589 return std::shared_ptr<IObject>();
590}
591
596void ObjCompAssembly::setOutline(std::shared_ptr<const IObject> obj) { m_shape = std::move(obj); }
597
607std::ostream &operator<<(std::ostream &os, const ObjCompAssembly &ass) {
608 ass.printSelf(os);
609 os << "************************\n";
610 os << "Number of children :" << ass.nelements() << '\n';
611 ass.printChildren(os);
612 return os;
613}
614
615} // namespace Mantid::Geometry
double height
Definition: GetAllEi.cpp:155
#define fabs(x)
Definition: Matrix.cpp:22
double radius
Definition: Rasterize.cpp:31
double innerRadius
Definition: Rasterize.cpp:39
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:307
Kernel::V3D getPos() const override
Get the position of the IComponent. Tree structure is traverse through the.
Definition: Component.cpp:325
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 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...
Definition: IObjComponent.h:37
Void deleter for shared pointers.
void operator()(void *p)
deleting operator. Does nothing
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
Register the contents of this ObjComponent.
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::string type() const override
String description of the type of component.
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...
Definition: ObjComponent.h:33
std::shared_ptr< const IObject > m_shape
The physical geometry representation.
Definition: ObjComponent.h:86
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.
Definition: ShapeFactory.h:89
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:52
void debug(const std::string &msg)
Logs at debug level.
Definition: Logger.cpp:114
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
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:274
constexpr double X() const noexcept
Get x.
Definition: V3D.h:232
constexpr double Y() const noexcept
Get y.
Definition: V3D.h:233
constexpr double Z() const noexcept
Get z.
Definition: V3D.h:234
Kernel::Logger g_log("ExperimentInfo")
static logger object
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.
Definition: PointGroup.cpp:312
Mantid::Kernel::Matrix< double > DblMatrix
Definition: Matrix.h:206