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
288//------------------------------------------------------------------------------------------------
297 std::deque<IComponent_const_sptr> &searchQueue) const {
298 int nchildren = this->nelements();
299 for (int i = 0; i < nchildren; ++i) {
300 std::shared_ptr<Geometry::IComponent> comp = this->getChild(i);
301 if (std::dynamic_pointer_cast<ICompAssembly>(comp)) {
302 searchQueue.emplace_back(comp);
303 }
304 // Check the physical object intersection
305 else if (const auto *physicalObject = dynamic_cast<IObjComponent *>(comp.get())) {
306 physicalObject->interceptSurface(testRay);
307 } else {
308 }
309 }
310}
311
313 // Generic Assembly registration call.
314 return visitor.registerObjComponentAssembly(*this);
315}
316
324std::shared_ptr<IObject> ObjCompAssembly::createOutline() {
325 if (m_group.empty()) {
326 throw Kernel::Exception::InstrumentDefinitionError("Empty ObjCompAssembly");
327 }
328
329 if (nelements() < 2) {
330 g_log.warning("Creating outline with fewer than 2 elements. The outline "
331 "displayed may be inaccurate.");
332 }
333
334 // Get information about the shape and size of a detector
335 std::string detectorType;
337 std::vector<Kernel::V3D> vectors;
338 double radius, height, innerRadius;
339 std::shared_ptr<const IObject> obj = m_group.front()->shape();
340 if (!obj) {
341 throw Kernel::Exception::InstrumentDefinitionError("Found ObjComponent without shape");
342 }
343 obj->GetObjectGeom(otype, vectors, innerRadius, radius, height);
345 detectorType = "box";
346 } else if (otype == detail::ShapeInfo::GeometryShape::CYLINDER) {
347 detectorType = "cylinder";
348 } else {
349 throw std::runtime_error("IDF \"outline\" option is only allowed for assemblies containing "
350 "components of types \"box\" or \"cylinder\".");
351 }
352
353 // Calculate the dimensions of the outline object
354
355 // find the 'moments of inertia' of the assembly
356 double Ixx = 0, Iyy = 0, Izz = 0, Ixy = 0, Ixz = 0, Iyz = 0;
357 V3D Cmass; // 'center of mass' of the assembly
358 for (const_comp_it it = m_group.begin(); it != m_group.end(); ++it) {
359 V3D p = (**it).getRelativePos();
360 Cmass += p;
361 }
362 Cmass /= nelements();
363 for (const_comp_it it = m_group.begin(); it != m_group.end(); ++it) {
364 V3D p = (**it).getRelativePos();
365 double x = p.X() - Cmass.X(), x2 = x * x;
366 double y = p.Y() - Cmass.Y(), y2 = y * y;
367 double z = p.Z() - Cmass.Z(), z2 = z * z;
368 Ixx += y2 + z2;
369 Iyy += x2 + z2;
370 Izz += y2 + x2;
371 Ixy -= x * y;
372 Ixz -= x * z;
373 Iyz -= y * z;
374 }
375 // principal axes of the outline shape
376 // vz defines the line through all pixel centres
377 V3D vx, vy, vz;
378
379 if (Ixx == 0) // pixels along x axis
380 {
381 vx = V3D(0, 1, 0);
382 vy = V3D(0, 0, 1);
383 vz = V3D(1, 0, 0);
384 } else if (Iyy == 0) // pixels along y axis
385 {
386 vx = V3D(0, 0, 1);
387 vy = V3D(1, 0, 0);
388 vz = V3D(0, 1, 0);
389 } else if (Izz == 0) // pixels along z axis
390 {
391 vx = V3D(1, 0, 0);
392 vy = V3D(0, 1, 0);
393 vz = V3D(0, 0, 1);
394 } else {
395 // Either the detectors are not perfectrly aligned or
396 // vz is parallel to neither of the 3 axis x,y,z
397 // This code is unfinished
398 DblMatrix II(3, 3), Vec(3, 3), D(3, 3);
399 II[0][0] = Ixx;
400 II[0][1] = Ixy;
401 II[0][2] = Ixz;
402 II[1][0] = Ixy;
403 II[1][1] = Iyy;
404 II[1][2] = Iyz;
405 II[2][0] = Ixz;
406 II[2][1] = Iyz;
407 II[2][2] = Izz;
408 g_log.debug() << "Inertia matrix: " << II << II.determinant() << '\n';
409 II.Diagonalise(Vec, D);
410 g_log.debug() << "Vectors: " << Vec << '\n';
411 g_log.debug() << "Moments: " << D << '\n';
412 vx = V3D(Vec[0][0], Vec[1][0], Vec[2][0]);
413 vy = V3D(Vec[0][1], Vec[1][1], Vec[2][1]);
414 vz = V3D(Vec[0][2], Vec[1][2], Vec[2][2]);
415 }
416
417 // find assembly sizes along the principal axes
418 double hx, hy, hz; // sizes along x,y, and z axis
419
420 // maximum displacements from the mass centre along axis vx,vy, and vz
421 // in positive (p) and negative (n) directions.
422 // positive displacements are positive numbers and negative ones are negative
423 double hxn = 0, hyn = 0, hzn = 0;
424 double hxp = 0, hyp = 0, hzp = 0;
425 for (const_comp_it it = m_group.begin(); it != m_group.end(); ++it) {
426 // displacement vector of a detector
427 V3D p = (**it).getRelativePos() - Cmass;
428 // its projection on the vx axis
429 double h = p.scalar_prod(vx);
430 if (h > hxp)
431 hxp = h;
432 if (h < hxn)
433 hxn = h;
434 // its projection on the vy axis
435 h = p.scalar_prod(vy);
436 if (h > hyp)
437 hyp = h;
438 if (h < hyn)
439 hyn = h;
440 // its projection on the vz axis
441 h = p.scalar_prod(vz);
442 if (h > hzp)
443 hzp = h;
444 if (h < hzn)
445 hzn = h;
446 }
447
448 // calc the assembly sizes
449 hx = hxp - hxn;
450 hy = hyp - hyn;
451 hz = hzp - hzn;
452 // hx and hy must be practically zero
453 if (hx > 1e-3 || hy > 1e-3) // arbitrary numbers
454 {
455 throw Kernel::Exception::InstrumentDefinitionError("Detectors of a ObjCompAssembly do not lie on a staraight line");
456 }
457
458 // determine the order of the detectors to make sure that the texture
459 // coordinates are correct
460 bool firstAtBottom; // first detector is at the bottom of the outline shape
461 // the bottom end is the one with the negative displacement from the centre
462 firstAtBottom = ((**m_group.begin()).getRelativePos() - Cmass).scalar_prod(vz) < 0;
463
464 // form the input string for the ShapeFactory
465 std::ostringstream obj_str;
466 if (detectorType == "box") {
467 hx = hy = 0;
468 height = 0;
469 V3D p0 = vectors[0];
470 for (size_t i = 1; i < vectors.size(); ++i) {
471 V3D p = vectors[i] - p0;
472 double h = fabs(p.scalar_prod(vx));
473 if (h > hx)
474 hx = h;
475 h = fabs(p.scalar_prod(vy));
476 if (h > hy)
477 hy = h;
478 height = fabs(p.scalar_prod(vz));
479 if (h > height)
480 height = h;
481 }
482
483 vx *= hx / 2;
484 vy *= hy / 2;
485 vz *= hzp + height / 2;
486
487 if (!firstAtBottom) {
488 vz = vz * (-1);
489 }
490
491 // define the outline shape as cuboid
492 V3D p_lfb = Cmass - vx - vy - vz;
493 V3D p_lft = Cmass - vx - vy + vz;
494 V3D p_lbb = Cmass - vx + vy - vz;
495 V3D p_rfb = Cmass + vx - vy - vz;
496 obj_str << "<cuboid id=\"shape\">";
497 obj_str << "<left-front-bottom-point ";
498 obj_str << "x=\"" << p_lfb.X();
499 obj_str << "\" y=\"" << p_lfb.Y();
500 obj_str << "\" z=\"" << p_lfb.Z();
501 obj_str << "\" />";
502 obj_str << "<left-front-top-point ";
503 obj_str << "x=\"" << p_lft.X();
504 obj_str << "\" y=\"" << p_lft.Y();
505 obj_str << "\" z=\"" << p_lft.Z();
506 obj_str << "\" />";
507 obj_str << "<left-back-bottom-point ";
508 obj_str << "x=\"" << p_lbb.X();
509 obj_str << "\" y=\"" << p_lbb.Y();
510 obj_str << "\" z=\"" << p_lbb.Z();
511 obj_str << "\" />";
512 obj_str << "<right-front-bottom-point ";
513 obj_str << "x=\"" << p_rfb.X();
514 obj_str << "\" y=\"" << p_rfb.Y();
515 obj_str << "\" z=\"" << p_rfb.Z();
516 obj_str << "\" />";
517 obj_str << "</cuboid>";
518
519 } else if (detectorType == "cylinder") {
520 // the outline is one detector height short
521 hz += height;
522 // shift Cmass to the end of the cylinder where the first detector is
523 if (firstAtBottom) {
524 Cmass += vz * hzn;
525 } else {
526 hzp += height;
527 Cmass += vz * hzp;
528 // inverse the vz axis
529 vz = vz * (-1);
530 }
531 obj_str << "<cylinder id=\"stick\">";
532 obj_str << "<centre-of-bottom-base ";
533 obj_str << "x=\"" << Cmass.X();
534 obj_str << "\" y=\"" << Cmass.Y();
535 obj_str << "\" z=\"" << Cmass.Z();
536 obj_str << "\" />";
537 obj_str << "<axis x=\"" << vz.X() << "\" y=\"" << vz.Y() << "\" z=\"" << vz.Z() << "\" /> ";
538 obj_str << "<radius val=\"" << radius << "\" />";
539 obj_str << "<height val=\"" << hz << "\" />";
540 obj_str << "</cylinder>";
541 }
542
543 if (!obj_str.str().empty()) {
544 std::shared_ptr<IObject> s = ShapeFactory().createShape(obj_str.str());
545 setOutline(s);
546 return s;
547 }
548 return std::shared_ptr<IObject>();
549}
550
555void ObjCompAssembly::setOutline(std::shared_ptr<const IObject> obj) { m_shape = std::move(obj); }
556
566std::ostream &operator<<(std::ostream &os, const ObjCompAssembly &ass) {
567 ass.printSelf(os);
568 os << "************************\n";
569 os << "Number of children :" << ass.nelements() << '\n';
570 ass.printChildren(os);
571 return os;
572}
573
574} // 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:318
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 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.
~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.
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.
Parameter map iterator typedef.
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 3D vectors.
Definition V3D.h:35
constexpr double scalar_prod(const V3D &v) const noexcept
Calculates the cross product.
Definition V3D.h:281
constexpr double X() const noexcept
Get x.
Definition V3D.h:239
constexpr double Y() const noexcept
Get y.
Definition V3D.h:240
constexpr double Z() const noexcept
Get z.
Definition V3D.h:241
This functor is used as the deleter object of a shared_ptr to effectively erase ownership Raw pointer...
Definition IComponent.h:171
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:205