Mantid
Loading...
Searching...
No Matches
ShapeFactory.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 +
7//----------------------------------------------------------------------
8// Includes
9//----------------------------------------------------------------------
10
23
24#include "MantidKernel/Logger.h"
25#include "MantidKernel/Quat.h"
26
27#include <Poco/AutoPtr.h>
28#include <Poco/DOM/DOMParser.h>
29#include <Poco/DOM/DOMWriter.h>
30#include <Poco/DOM/Document.h>
31#include <Poco/DOM/Element.h>
32#include <Poco/DOM/NodeList.h>
33
34#include "boost/make_shared.hpp"
35
36#include <algorithm>
37#include <iomanip>
38#include <limits>
39#include <optional>
40#include <sstream>
41
42using Poco::XML::Document;
43using Poco::XML::DOMParser;
44using Poco::XML::DOMWriter;
45using Poco::XML::Element;
46using Poco::XML::Node;
47using Poco::XML::NodeList;
48
49namespace Mantid::Geometry {
50
51using namespace Kernel;
52
53namespace {
54const V3D DEFAULT_CENTRE(0, 0, 0);
55const V3D DEFAULT_AXIS(0, 0, 1);
56
58Logger g_log("ShapeFactory");
59} // namespace
60
61namespace {
62std::vector<double> DegreesToRadians(const std::vector<double> &anglesDegrees) {
63 std::vector<double> anglesRadians;
64 std::transform(anglesDegrees.cbegin(), anglesDegrees.cend(), std::back_inserter(anglesRadians),
65 [](const auto angle) { return angle * M_PI / 180.0; });
66 return anglesRadians;
67}
68} // namespace
69
78std::shared_ptr<CSGObject> ShapeFactory::createShape(std::string shapeXML, bool addTypeTag) {
79 // wrap in a type tag
80 if (addTypeTag)
81 shapeXML = "<type name=\"userShape\"> " + shapeXML + " </type>";
82
83 // Set up the DOM parser and parse xml string
84 DOMParser pParser;
85 Poco::AutoPtr<Document> pDoc;
86 try {
87 pDoc = pParser.parseString(shapeXML);
88 } catch (...) {
89 g_log.warning("Unable to parse XML string " + shapeXML + " . Empty geometry Object is returned.");
90
91 return std::make_shared<CSGObject>();
92 }
93 // Get pointer to root element
94 Element *pRootElem = pDoc->documentElement();
95
96 // convert into a Geometry object
97 return createShape(pRootElem);
98}
99
108std::shared_ptr<CSGObject> ShapeFactory::createShape(Poco::XML::Element *pElem) {
109 // Write the definition to a string to store in the final object
110 std::stringstream xmlstream;
111 DOMWriter writer;
112 writer.writeNode(xmlstream, pElem);
113 std::string shapeXML = xmlstream.str();
114 auto retVal = std::make_shared<CSGObject>(shapeXML);
115
116 // if no <algebra> element then use default algebra
117 bool defaultAlgebra(false);
118 // get algebra string
119 Poco::AutoPtr<NodeList> pNL_algebra = pElem->getElementsByTagName("algebra");
120 std::string algebraFromUser;
121 if (pNL_algebra->length() == 0) {
122 defaultAlgebra = true;
123 } else if (pNL_algebra->length() == 1) {
124 auto *pElemAlgebra = static_cast<Element *>(pNL_algebra->item(0));
125 algebraFromUser = pElemAlgebra->getAttribute("val");
126 } else {
127 g_log.warning() << "More than one algebra string defined for this shape. "
128 << "Maximum one allowed. Therefore empty shape is returned.";
129 return retVal;
130 }
131
132 // <goniometer> is the TOTAL rotation applied to the surfaces below as they are parsed.
133 Poco::AutoPtr<NodeList> pNL_gonio = pElem->getElementsByTagName("goniometer");
134 auto *pElemGonio = static_cast<Element *>(pNL_gonio->item(0));
136 if (pElemGonio) {
138 }
139
140 // <applied-goniometer> says how much of that total is a bake into the lab frame. Pure metadata -
141 // it rotates nothing - and the only account of which frame the parsed surfaces ended up in.
142 Poco::AutoPtr<NodeList> pNL_applied = pElem->getElementsByTagName("applied-goniometer");
143 auto *pElemApplied = static_cast<Element *>(pNL_applied->item(0));
144 Kernel::Matrix<double> bakedRotation(3, 3, true);
145 if (pElemApplied && !pElemGonio) {
146 g_log.warning() << "An <applied-goniometer> tag was given without a <goniometer> tag. There is "
147 << "no rotation for it to describe, so it is ignored.\n";
148 } else if (pElemApplied) {
149 bakedRotation = parseMatrixElement(pElemApplied);
150 } else {
151 // No <applied-goniometer>: read the whole <goniometer> as a bake, which is what CopySample and
152 // SetSample wrote. RotateSampleShape also wrote a lone tag, holding Rs * R, and that cannot be told
153 // apart here, so its Rs is misread as part of the bake.
154 bakedRotation = m_gonioRotateMatrix;
155 }
156 retVal->setAppliedGoniometerRotation(bakedRotation);
157
158 Poco::AutoPtr<NodeList> pNL_rotate_all = pElem->getElementsByTagName("rotate-all");
159 auto *pElemRotateAll = static_cast<Element *>(pNL_rotate_all->item(0));
161 if (pElemRotateAll) {
162 std::vector<double> rotateAngles = DegreesToRadians(parsePosition(pElemRotateAll));
163 m_rotateAllMatrix = generateMatrix(rotateAngles[0], rotateAngles[1], rotateAngles[2]);
164 }
165
166 // match id given to a shape by the user to
167 // id understandable by Mantid code
168 std::map<std::string, std::string> idMatching;
169
170 // loop over all the sub-elements of pElem
171 Poco::AutoPtr<NodeList> pNL = pElem->childNodes(); // get all child nodes
172 unsigned long pNL_length = pNL->length();
173 int numPrimitives = 0;
174 // stores the primitives that will be
175 // used to build final shape
176 std::map<int, std::shared_ptr<Surface>> primitives;
177 // used to build up unique id's for each shape added. Must start
178 // from int > zero.
179 int l_id = 1;
180 // Element of fixed complete object
181 Element *lastElement = nullptr;
182 for (unsigned int i = 0; i < pNL_length; i++) {
183 if ((pNL->item(i))->nodeType() == Node::ELEMENT_NODE) {
184 auto *pE = static_cast<Element *>(pNL->item(i));
185
186 // assume for now that if sub-element has attribute id then it is a shape
187 // element
188 if (pE->hasAttribute("id")) {
189 std::string idFromUser = pE->getAttribute("id"); // get id
190
191 std::string primitiveName = pE->tagName(); // get name of primitive
192
193 // if there are any error thrown while parsing the XML string for a
194 // given shape
195 // write out a warning to the user that this shape is ignored. If all
196 // shapes are ignored
197 // this way an empty object is returned to the user.
198 try {
199 if (primitiveName == "sphere") {
200 lastElement = pE;
201 idMatching[idFromUser] = parseSphere(pE, primitives, l_id);
202 numPrimitives++;
203 } else if (primitiveName == "infinite-plane") {
204 idMatching[idFromUser] = parseInfinitePlane(pE, primitives, l_id);
205 retVal->setFiniteGeometryFlag(false);
206 numPrimitives++;
207 } else if (primitiveName == "infinite-cylinder") {
208 idMatching[idFromUser] = parseInfiniteCylinder(pE, primitives, l_id);
209 retVal->setFiniteGeometryFlag(false);
210 numPrimitives++;
211 } else if (primitiveName == "cylinder") {
212 lastElement = pE;
213 idMatching[idFromUser] = parseCylinder(pE, primitives, l_id);
214 numPrimitives++;
215 } else if (primitiveName == "hollow-cylinder") {
216 lastElement = pE;
217 idMatching[idFromUser] = parseHollowCylinder(pE, primitives, l_id);
218 numPrimitives++;
219 } else if (primitiveName == "cuboid") {
220 lastElement = pE;
221 idMatching[idFromUser] = parseCuboid(pE, primitives, l_id);
222 numPrimitives++;
223 } else if (primitiveName == "infinite-cone") {
224 idMatching[idFromUser] = parseInfiniteCone(pE, primitives, l_id);
225 retVal->setFiniteGeometryFlag(false);
226 numPrimitives++;
227 } else if (primitiveName == "cone") {
228 lastElement = pE;
229 idMatching[idFromUser] = parseCone(pE, primitives, l_id);
230 numPrimitives++;
231 } else if (primitiveName == "hexahedron") {
232 lastElement = pE;
233 idMatching[idFromUser] = parseHexahedron(pE, primitives, l_id);
234 numPrimitives++;
235 } else if (primitiveName == "tapered-guide") {
236 idMatching[idFromUser] = parseTaperedGuide(pE, primitives, l_id);
237 numPrimitives++;
238 } else if (primitiveName == "torus") {
239 idMatching[idFromUser] = parseTorus(pE, primitives, l_id);
240 numPrimitives++;
241 } else if (primitiveName == "slice-of-cylinder-ring") {
242 idMatching[idFromUser] = parseSliceOfCylinderRing(pE, primitives, l_id);
243 numPrimitives++;
244 } else {
245 g_log.warning(primitiveName + " not a recognised geometric shape. This shape is ignored.");
246 }
247 } catch (std::invalid_argument &e) {
248 g_log.warning() << e.what() << " <" << primitiveName << "> shape is ignored.";
249 } catch (std::runtime_error &e) {
250 g_log.warning() << e.what() << " <" << primitiveName << "> shape is ignored.";
251 } catch (...) {
252 g_log.warning() << " Problem with parsing XML string for <" << primitiveName << ">. This shape is ignored.";
253 }
254 }
255 }
256 }
257
258 if (!defaultAlgebra) {
259 // Translate algebra string defined by the user into something Mantid can
260 // understand
261
262 // std::string algebra; // to hold algebra in a way Mantid can understand
263 std::map<std::string, std::string>::iterator iter;
264 std::map<size_t, std::string, std::greater<size_t>> allFound;
265 for (iter = idMatching.begin(); iter != idMatching.end(); ++iter) {
266 size_t found = algebraFromUser.find(iter->first);
267
268 if (found == std::string::npos) {
269 defaultAlgebra = true;
270 g_log.warning() << "Algebra shape Warning: " + iter->first +
271 " not found in algebra string: " + algebraFromUser + "\n" +
272 ". Default to equal shape to intersection of those defined.";
273 break;
274 } else {
275 allFound[found] = iter->first;
276 }
277 }
278
279 // Here do the actually swapping of strings
280 // but only if the algebra containes all the shapes
281 if (allFound.size() == idMatching.size()) {
282 std::map<size_t, std::string, std::greater<size_t>>::iterator iter2;
283 for (iter2 = allFound.begin(); iter2 != allFound.end(); ++iter2) {
284 // std::string kuse = iter2->second;
285 algebraFromUser.replace(iter2->first, (iter2->second).size(), idMatching[iter2->second]);
286 }
287 }
288 }
289 if (defaultAlgebra) {
290 algebraFromUser = ""; // reset in case we are overwriten invalid string
291 std::map<std::string, std::string>::iterator iter;
292 for (iter = idMatching.begin(); iter != idMatching.end(); ++iter) {
293 algebraFromUser.append(iter->second + " "); // default is intersection
294 }
295 }
296
297 // check to see if there actually were any primitives in 'type' xml element
298 // and if yes then return empty Object. Otherwise populate Object with the
299 // primitives
300
301 if (numPrimitives == 0)
302 return retVal;
303 else {
304 retVal->setObject(21, algebraFromUser);
305 retVal->populate(primitives);
306 // check whether there is only one surface/closed surface
307 if (numPrimitives == 1 && lastElement != nullptr) // special case
308 {
309 // parse the primitive and create a Geometry handler for the object
310 createGeometryHandler(lastElement, retVal);
311 }
312
313 // get bounding box string
314 Poco::AutoPtr<NodeList> pNL_boundingBox = pElem->getElementsByTagName("bounding-box");
315 if (pNL_boundingBox->length() != 1) // should probably throw an error if
316 // more than 1 bounding box is
317 // defined...
318 return retVal;
319
320 double xmin = std::stod((getShapeElement(pElem, "x-min"))->getAttribute("val"));
321 double ymin = std::stod((getShapeElement(pElem, "y-min"))->getAttribute("val"));
322 double zmin = std::stod((getShapeElement(pElem, "z-min"))->getAttribute("val"));
323 double xmax = std::stod((getShapeElement(pElem, "x-max"))->getAttribute("val"));
324 double ymax = std::stod((getShapeElement(pElem, "y-max"))->getAttribute("val"));
325 double zmax = std::stod((getShapeElement(pElem, "z-max"))->getAttribute("val"));
326
327 retVal->defineBoundingBox(xmax, ymax, zmax, xmin, ymin, zmin);
328
329 return retVal;
330 }
331}
332
344std::string ShapeFactory::parseSphere(Poco::XML::Element *pElem, std::map<int, std::shared_ptr<Surface>> &prim,
345 int &l_id) {
346 Element *pElemCentre = getOptionalShapeElement(pElem, "centre");
347 Element *pElemRadius = getShapeElement(pElem, "radius");
348 const double radius = getDoubleAttribute(pElemRadius, "val");
349 V3D centre = pElemCentre ? parsePosition(pElemCentre) : DEFAULT_CENTRE;
350
351 // Only rotate the normal vector by the rotate-all and goniometer tags
352 // Special case: do not obey rotate tag as rotation around the centre of sphere is unneccessary
353 if (m_rotateAllMatrix != Kernel::Matrix<double>(3, 3, true)) {
354 // Apply automatic rotation due to the rotate-all tag
356 }
357 if (m_gonioRotateMatrix != Kernel::Matrix<double>(3, 3, true)) {
358 // Apply automatic rotation due to the goniometer that should NOT be manually defined by the user
360 }
361
362 prim[l_id] = std::make_shared<Sphere>(centre, radius);
363 const auto algebra = sphereAlgebra(l_id);
364 l_id++;
365 return algebra;
366}
367
373std::string ShapeFactory::sphereAlgebra(const int surfaceID) { return "(-" + std::to_string(surfaceID) + ")"; }
374
386std::string ShapeFactory::parseInfinitePlane(Poco::XML::Element *pElem, std::map<int, std::shared_ptr<Surface>> &prim,
387 int &l_id) {
388 Element *pElemPip = getShapeElement(pElem, "point-in-plane");
389 Element *pElemNormal = getShapeElement(pElem, "normal-to-plane");
390 Element *pElem_rot = getOptionalShapeElement(pElem, "rotate");
391
392 V3D normVec = normalize(parsePosition(pElemNormal));
393 V3D centre = parsePosition(pElemPip);
394
395 // Rotate the normal vector by the rotate, rotate-all and goniometer tags
396 // Rotate the centre by the rotate-all and goniometer tags
397 if (pElem_rot) {
398 // Apply manual rotation supplied to rotate tag
399 std::vector<double> rotateAngles = DegreesToRadians(parsePosition(pElem_rot));
400 const std::vector<double> rotateMatrix = generateMatrix(rotateAngles[0], rotateAngles[1], rotateAngles[2]);
401 normVec.rotate(rotateMatrix);
402 }
403 if (m_rotateAllMatrix != Kernel::Matrix<double>(3, 3, true)) {
404 // Apply automatic rotation due to the rotate-all tag
406 normVec.rotate(m_rotateAllMatrix);
407 }
408 if (m_gonioRotateMatrix != Kernel::Matrix<double>(3, 3, true)) {
409 // Apply automatic rotation due to the goniometer that should NOT be manually defined by the user
412 }
413
414 // create infinite-plane
415 auto pPlane = std::make_shared<Plane>();
416 pPlane->setPlane(centre, normVec);
417 prim[l_id] = pPlane;
418
419 std::stringstream retAlgebraMatch;
420 retAlgebraMatch << "(" << l_id << ")";
421 l_id++;
422 return retAlgebraMatch.str();
423}
424
436std::string ShapeFactory::parseInfiniteCylinder(Poco::XML::Element *pElem,
437 std::map<int, std::shared_ptr<Surface>> &prim, int &l_id) {
438 Element *pElemCentre = getShapeElement(pElem, "centre");
439 Element *pElemAxis = getShapeElement(pElem, "axis");
440 Element *pElemRadius = getShapeElement(pElem, "radius");
441 Element *pElem_rot = getOptionalShapeElement(pElem, "rotate");
442
443 // getDoubleAttribute can throw - put the calls above any new
444 const double radius = getDoubleAttribute(pElemRadius, "val");
445 V3D normVec = normalize(parsePosition(pElemAxis));
446 V3D centre = parsePosition(pElemCentre);
447
448 // Rotate the normal vector by the rotate, rotate-all and goniometer tags
449 // Rotate the centre by the rotate-all and goniometer tags
450 if (pElem_rot) {
451 // Apply manual rotation supplied to rotate tag
452 std::vector<double> rotateAngles = DegreesToRadians(parsePosition(pElem_rot));
453 const std::vector<double> rotateMatrix = generateMatrix(rotateAngles[0], rotateAngles[1], rotateAngles[2]);
454 normVec.rotate(rotateMatrix);
455 }
456 if (m_rotateAllMatrix != Kernel::Matrix<double>(3, 3, true)) {
457 // Apply automatic rotation due to the rotate-all tag
459 normVec.rotate(m_rotateAllMatrix);
460 }
461 if (m_gonioRotateMatrix != Kernel::Matrix<double>(3, 3, true)) {
462 // Apply automatic rotation due to the goniometer that should NOT be manually defined by the user
465 }
466
467 // create infinite-cylinder
468 auto pCylinder = std::make_shared<Cylinder>();
469 pCylinder->setNorm(normVec);
470 pCylinder->setCentre(centre);
471
472 pCylinder->setRadius(radius);
473 prim[l_id] = pCylinder;
474
475 std::stringstream retAlgebraMatch;
476 retAlgebraMatch << "(-" << l_id << ")";
477 l_id++;
478 return retAlgebraMatch.str();
479}
480
492std::string ShapeFactory::parseCylinder(Poco::XML::Element *pElem, std::map<int, std::shared_ptr<Surface>> &prim,
493 int &l_id) {
494 Element *pElemBase = getShapeElement(pElem, "centre-of-bottom-base");
495 Element *pElemAxis = getShapeElement(pElem, "axis");
496 Element *pElemRadius = getShapeElement(pElem, "radius");
497 Element *pElemHeight = getShapeElement(pElem, "height");
498 Element *pElem_rot = getOptionalShapeElement(pElem, "rotate");
499
500 V3D normVec = normalize(parsePosition(pElemAxis));
501
502 // getDoubleAttribute can throw - put the calls above any new
503 const double radius = getDoubleAttribute(pElemRadius, "val");
504 const double height = getDoubleAttribute(pElemHeight, "val");
505
506 // add infinite cylinder
507 auto pCylinder = std::make_shared<Cylinder>();
508 V3D centreOfBottomBase = parsePosition(pElemBase);
509 V3D centre = centreOfBottomBase + normVec * (0.5 * height);
510 pCylinder->setRadius(radius);
511
512 // Rotate the normal vector by the rotate, rotate-all and goniometer tags
513 // Rotate the centre by the rotate-all and goniometer tags
514 if (pElem_rot) {
515 // Apply manual rotation supplied to rotate tag
516 std::vector<double> rotateAngles = DegreesToRadians(parsePosition(pElem_rot));
517 const std::vector<double> rotateMatrix = generateMatrix(rotateAngles[0], rotateAngles[1], rotateAngles[2]);
518 normVec.rotate(rotateMatrix);
519 }
520 if (m_rotateAllMatrix != Kernel::Matrix<double>(3, 3, true)) {
521 // Apply automatic rotation due to the rotate-all tag
523 normVec.rotate(m_rotateAllMatrix);
524 }
525 if (m_gonioRotateMatrix != Kernel::Matrix<double>(3, 3, true)) {
526 // Apply automatic rotation due to the goniometer that should NOT be manually defined by the user
529 }
530
531 pCylinder->setNorm(normVec);
532 pCylinder->setCentre(centre);
533
534 prim[l_id] = pCylinder;
535 std::stringstream retAlgebraMatch;
536 retAlgebraMatch << "(-" << l_id << " ";
537 l_id++;
538
539 // add top plane
540 auto pPlaneTop = std::make_shared<Plane>();
541 // to get point in top plane
542 V3D pointInPlaneTop = centre + (normVec * height * 0.5);
543 pPlaneTop->setPlane(pointInPlaneTop, normVec);
544 prim[l_id] = pPlaneTop;
545 retAlgebraMatch << "-" << l_id << " ";
546 l_id++;
547
548 // add bottom plane
549 auto pPlaneBottom = std::make_shared<Plane>();
550 V3D pointInPlaneBottom = centre - (normVec * height * 0.5);
551 pPlaneBottom->setPlane(pointInPlaneBottom, normVec);
552 prim[l_id] = pPlaneBottom;
553 retAlgebraMatch << "" << l_id << ")";
554 l_id++;
555
556 return retAlgebraMatch.str();
557}
558
571std::string ShapeFactory::parseHollowCylinder(Poco::XML::Element *pElem, std::map<int, std::shared_ptr<Surface>> &prim,
572 int &l_id) {
573 Element *pElemBase = getShapeElement(pElem, "centre-of-bottom-base");
574 Element *pElemAxis = getShapeElement(pElem, "axis");
575 Element *pElemInnerRadius = getShapeElement(pElem, "inner-radius");
576 Element *pElemOuterRadius = getShapeElement(pElem, "outer-radius");
577 Element *pElemHeight = getShapeElement(pElem, "height");
578 Element *pElem_rot = getOptionalShapeElement(pElem, "rotate");
579
580 const double innerRadius = getDoubleAttribute(pElemInnerRadius, "val");
581 if (innerRadius <= 0.0) {
582 throw std::runtime_error("ShapeFactory::parseHollowCylinder(): inner-radius < 0.0");
583 }
584 const double outerRadius = getDoubleAttribute(pElemOuterRadius, "val");
585 if (outerRadius <= 0.0) {
586 throw std::runtime_error("ShapeFactory::parseHollowCylinder(): outer-radius < 0.0");
587 }
588 if (innerRadius > outerRadius) {
589 throw std::runtime_error("ShapeFactory::parseHollowCylinder(): inner-radius > outer-radius.");
590 }
591 const double height = getDoubleAttribute(pElemHeight, "val");
592 if (height <= 0.0) {
593 throw std::runtime_error("ShapeFactory::parseHollowCylinder(): height < 0.0");
594 }
595 V3D centreOfBottomBase = parsePosition(pElemBase);
596 V3D normVec = normalize(parsePosition(pElemAxis));
597 V3D centre = centreOfBottomBase + normVec * (0.5 * height);
598
599 // Rotate the normal vector by the rotate, rotate-all and goniometer tags
600 // Rotate the centre by the rotate-all and goniometer tags
601 if (pElem_rot) {
602 // Apply manual rotation supplied to rotate tag
603 std::vector<double> rotateAngles = DegreesToRadians(parsePosition(pElem_rot));
604 const std::vector<double> rotateMatrix = generateMatrix(rotateAngles[0], rotateAngles[1], rotateAngles[2]);
605 normVec.rotate(rotateMatrix);
606 }
607 if (m_rotateAllMatrix != Kernel::Matrix<double>(3, 3, true)) {
608 // Apply automatic rotation due to the rotate-all tag
610 normVec.rotate(m_rotateAllMatrix);
611 }
612 if (m_gonioRotateMatrix != Kernel::Matrix<double>(3, 3, true)) {
613 // Apply automatic rotation due to the goniometer that should NOT be manually defined by the user
616 }
617
618 // add outer infinite cylinder surface
619 auto outerCylinder = std::make_shared<Cylinder>();
620 outerCylinder->setCentre(centre);
621 outerCylinder->setNorm(normVec);
622 outerCylinder->setRadius(outerRadius);
623 prim[l_id] = outerCylinder;
624
625 std::stringstream retAlgebraMatch;
626 retAlgebraMatch << "(-" << l_id << " ";
627 l_id++;
628
629 // add inner infinite cylinder surface
630 auto innerCylinder = std::make_shared<Cylinder>();
631 innerCylinder->setCentre(centre);
632 innerCylinder->setNorm(normVec);
633 innerCylinder->setRadius(innerRadius);
634 prim[l_id] = innerCylinder;
635 retAlgebraMatch << l_id << " ";
636 l_id++;
637
638 // add top plane
639 auto pPlaneTop = std::make_shared<Plane>();
640 // to get point in top plane
641 V3D pointInPlaneTop = centre + (normVec * height * 0.5);
642 pPlaneTop->setPlane(pointInPlaneTop, normVec);
643 prim[l_id] = pPlaneTop;
644 retAlgebraMatch << "-" << l_id << " ";
645 l_id++;
646
647 // add bottom plane
648 auto pPlaneBottom = std::make_shared<Plane>();
649 V3D pointInPlaneBottom = centre - (normVec * height * 0.5);
650 pPlaneBottom->setPlane(pointInPlaneBottom, normVec);
651 prim[l_id] = pPlaneBottom;
652 retAlgebraMatch << "" << l_id << ")";
653 l_id++;
654
655 return retAlgebraMatch.str();
656}
657
667CuboidCorners ShapeFactory::parseCuboid(Poco::XML::Element *pElem) {
668 // Users have two syntax options when defining cuboids:
669
670 // A - "Point" syntax.
671 Element *pElem_lfb = getOptionalShapeElement(pElem, "left-front-bottom-point");
672 Element *pElem_lft = getOptionalShapeElement(pElem, "left-front-top-point");
673 Element *pElem_lbb = getOptionalShapeElement(pElem, "left-back-bottom-point");
674 Element *pElem_rfb = getOptionalShapeElement(pElem, "right-front-bottom-point");
675
676 // B - "Alternate" syntax.
677 Element *pElem_height = getOptionalShapeElement(pElem, "height");
678 Element *pElem_width = getOptionalShapeElement(pElem, "width");
679 Element *pElem_depth = getOptionalShapeElement(pElem, "depth");
680 Element *pElem_centre = getOptionalShapeElement(pElem, "centre");
681 Element *pElem_axis = getOptionalShapeElement(pElem, "axis");
682 Element *pElem_rot = getOptionalShapeElement(pElem, "rotate");
683
684 const bool usingPointSyntax = pElem_lfb && pElem_lft && pElem_lbb && pElem_rfb;
685 const bool usingAlternateSyntax = pElem_height && pElem_width && pElem_depth;
686
687 const bool usedPointSyntaxField = pElem_lfb || pElem_lft || pElem_lbb || pElem_rfb;
688 const bool usedAlternateSyntaxField =
689 pElem_height || pElem_width || pElem_depth || pElem_centre || pElem_axis || pElem_rot;
690
691 const std::string SYNTAX_ERROR_MSG = "XML element: <" + pElem->tagName() +
692 "> may contain EITHER corner points (LFB, LFT, LBB and RFB) OR " +
693 "height, width, depth, centre and axis values.";
694
695 CuboidCorners result;
696
697 if (usingPointSyntax && !usingAlternateSyntax) {
698 if (usedAlternateSyntaxField)
699 throw std::invalid_argument(SYNTAX_ERROR_MSG);
700
701 result.lfb = parsePosition(pElem_lfb);
702 result.lft = parsePosition(pElem_lft);
703 result.lbb = parsePosition(pElem_lbb);
704 result.rfb = parsePosition(pElem_rfb);
705 } else if (usingAlternateSyntax && !usingPointSyntax) {
706 if (usedPointSyntaxField)
707 throw std::invalid_argument(SYNTAX_ERROR_MSG);
708
709 const double deltaH = getDoubleAttribute(pElem_height, "val") / 2;
710 const double deltaW = getDoubleAttribute(pElem_width, "val") / 2;
711 const double deltaD = getDoubleAttribute(pElem_depth, "val") / 2;
712
713 V3D centre = pElem_centre ? parsePosition(pElem_centre) : DEFAULT_CENTRE;
714
715 result.lfb = V3D(-deltaW, -deltaH, -deltaD);
716 result.lft = V3D(-deltaW, deltaH, -deltaD);
717 result.lbb = V3D(-deltaW, -deltaH, deltaD);
718 result.rfb = V3D(deltaW, -deltaH, -deltaD);
719
720 if (pElem_axis) {
721 // Use a quarternion to do a rotate for us, with respect to the default
722 // axis. Our "Quat" implementation requires that the vectors passed to
723 // it be normalised.
724 const V3D axis = normalize(parsePosition(pElem_axis));
725 const Quat rotate(DEFAULT_AXIS, axis);
726
727 rotate.rotate(result.lfb);
728 rotate.rotate(result.lft);
729 rotate.rotate(result.lbb);
730 rotate.rotate(result.rfb);
731 }
732
733 // Rotate the points by the rotate, rotate-all and goniometer tags
734 // Rotate the centre by the rotate-all and goniometer tags
735 if (pElem_rot) {
736 // Apply manual rotation supplied to rotate tag
737 std::vector<double> rotateAngles = DegreesToRadians(parsePosition(pElem_rot));
738 const std::vector<double> rotateMatrix = generateMatrix(rotateAngles[0], rotateAngles[1], rotateAngles[2]);
739 result.rotatePoints(rotateMatrix);
740 }
741 if (m_rotateAllMatrix != Kernel::Matrix<double>(3, 3, true)) {
742 // Apply automatic rotation due to the rotate-all tag
745 }
746 if (m_gonioRotateMatrix != Kernel::Matrix<double>(3, 3, true)) {
747 // Apply automatic rotation due to the goniometer that should NOT be manually defined by the user
750 }
751
752 result.lfb += centre;
753 result.lft += centre;
754 result.lbb += centre;
755 result.rfb += centre;
756 } else {
757 throw std::invalid_argument(SYNTAX_ERROR_MSG);
758 }
759
760 return result;
761}
762
774std::string ShapeFactory::parseCuboid(Poco::XML::Element *pElem, std::map<int, std::shared_ptr<Surface>> &prim,
775 int &l_id) {
776 auto corners = parseCuboid(pElem);
777
778 const V3D pointTowardBack = normalize(corners.lbb - corners.lfb);
779
780 // add front plane cutoff
781 auto pPlaneFrontCutoff = std::make_shared<Plane>();
782 try {
783 pPlaneFrontCutoff->setPlane(corners.lfb, pointTowardBack);
784 } catch (std::invalid_argument &) {
785 throw;
786 }
787 prim[l_id] = pPlaneFrontCutoff;
788
789 std::stringstream retAlgebraMatch;
790 retAlgebraMatch << "(" << l_id << " ";
791 l_id++;
792
793 // add back plane cutoff
794 auto pPlaneBackCutoff = std::make_shared<Plane>();
795 try {
796 pPlaneBackCutoff->setPlane(corners.lbb, pointTowardBack);
797 } catch (std::invalid_argument &) {
798 throw;
799 }
800 prim[l_id] = pPlaneBackCutoff;
801 retAlgebraMatch << "-" << l_id << " ";
802 l_id++;
803
804 const V3D pointTowardRight = normalize(corners.rfb - corners.lfb);
805
806 // add left plane cutoff
807 auto pPlaneLeftCutoff = std::make_shared<Plane>();
808 try {
809 pPlaneLeftCutoff->setPlane(corners.lfb, pointTowardRight);
810 } catch (std::invalid_argument &) {
811 throw;
812 }
813 prim[l_id] = pPlaneLeftCutoff;
814 retAlgebraMatch << "" << l_id << " ";
815 l_id++;
816
817 // add right plane cutoff
818 auto pPlaneRightCutoff = std::make_shared<Plane>();
819 try {
820 pPlaneRightCutoff->setPlane(corners.rfb, pointTowardRight);
821 } catch (std::invalid_argument &) {
822 throw;
823 }
824 prim[l_id] = pPlaneRightCutoff;
825 retAlgebraMatch << "-" << l_id << " ";
826 l_id++;
827
828 const V3D pointTowardTop = normalize(corners.lft - corners.lfb);
829
830 // add bottom plane cutoff
831 auto pPlaneBottomCutoff = std::make_shared<Plane>();
832 try {
833 pPlaneBottomCutoff->setPlane(corners.lfb, pointTowardTop);
834 } catch (std::invalid_argument &) {
835 throw;
836 }
837 prim[l_id] = pPlaneBottomCutoff;
838 retAlgebraMatch << "" << l_id << " ";
839 l_id++;
840
841 // add top plane cutoff
842 auto pPlaneTopCutoff = std::make_shared<Plane>();
843 try {
844 pPlaneTopCutoff->setPlane(corners.lft, pointTowardTop);
845 } catch (std::invalid_argument &) {
846 throw;
847 }
848 prim[l_id] = pPlaneTopCutoff;
849 retAlgebraMatch << "-" << l_id << ")";
850 l_id++;
851
852 return retAlgebraMatch.str();
853}
854
866std::string ShapeFactory::parseInfiniteCone(Poco::XML::Element *pElem, std::map<int, std::shared_ptr<Surface>> &prim,
867 int &l_id) {
868 Element *pElemTipPoint = getShapeElement(pElem, "tip-point");
869 Element *pElemAxis = getShapeElement(pElem, "axis");
870 Element *pElemAngle = getShapeElement(pElem, "angle");
871
872 const V3D normVec = normalize(parsePosition(pElemAxis));
873
874 // getDoubleAttribute can throw - put the calls above any new
875 const double angle = getDoubleAttribute(pElemAngle, "val");
876
877 // add infinite double cone
878 auto pCone = std::make_shared<Cone>();
879 pCone->setCentre(parsePosition(pElemTipPoint));
880 pCone->setNorm(normVec);
881 pCone->setAngle(angle);
882 prim[l_id] = pCone;
883
884 std::stringstream retAlgebraMatch;
885 retAlgebraMatch << "(" << l_id << " ";
886 l_id++;
887
888 // plane top cut of top part of double cone
889 auto pPlaneBottom = std::make_shared<Plane>();
890 pPlaneBottom->setPlane(parsePosition(pElemTipPoint), normVec);
891 prim[l_id] = pPlaneBottom;
892 retAlgebraMatch << "-" << l_id << ")";
893 l_id++;
894
895 return retAlgebraMatch.str();
896}
897
909std::string ShapeFactory::parseCone(Poco::XML::Element *pElem, std::map<int, std::shared_ptr<Surface>> &prim,
910 int &l_id) {
911 Element *pElemTipPoint = getShapeElement(pElem, "tip-point");
912 Element *pElemAxis = getShapeElement(pElem, "axis");
913 Element *pElemAngle = getShapeElement(pElem, "angle");
914 Element *pElemHeight = getShapeElement(pElem, "height");
915
916 const V3D normVec = normalize(parsePosition(pElemAxis));
917
918 // getDoubleAttribute can throw - put the calls above any new
919 const double angle = getDoubleAttribute(pElemAngle, "val");
920 const double height = getDoubleAttribute(pElemHeight, "val");
921
922 // add infinite double cone
923 auto pCone = std::make_shared<Cone>();
924 pCone->setCentre(parsePosition(pElemTipPoint));
925 pCone->setNorm(normVec);
926 pCone->setAngle(angle);
927 prim[l_id] = pCone;
928
929 std::stringstream retAlgebraMatch;
930 retAlgebraMatch << "(" << l_id << " ";
931 l_id++;
932
933 // Plane to cut off cone from below
934 auto pPlaneTop = std::make_shared<Plane>();
935 V3D pointInPlane = parsePosition(pElemTipPoint);
936 pointInPlane -= (normVec * height);
937 pPlaneTop->setPlane(pointInPlane, normVec);
938 prim[l_id] = pPlaneTop;
939 retAlgebraMatch << "" << l_id << " ";
940 l_id++;
941
942 // plane top cut of top part of double cone
943 auto pPlaneBottom = std::make_shared<Plane>();
944 pPlaneBottom->setPlane(parsePosition(pElemTipPoint), normVec);
945 prim[l_id] = pPlaneBottom;
946 retAlgebraMatch << "-" << l_id << ")";
947 l_id++;
948
949 return retAlgebraMatch.str();
950}
951
959 std::map<int, std::shared_ptr<Surface>> &prim, int &l_id) {
960 // add front face
961 auto pPlaneFrontCutoff = std::make_shared<Plane>();
962 auto normal = (hex.rfb - hex.lfb).cross_prod(hex.lft - hex.lfb);
963
964 // V3D jjj = (normal*(rfb-rbb));
965 if (normal.scalar_prod(hex.rfb - hex.rbb) < 0)
966 normal *= -1.0;
967 pPlaneFrontCutoff->setPlane(hex.lfb, normal);
968 prim[l_id] = pPlaneFrontCutoff;
969 std::stringstream retAlgebraMatch;
970 retAlgebraMatch << "(-" << l_id << " ";
971 l_id++;
972
973 // add back face
974 auto pPlaneBackCutoff = std::make_shared<Plane>();
975 normal = (hex.rbb - hex.lbb).cross_prod(hex.lbt - hex.lbb);
976 if (normal.scalar_prod(hex.rfb - hex.rbb) < 0)
977 normal *= -1.0;
978 pPlaneBackCutoff->setPlane(hex.lbb, normal);
979 prim[l_id] = pPlaneBackCutoff;
980 retAlgebraMatch << "" << l_id << " ";
981 l_id++;
982
983 // add left face
984 auto pPlaneLeftCutoff = std::make_shared<Plane>();
985 normal = (hex.lbb - hex.lfb).cross_prod(hex.lft - hex.lfb);
986 if (normal.scalar_prod(hex.rfb - hex.lfb) < 0)
987 normal *= -1.0;
988 pPlaneLeftCutoff->setPlane(hex.lfb, normal);
989 prim[l_id] = pPlaneLeftCutoff;
990 retAlgebraMatch << "" << l_id << " ";
991 l_id++;
992
993 // add right face
994 auto pPlaneRightCutoff = std::make_shared<Plane>();
995 normal = (hex.rbb - hex.rfb).cross_prod(hex.rft - hex.rfb);
996 if (normal.scalar_prod(hex.rfb - hex.lfb) < 0)
997 normal *= -1.0;
998 pPlaneRightCutoff->setPlane(hex.rfb, normal);
999 prim[l_id] = pPlaneRightCutoff;
1000 retAlgebraMatch << "-" << l_id << " ";
1001 l_id++;
1002
1003 // add top face
1004 auto pPlaneTopCutoff = std::make_shared<Plane>();
1005 normal = (hex.rft - hex.lft).cross_prod(hex.lbt - hex.lft);
1006 if (normal.scalar_prod(hex.rft - hex.rfb) < 0)
1007 normal *= -1.0;
1008 pPlaneTopCutoff->setPlane(hex.lft, normal);
1009 prim[l_id] = pPlaneTopCutoff;
1010 retAlgebraMatch << "-" << l_id << " ";
1011 l_id++;
1012
1013 // add bottom face
1014 auto pPlaneBottomCutoff = std::make_shared<Plane>();
1015 normal = (hex.rfb - hex.lfb).cross_prod(hex.lbb - hex.lfb);
1016 if (normal.scalar_prod(hex.rft - hex.rfb) < 0)
1017 normal *= -1.0;
1018 pPlaneBottomCutoff->setPlane(hex.lfb, normal);
1019 prim[l_id] = pPlaneBottomCutoff;
1020 retAlgebraMatch << "" << l_id << ")";
1021 l_id++;
1022
1023 return retAlgebraMatch.str();
1024}
1025
1034Hexahedron ShapeFactory::parseHexahedron(Poco::XML::Element *pElem) {
1035 Element *pElem_lfb = getShapeElement(pElem, "left-front-bottom-point");
1036 Element *pElem_lft = getShapeElement(pElem, "left-front-top-point");
1037 Element *pElem_lbb = getShapeElement(pElem, "left-back-bottom-point");
1038 Element *pElem_lbt = getShapeElement(pElem, "left-back-top-point");
1039 Element *pElem_rfb = getShapeElement(pElem, "right-front-bottom-point");
1040 Element *pElem_rft = getShapeElement(pElem, "right-front-top-point");
1041 Element *pElem_rbb = getShapeElement(pElem, "right-back-bottom-point");
1042 Element *pElem_rbt = getShapeElement(pElem, "right-back-top-point");
1043 Element *pElem_rot = getOptionalShapeElement(pElem, "rotate");
1044
1045 const bool isValid =
1046 pElem_lfb && pElem_lft && pElem_lbb && pElem_lbt && pElem_rfb && pElem_rft && pElem_rbb && pElem_rbt;
1047
1048 std::ostringstream ERROR_MSG;
1049 ERROR_MSG << "XML element: <" + pElem->tagName() + ""
1050 << "> contains invalid syntax for defining hexahedron. The "
1051 "following points have not been defined:\n\n";
1052
1053 if (!pElem_lfb)
1054 ERROR_MSG << "left-front-bottom-point\n";
1055 if (!pElem_lft)
1056 ERROR_MSG << "left-front-top-point\n";
1057 if (!pElem_lbb)
1058 ERROR_MSG << "left-back-bottom-point\n";
1059 if (!pElem_lbt)
1060 ERROR_MSG << "left-back-top-point\n";
1061 if (!pElem_rfb)
1062 ERROR_MSG << "right-front-bottom-point\n";
1063 if (!pElem_rft)
1064 ERROR_MSG << "right-front-top-point\n";
1065 if (!pElem_rbb)
1066 ERROR_MSG << "right-back-bottom-point\n";
1067 if (!pElem_rbt)
1068 ERROR_MSG << "right-back-top-point\n";
1069
1070 if (!isValid)
1071 throw std::invalid_argument(ERROR_MSG.str());
1072
1073 Hexahedron hex;
1074 hex.lfb = parsePosition(pElem_lfb);
1075 hex.lft = parsePosition(pElem_lft);
1076 hex.lbb = parsePosition(pElem_lbb);
1077 hex.lbt = parsePosition(pElem_lbt);
1078 hex.rfb = parsePosition(pElem_rfb);
1079 hex.rft = parsePosition(pElem_rft);
1080 hex.rbb = parsePosition(pElem_rbb);
1081 hex.rbt = parsePosition(pElem_rbt);
1082
1083 // Rotate the points by the rotate, rotate-all and goniometer tags
1084 if (pElem_rot) {
1085 // Apply manual rotation supplied to rotate tag
1086 std::vector<double> rotateAngles = DegreesToRadians(parsePosition(pElem_rot));
1087 const std::vector<double> rotateMatrix = generateMatrix(rotateAngles[0], rotateAngles[1], rotateAngles[2]);
1088 hex.rotatePoints(rotateMatrix);
1089 }
1090 if (m_rotateAllMatrix != Kernel::Matrix<double>(3, 3, true)) {
1091 // Apply automatic rotation due to the rotate-all tag
1093 }
1094 if (m_gonioRotateMatrix != Kernel::Matrix<double>(3, 3, true)) {
1095 // Apply automatic rotation due to the goniometer that should NOT be manually defined by the user
1097 }
1098
1099 return hex;
1100}
1101
1113std::string ShapeFactory::parseHexahedron(Poco::XML::Element *pElem, std::map<int, std::shared_ptr<Surface>> &prim,
1114 int &l_id) {
1115 Hexahedron hex = parseHexahedron(pElem);
1116
1117 return parseHexahedronFromStruct(hex, prim, l_id);
1118}
1119
1132std::string ShapeFactory::parseTaperedGuide(Poco::XML::Element *pElem, std::map<int, std::shared_ptr<Surface>> &prim,
1133 int &l_id) {
1134 Element *pElemApertureStart = getShapeElement(pElem, "aperture-start");
1135 Element *pElemLength = getShapeElement(pElem, "length");
1136 Element *pElemApertureEnd = getShapeElement(pElem, "aperture-end");
1137 Element *pElemCentre = getOptionalShapeElement(pElem, "centre");
1138 Element *pElemAxis = getOptionalShapeElement(pElem, "axis");
1139 Element *pElem_rot = getOptionalShapeElement(pElem, "rotate");
1140
1141 // For centre and axis we allow defaults.
1142 V3D centre = pElemCentre ? parsePosition(pElemCentre) : DEFAULT_CENTRE;
1143 // Quat requires normalised axes.
1144 const V3D axis = normalize(pElemAxis ? parsePosition(pElemAxis) : DEFAULT_AXIS);
1145
1146 const double apertureStartWidth = getDoubleAttribute(pElemApertureStart, "width");
1147 const double apertureStartHeight = getDoubleAttribute(pElemApertureStart, "height");
1148 const double length = getDoubleAttribute(pElemLength, "val");
1149 const double apertureEndWidth = getDoubleAttribute(pElemApertureEnd, "width");
1150 const double apertureEndHeight = getDoubleAttribute(pElemApertureEnd, "height");
1151
1152 const double halfSW = apertureStartWidth / 2;
1153 const double halfSH = apertureStartHeight / 2;
1154 const double halfEW = apertureEndWidth / 2;
1155 const double halfEH = apertureEndHeight / 2;
1156
1157 // Build the basic shape.
1158 Hexahedron hex;
1159 hex.lfb = V3D(-halfSW, -halfSH, 0);
1160 hex.lft = V3D(-halfSW, halfSH, 0);
1161 hex.lbb = V3D(-halfEW, -halfEH, length);
1162 hex.lbt = V3D(-halfEW, halfEH, length);
1163 hex.rfb = V3D(halfSW, -halfSH, 0);
1164 hex.rft = V3D(halfSW, halfSH, 0);
1165 hex.rbb = V3D(halfEW, -halfEH, length);
1166 hex.rbt = V3D(halfEW, halfEH, length);
1167
1168 // Point it along the defined axis.
1169 if (axis != DEFAULT_AXIS) {
1170 const Quat q(DEFAULT_AXIS, axis);
1171
1172 q.rotate(hex.lfb);
1173 q.rotate(hex.lft);
1174 q.rotate(hex.lbb);
1175 q.rotate(hex.lbt);
1176 q.rotate(hex.rfb);
1177 q.rotate(hex.rft);
1178 q.rotate(hex.rbb);
1179 q.rotate(hex.rbt);
1180 }
1181
1182 // Rotate the points by the rotate, rotate-all and goniometer tags
1183 if (pElem_rot) {
1184 // Apply manual rotation supplied to rotate tag
1185 std::vector<double> rotateAngles = DegreesToRadians(parsePosition(pElem_rot));
1186 const std::vector<double> rotateMatrix = generateMatrix(rotateAngles[0], rotateAngles[1], rotateAngles[2]);
1187 hex.rotatePoints(rotateMatrix);
1188 }
1189 if (m_rotateAllMatrix != Kernel::Matrix<double>(3, 3, true)) {
1190 // Apply automatic rotation due to the rotate-all tag
1192 centre.rotate(m_rotateAllMatrix);
1193 }
1194 if (m_gonioRotateMatrix != Kernel::Matrix<double>(3, 3, true)) {
1195 // Apply automatic rotation due to the goniometer that should NOT be manually defined by the user
1198 }
1199
1200 // Move it to the defined centre.
1201 hex.lfb += centre;
1202 hex.lft += centre;
1203 hex.lbb += centre;
1204 hex.lbt += centre;
1205 hex.rfb += centre;
1206 hex.rft += centre;
1207 hex.rbb += centre;
1208 hex.rbt += centre;
1209
1210 return parseHexahedronFromStruct(hex, prim, l_id);
1211}
1212
1224std::string ShapeFactory::parseTorus(Poco::XML::Element *pElem, std::map<int, std::shared_ptr<Surface>> &prim,
1225 int &l_id) {
1226 Element *pElemCentre = getShapeElement(pElem, "centre");
1227 Element *pElemAxis = getShapeElement(pElem, "axis");
1228 Element *pElemRadiusFromCentre = getShapeElement(pElem, "radius-from-centre-to-tube");
1229 Element *pElemRadiusTube = getShapeElement(pElem, "radius-tube");
1230
1231 const V3D normVec = normalize(parsePosition(pElemAxis));
1232
1233 // getDoubleAttribute can throw - put the calls above any new
1234 const double radiusCentre = getDoubleAttribute(pElemRadiusFromCentre, "val");
1235 const double radiusTube = getDoubleAttribute(pElemRadiusTube, "val");
1236
1237 // add torus
1238 auto pTorus = std::make_shared<Torus>();
1239 pTorus->setCentre(parsePosition(pElemCentre));
1240 pTorus->setNorm(normVec);
1241 pTorus->setDistanceFromCentreToTube(radiusCentre);
1242 pTorus->setTubeRadius(radiusTube);
1243 prim[l_id] = pTorus;
1244
1245 std::stringstream retAlgebraMatch;
1246 retAlgebraMatch << "(-" << l_id << ")";
1247 l_id++;
1248
1249 return retAlgebraMatch.str();
1250}
1251
1264std::string ShapeFactory::parseSliceOfCylinderRing(Poco::XML::Element *pElem,
1265 std::map<int, std::shared_ptr<Surface>> &prim, int &l_id) {
1266 Element *pElemArc = getShapeElement(pElem, "arc");
1267 Element *pElemInnerRadius = getShapeElement(pElem, "inner-radius");
1268 Element *pElemOuterRadius = getShapeElement(pElem, "outer-radius");
1269 Element *pElemDepth = getShapeElement(pElem, "depth");
1270 Element *pElem_rot = getOptionalShapeElement(pElem, "rotate");
1271
1272 const double outerRadius = getDoubleAttribute(pElemOuterRadius, "val");
1273 double innerRadius = getDoubleAttribute(pElemInnerRadius, "val");
1274 if (innerRadius <= 0.0) {
1275 innerRadius = outerRadius / 1000;
1276 g_log.warning() << "ShapeFactory::parseSliceOfCylinderRing(): inner-radius cannot be < 0.0 or = 0.0, so has been "
1277 "automatically set.";
1278 }
1279 const double middleRadius = (outerRadius + innerRadius) / 2.0;
1280 const double depth = getDoubleAttribute(pElemDepth, "val");
1281 const double arc = (M_PI / 180.0) * getDoubleAttribute(pElemArc, "val");
1282
1283 V3D normVec(0, 0, 1);
1284 V3D centrePoint(-middleRadius, 0, 0);
1285 V3D planeSlice1 = V3D(cos(arc / 2.0 + M_PI / 2.0), sin(arc / 2.0 + M_PI / 2.0), 0);
1286 V3D planeSlice2 = V3D(cos(-arc / 2.0 + M_PI / 2.0), sin(-arc / 2.0 + M_PI / 2.0), 0);
1287
1288 // Rotate the normal vector and both place slices by the rotate, rotate-all and goniometer tags
1289 // Rotate the centre by the rotate-all and goniometer tags
1290 if (pElem_rot) {
1291 // Apply manual rotation supplied to rotate tag
1292 std::vector<double> rotateAngles = DegreesToRadians(parsePosition(pElem_rot));
1293 const std::vector<double> rotateMatrix = generateMatrix(rotateAngles[0], rotateAngles[1], rotateAngles[2]);
1294 normVec.rotate(rotateMatrix);
1295 planeSlice1.rotate(rotateMatrix);
1296 planeSlice2.rotate(rotateMatrix);
1297 }
1298 if (m_rotateAllMatrix != Kernel::Matrix<double>(3, 3, true)) {
1299 // Apply automatic rotation due to the rotate-all tag
1300 normVec.rotate(m_rotateAllMatrix);
1301 planeSlice1.rotate(m_rotateAllMatrix);
1302 planeSlice2.rotate(m_rotateAllMatrix);
1303 centrePoint.rotate(m_rotateAllMatrix);
1304 }
1305 if (m_gonioRotateMatrix != Kernel::Matrix<double>(3, 3, true)) {
1306 // Apply automatic rotation due to the goniometer that should NOT be manually defined by the user
1307 normVec.rotate(m_gonioRotateMatrix);
1308 planeSlice1.rotate(m_gonioRotateMatrix);
1309 planeSlice2.rotate(m_gonioRotateMatrix);
1310 centrePoint.rotate(m_gonioRotateMatrix);
1311 }
1312
1313 // add inner infinite cylinder
1314 auto pCylinder1 = std::make_shared<Cylinder>();
1315 pCylinder1->setCentre(centrePoint);
1316 pCylinder1->setNorm(normVec);
1317 pCylinder1->setRadius(innerRadius);
1318 prim[l_id] = pCylinder1;
1319 std::stringstream retAlgebraMatch;
1320 retAlgebraMatch << "(" << l_id << " ";
1321 l_id++;
1322
1323 // add outer infinite cylinder
1324 auto pCylinder2 = std::make_shared<Cylinder>();
1325 pCylinder2->setCentre(centrePoint);
1326 pCylinder2->setNorm(normVec);
1327 pCylinder2->setRadius(outerRadius);
1328 prim[l_id] = pCylinder2;
1329 retAlgebraMatch << "-" << l_id << " ";
1330 l_id++;
1331
1332 // add top cutoff plane of infinite cylinder ring
1333 auto pPlaneTop = std::make_shared<Plane>();
1334 V3D pointInPlaneTop = centrePoint + (normVec * depth * 0.5);
1335 pPlaneTop->setPlane(pointInPlaneTop, normVec);
1336 prim[l_id] = pPlaneTop;
1337 retAlgebraMatch << "-" << l_id << " ";
1338 l_id++;
1339
1340 // add bottom cutoff plane (which is assumed to face the sample)
1341 // which at this point will result in a cylinder ring
1342 auto pPlaneBottom = std::make_shared<Plane>();
1343 V3D pointInPlaneBottom = centrePoint - (normVec * depth * 0.5);
1344 pPlaneBottom->setPlane(pointInPlaneBottom, normVec);
1345 prim[l_id] = pPlaneBottom;
1346 retAlgebraMatch << "" << l_id << " ";
1347 l_id++;
1348
1349 // the two planes that are going to cut a slice of the cylinder ring
1350
1351 auto pPlaneSlice1 = std::make_shared<Plane>();
1352 pPlaneSlice1->setPlane(centrePoint, planeSlice1);
1353 prim[l_id] = pPlaneSlice1;
1354 retAlgebraMatch << "-" << l_id << " ";
1355 l_id++;
1356
1357 auto pPlaneSlice2 = std::make_shared<Plane>();
1358 pPlaneSlice2->setPlane(centrePoint, planeSlice2);
1359 prim[l_id] = pPlaneSlice2;
1360 retAlgebraMatch << "" << l_id << ")";
1361 l_id++;
1362
1363 return retAlgebraMatch.str();
1364}
1365
1376Poco::XML::Element *ShapeFactory::getShapeElement(Poco::XML::Element *pElem, const std::string &name) {
1377 // check if this shape element contain an element with name specified by the
1378 // 2nd function argument
1379 Poco::AutoPtr<NodeList> pNL = pElem->getElementsByTagName(name);
1380 if (pNL->length() != 1) {
1381 throw std::invalid_argument("XML element: <" + pElem->tagName() +
1382 "> must contain exactly one sub-element with name: <" + name + ">.");
1383 }
1384 auto *retVal = static_cast<Element *>(pNL->item(0));
1385 return retVal;
1386}
1387
1399Poco::XML::Element *ShapeFactory::getOptionalShapeElement(Poco::XML::Element *pElem, const std::string &name) {
1400 // Allow zero or one occurances of subelements with the given name.
1401 Poco::AutoPtr<NodeList> pNL = pElem->getElementsByTagName(name);
1402 if (pNL->length() == 0)
1403 return nullptr;
1404 else if (pNL->length() > 1)
1405 throw std::invalid_argument("XML element: <" + pElem->tagName() +
1406 "> may contain at most one sub-element with name: <" + name + ">.");
1407
1408 auto *retVal = static_cast<Element *>(pNL->item(0));
1409 return retVal;
1410}
1411
1422double ShapeFactory::getDoubleAttribute(Poco::XML::Element *pElem, const std::string &name) {
1423 if (pElem->hasAttribute(name)) {
1424 return std::stod(pElem->getAttribute(name));
1425 } else {
1426 throw std::invalid_argument("XML element: <" + pElem->tagName() + "> does not have the attribute: " + name + ".");
1427 }
1428}
1429
1435V3D ShapeFactory::parsePosition(Poco::XML::Element *pElem) {
1436 V3D retVal;
1437
1438 if (pElem->hasAttribute("R") || pElem->hasAttribute("theta") || pElem->hasAttribute("phi")) {
1439 double R = 0.0, theta = 0.0, phi = 0.0;
1440
1441 if (pElem->hasAttribute("R"))
1442 R = std::stod(pElem->getAttribute("R"));
1443 if (pElem->hasAttribute("theta"))
1444 theta = std::stod(pElem->getAttribute("theta"));
1445 if (pElem->hasAttribute("phi"))
1446 phi = std::stod(pElem->getAttribute("phi"));
1447
1448 retVal.spherical(R, theta, phi);
1449 } else if (pElem->hasAttribute("r") || pElem->hasAttribute("t") || pElem->hasAttribute("p"))
1450 // This is alternative way a user may specify sphecical coordinates
1451 // which may be preferred in the long run to the more verbose of
1452 // using R, theta and phi.
1453 {
1454 double R = 0.0, theta = 0.0, phi = 0.0;
1455
1456 if (pElem->hasAttribute("r"))
1457 R = std::stod(pElem->getAttribute("r"));
1458 if (pElem->hasAttribute("t"))
1459 theta = std::stod(pElem->getAttribute("t"));
1460 if (pElem->hasAttribute("p"))
1461 phi = std::stod(pElem->getAttribute("p"));
1462
1463 retVal.spherical(R, theta, phi);
1464 } else {
1465 double x = 0.0, y = 0.0, z = 0.0;
1466
1467 if (pElem->hasAttribute("x"))
1468 x = std::stod(pElem->getAttribute("x"));
1469 if (pElem->hasAttribute("y"))
1470 y = std::stod(pElem->getAttribute("y"));
1471 if (pElem->hasAttribute("z"))
1472 z = std::stod(pElem->getAttribute("z"));
1473
1474 retVal(x, y, z);
1475 }
1476
1477 return retVal;
1478}
1479
1486std::shared_ptr<CSGObject> ShapeFactory::createSphere(const Kernel::V3D &centre, double radius) {
1487 const int surfaceID = 1;
1488 const std::map<int, std::shared_ptr<Surface>> primitives{{surfaceID, std::make_shared<Sphere>(centre, radius)}};
1489
1490 auto shape = std::make_shared<CSGObject>();
1491 shape->setObject(21, sphereAlgebra(surfaceID));
1492 shape->populate(primitives);
1493
1494 auto handler = std::make_shared<GeometryHandler>(shape);
1495 shape->setGeometryHandler(handler);
1496 detail::ShapeInfo shapeInfo;
1497 shapeInfo.setSphere(centre, radius);
1498 handler->setShapeInfo(std::move(shapeInfo));
1499
1500 shape->defineBoundingBox(radius, radius, radius, -radius, -radius, -radius);
1501 return shape;
1502}
1503
1516std::shared_ptr<CSGObject> ShapeFactory::createHexahedralShape(double xlb, double xlf, double xrf, double xrb,
1517 double ylb, double ylf, double yrf, double yrb) {
1518 Hexahedron hex;
1519 static const double ZDEPTH = 0.001;
1520 hex.lbb = V3D(xlb, ylb, 0);
1521 hex.lbt = V3D(xlb, ylb, ZDEPTH);
1522 hex.lfb = V3D(xlf, ylf, 0);
1523 hex.lft = V3D(xlf, ylf, ZDEPTH);
1524 hex.rbb = V3D(xrb, yrb, 0);
1525 hex.rbt = V3D(xrb, yrb, ZDEPTH);
1526 hex.rfb = V3D(xrf, yrf, 0);
1527 hex.rft = V3D(xrf, yrf, ZDEPTH);
1528
1529 std::map<int, std::shared_ptr<Surface>> prim;
1530 int l_id = 1;
1531 auto algebra = parseHexahedronFromStruct(hex, prim, l_id);
1532
1533 auto shape = std::make_shared<CSGObject>();
1534 shape->setObject(21, algebra);
1535 shape->populate(prim);
1536
1537 auto handler = std::make_shared<GeometryHandler>(shape);
1538 detail::ShapeInfo shapeInfo;
1539 shape->setGeometryHandler(handler);
1540
1541 shapeInfo.setHexahedron(hex.lbb, hex.lfb, hex.rfb, hex.rbb, hex.lbt, hex.lft, hex.rft, hex.rbt);
1542
1543 handler->setShapeInfo(std::move(shapeInfo));
1544
1545 shape->defineBoundingBox(std::max(xrb, xrf), yrf, ZDEPTH, std::min(xlf, xlb), ylb, 0);
1546
1547 return shape;
1548}
1549
1551void ShapeFactory::createGeometryHandler(Poco::XML::Element *pElem, const std::shared_ptr<CSGObject> &Obj) {
1552
1553 auto geomHandler = std::make_shared<GeometryHandler>(Obj);
1554 detail::ShapeInfo shapeInfo;
1555 Obj->setGeometryHandler(geomHandler);
1556
1557 if (pElem->tagName() == "cuboid") {
1558 auto corners = parseCuboid(pElem);
1559 shapeInfo.setCuboid(corners.lfb, corners.lft, corners.lbb, corners.rfb);
1560 } else if (pElem->tagName() == "hexahedron") {
1561 auto corners = parseHexahedron(pElem);
1562 shapeInfo.setHexahedron(corners.lbb, corners.lfb, corners.rfb, corners.rbb, corners.lbt, corners.lft, corners.rft,
1563 corners.rbt);
1564 } else if (pElem->tagName() == "sphere") {
1565 Element *pElemCentre = getOptionalShapeElement(pElem, "centre");
1566 Element *pElemRadius = getShapeElement(pElem, "radius");
1567 V3D centre;
1568 if (pElemCentre)
1569 centre = parsePosition(pElemCentre);
1570 shapeInfo.setSphere(centre, std::stod(pElemRadius->getAttribute("val")));
1571 } else if (pElem->tagName() == "cylinder") {
1572 Element *pElemCentre = getShapeElement(pElem, "centre-of-bottom-base");
1573 Element *pElemAxis = getShapeElement(pElem, "axis");
1574 Element *pElemRadius = getShapeElement(pElem, "radius");
1575 Element *pElemHeight = getShapeElement(pElem, "height");
1576 const V3D normVec = normalize(parsePosition(pElemAxis));
1577 shapeInfo.setCylinder(parsePosition(pElemCentre), normVec, std::stod(pElemRadius->getAttribute("val")),
1578 std::stod(pElemHeight->getAttribute("val")));
1579 } else if (pElem->tagName() == "hollow-cylinder") {
1580 Element *pElemCentre = getShapeElement(pElem, "centre-of-bottom-base");
1581 Element *pElemAxis = getShapeElement(pElem, "axis");
1582 Element *pElemInnerRadius = getShapeElement(pElem, "inner-radius");
1583 Element *pElemOuterRadius = getShapeElement(pElem, "outer-radius");
1584 Element *pElemHeight = getShapeElement(pElem, "height");
1585 V3D normVec = parsePosition(pElemAxis);
1586 normVec.normalize();
1587 shapeInfo.setHollowCylinder(parsePosition(pElemCentre), normVec, std::stod(pElemInnerRadius->getAttribute("val")),
1588 std::stod(pElemOuterRadius->getAttribute("val")),
1589 std::stod(pElemHeight->getAttribute("val")));
1590 } else if (pElem->tagName() == "cone") {
1591 Element *pElemTipPoint = getShapeElement(pElem, "tip-point");
1592 Element *pElemAxis = getShapeElement(pElem, "axis");
1593 Element *pElemAngle = getShapeElement(pElem, "angle");
1594 Element *pElemHeight = getShapeElement(pElem, "height");
1595
1596 const V3D normVec = normalize(parsePosition(pElemAxis));
1597 const double height = std::stod(pElemHeight->getAttribute("val"));
1598 const double radius = height * tan(M_PI * std::stod(pElemAngle->getAttribute("val")) / 180.0);
1599 shapeInfo.setCone(parsePosition(pElemTipPoint), normVec, radius, height);
1600 }
1601
1602 geomHandler->setShapeInfo(std::move(shapeInfo));
1603}
1604
1613Kernel::Matrix<double> ShapeFactory::generateMatrix(double xrotate, double yrotate, double zrotate) {
1614 Kernel::Matrix<double> xMatrix = generateXRotation(xrotate);
1615 Kernel::Matrix<double> yMatrix = generateYRotation(yrotate);
1616 Kernel::Matrix<double> zMatrix = generateZRotation(zrotate);
1617
1618 return zMatrix * yMatrix * xMatrix;
1619}
1620
1627 const double sinX = sin(xrotate);
1628 const double cosX = cos(xrotate);
1629 std::vector<double> matrixList = {1, 0, 0, 0, cosX, -sinX, 0, sinX, cosX};
1630 return Kernel::Matrix<double>(matrixList);
1631}
1632
1639 const double sinY = sin(yrotate);
1640 const double cosY = cos(yrotate);
1641 std::vector<double> matrixList = {cosY, 0, sinY, 0, 1, 0, -sinY, 0, cosY};
1642 return Kernel::Matrix<double>(matrixList);
1643}
1644
1651 const double sinZ = sin(zrotate);
1652 const double cosZ = cos(zrotate);
1653 std::vector<double> matrixList = {cosZ, -sinZ, 0, sinZ, cosZ, 0, 0, 0, 1};
1654 return Kernel::Matrix<double>(matrixList);
1655}
1656
1659 Kernel::Matrix<double> matrix(3, 3, true);
1660 for (size_t i = 0; i < 3; ++i) {
1661 for (size_t j = 0; j < 3; ++j) {
1662 matrix[i][j] = getDoubleAttribute(pElem, "a" + std::to_string(i + 1) + std::to_string(j + 1));
1663 }
1664 }
1665 return matrix;
1666}
1667
1670std::string ShapeFactory::insertMatrixTag(const std::string &tagName, const Kernel::Matrix<double> &matrix,
1671 std::string xml) {
1672 // Keeping the '<' attached is what stops "goniometer" matching inside "<applied-goniometer".
1673 const std::string openTag = "<" + tagName;
1674
1675 // Delete any previous tag of this name. The closing bracket is part of the tag, so erase it too -
1676 // leaving it behind drops a stray '>' into the character data on every rewrite, which is legal
1677 // XML and so goes unnoticed until the tags are rewritten repeatedly.
1678 const std::size_t foundTag = xml.find(openTag);
1679 if (foundTag != std::string::npos) {
1680 xml.erase(foundTag, xml.find(">", foundTag + 1) - foundTag + 1);
1681 }
1682
1683 // Insert before the innermost enclosing end tag, or at the end if there is none
1684 std::size_t tagPlace = xml.find("</type>");
1685 if (tagPlace == std::string::npos) {
1686 tagPlace = xml.find("</samplegeometry");
1687 }
1688 if (tagPlace == std::string::npos) {
1689 tagPlace = xml.size();
1690 }
1691
1692 // Full precision: these matrices are now composed rather than overwritten, so rounding here
1693 // accumulates over repeated CopySample and RotateSampleShape calls.
1694 std::ostringstream tag;
1695 tag << std::setprecision(std::numeric_limits<double>::max_digits10);
1696 tag << " " << openTag << " ";
1697 for (size_t i = 0; i < matrix.numRows(); ++i) {
1698 for (size_t j = 0; j < matrix.numCols(); ++j) {
1699 tag << "a" << i + 1 << j + 1 << " = '" << matrix[i][j] << "' ";
1700 }
1701 }
1702 tag << "/>";
1703 xml.insert(tagPlace, tag.str());
1704
1705 return xml;
1706}
1707
1708std::string ShapeFactory::addGoniometerTag(const Kernel::Matrix<double> &rotateMatrix, std::string xml) {
1709 return insertMatrixTag("goniometer", rotateMatrix, std::move(xml));
1710}
1711
1712std::string ShapeFactory::addAppliedGoniometerTag(const Kernel::Matrix<double> &bakedRotation, std::string xml) {
1713 return insertMatrixTag("applied-goniometer", bakedRotation, std::move(xml));
1714}
1715
1718std::optional<Kernel::Matrix<double>> ShapeFactory::matrixFromXMLTag(const std::string &xml,
1719 const std::string &tagName) {
1720 Poco::AutoPtr<Document> pDoc;
1721 try {
1722 // wrapped as createShape(std::string) does, so a bare list of primitives parses too
1723 pDoc = DOMParser().parseString("<type name=\"userShape\"> " + xml + " </type>");
1724 } catch (...) {
1725 return std::nullopt;
1726 }
1727 Poco::AutoPtr<NodeList> pNL = pDoc->getElementsByTagName(tagName);
1728 if (pNL->length() == 0) {
1729 return std::nullopt;
1730 }
1731 return parseMatrixElement(static_cast<Element *>(pNL->item(0)));
1732}
1733
1735 return matrixFromXMLTag(xml, "goniometer").value_or(Kernel::Matrix<double>(3, 3, true));
1736}
1737
1739 // Mirrors how createShape reads the pair, so a shape rebuilt from this XML reports what is
1740 // returned here.
1741 if (const auto applied = matrixFromXMLTag(xml, "applied-goniometer")) {
1742 // On its own the tag describes nothing and createShape ignores it, so nothing has been baked.
1743 return matrixFromXMLTag(xml, "goniometer") ? *applied : Kernel::Matrix<double>(3, 3, true);
1744 }
1745 // the whole of a lone <goniometer> is taken to be a bake, as in createShape
1746 return goniometerFromXML(xml);
1747}
1748
1749std::string ShapeFactory::rebakeGoniometer(const Kernel::Matrix<double> &newBake, std::string xml,
1750 const Kernel::Matrix<double> &currentBake) {
1751 // Strip the old bake off the total, leaving the definition-frame rotation, then put the new bake
1752 // on the outside of it. These are orthonormal so the transpose is the exact inverse.
1753 //
1754 // With nothing to preserve the answer is just the new bake. Taking that shortcut is not merely
1755 // cheaper but exact: the long way round multiplies by the old bake and its transpose, identity
1756 // only to within rounding, and those last bits reorder the rendered mesh's triangles and
1757 // accumulate over copies.
1758 const Kernel::Matrix<double> total = goniometerFromXML(xml);
1759 const Kernel::Matrix<double> newTotal = total == currentBake ? newBake : newBake * currentBake.Tprime() * total;
1760
1761 xml = addGoniometerTag(newTotal, std::move(xml));
1762 return addAppliedGoniometerTag(newBake, std::move(xml));
1763}
1764} // namespace Mantid::Geometry
std::string name
Definition Run.cpp:60
double centre
double height
Definition GetAllEi.cpp:155
std::string parseCone(Poco::XML::Element *pElem, std::map< int, std::shared_ptr< Surface > > &prim, int &l_id)
Parse XML 'cone' element.
static std::shared_ptr< CSGObject > createHexahedralShape(double xlb, double xlf, double xrf, double xrb, double ylb, double ylf, double yrf, double yrb)
Create a hexahedral shape object.
static Kernel::Matrix< double > generateYRotation(double yRotation)
Generates the y component of the rotate matrix.
std::string parseHollowCylinder(Poco::XML::Element *pElem, std::map< int, std::shared_ptr< Surface > > &prim, int &l_id)
Parse XML 'hollow-cylinder' element.
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...
static std::string parseHexahedronFromStruct(const Hexahedron &hex, std::map< int, std::shared_ptr< Surface > > &prim, int &l_id)
The "tapered-guide" shape is actually a special case of hexahedron; once we have the 8 points that ma...
std::string rebakeGoniometer(const Kernel::Matrix< double > &newBake, std::string xml, const Kernel::Matrix< double > &currentBake)
Rebase the shape so the baked part becomes exactly newBake, preserving the definition-frame rotation.
void createGeometryHandler(Poco::XML::Element *, const std::shared_ptr< CSGObject > &)
create a special geometry handler for the known finite primitives
static std::optional< Kernel::Matrix< double > > matrixFromXMLTag(const std::string &xml, const std::string &tagName)
The matrix held in the named tag of a shape XML string, read as createShape reads it,...
static Kernel::Matrix< double > generateMatrix(double xRotation, double yRotation, double zRotation)
Generates a rotate Matrix applying the x rotate then y rotate, then z rotate.
CuboidCorners parseCuboid(Poco::XML::Element *pElem)
Get the four corners of a cuboid from an XML element.
static Kernel::Matrix< double > appliedGoniometerFromXML(const std::string &xml)
The baked part of a shape XML string's rotation - what a shape built from this XML reports through ge...
std::string addGoniometerTag(const Kernel::Matrix< double > &rotateMatrix, std::string xml)
Replace or insert the <goniometer> tag, the TOTAL rotation applied to the shape's surfaces.
Kernel::V3D parsePosition(Poco::XML::Element *pElem)
Get position coordinates from XML element.
std::string parseSliceOfCylinderRing(Poco::XML::Element *pElem, std::map< int, std::shared_ptr< Surface > > &prim, int &l_id)
Parse XML 'slice-of-cylinder-ring' element.
static std::shared_ptr< CSGObject > createSphere(const Kernel::V3D &centre, double radius)
Create a Sphere.
static Kernel::Matrix< double > generateZRotation(double zRotation)
Generates the z component of the rotate matrix.
static double getDoubleAttribute(Poco::XML::Element *pElem, const std::string &name)
Return value of attribute to XML element.
Kernel::Matrix< double > m_rotateAllMatrix
Poco::XML::Element * getShapeElement(Poco::XML::Element *pElem, const std::string &name)
Return a subelement of an XML element, but also checks that there exist exactly one entry of this sub...
static std::string sphereAlgebra(const int surfaceID)
Create the algebra string for a Sphere.
std::string parseInfiniteCone(Poco::XML::Element *pElem, std::map< int, std::shared_ptr< Surface > > &prim, int &l_id)
Parse XML 'infinite-cone' element.
std::string addAppliedGoniometerTag(const Kernel::Matrix< double > &bakedRotation, std::string xml)
Replace or insert the <applied-goniometer> tag, recording how much of <goniometer> is a bake into the...
std::string parseCylinder(Poco::XML::Element *pElem, std::map< int, std::shared_ptr< Surface > > &prim, int &l_id)
Parse XML 'cylinder' element.
static Kernel::Matrix< double > parseMatrixElement(Poco::XML::Element *pElem)
Read a 3x3 matrix held as a11..a33 attributes on an XML element.
Hexahedron parseHexahedron(Poco::XML::Element *pElem)
Get all corners of a hexahedron from an XML element.
static Kernel::Matrix< double > goniometerFromXML(const std::string &xml)
The total rotation held in a shape XML string's <goniometer> tag, identity if there is none.
Kernel::Matrix< double > m_gonioRotateMatrix
std::string parseTorus(Poco::XML::Element *pElem, std::map< int, std::shared_ptr< Surface > > &prim, int &l_id)
Parse XML 'torus' element.
std::string parseSphere(Poco::XML::Element *pElem, std::map< int, std::shared_ptr< Surface > > &prim, int &l_id)
Parse XML 'sphere' element.
std::string parseInfinitePlane(Poco::XML::Element *pElem, std::map< int, std::shared_ptr< Surface > > &prim, int &l_id)
Parse XML 'infinite-plane' element.
Poco::XML::Element * getOptionalShapeElement(Poco::XML::Element *pElem, const std::string &name)
Return a subelement of an XML element.
static std::string insertMatrixTag(const std::string &tagName, const Kernel::Matrix< double > &matrix, std::string xml)
Replace, or insert, a tag holding a 3x3 matrix as a11..a33 attributes.
std::string parseTaperedGuide(Poco::XML::Element *pElem, std::map< int, std::shared_ptr< Surface > > &prim, int &l_id)
Parse XML 'tapered-guide' element, which is a special case of the XML 'hexahedron' element.
std::string parseInfiniteCylinder(Poco::XML::Element *pElem, std::map< int, std::shared_ptr< Surface > > &prim, int &l_id)
Parse XML 'infinite-cylinder' element.
static Kernel::Matrix< double > generateXRotation(double xRotation)
Generates the x component of the rotate matrix.
void setSphere(const Kernel::V3D &center, double radius)
sets the geometry handler for a sphere
Definition ShapeInfo.cpp:85
void setCylinder(const Kernel::V3D &centerBottomBase, const Kernel::V3D &symmetryAxis, double radius, double height)
sets the geometry handler for a cylinder
Definition ShapeInfo.cpp:93
void setCone(const Kernel::V3D &center, const Kernel::V3D &symmetryAxis, double radius, double height)
sets the geometry handler for a cone
void setHollowCylinder(const Kernel::V3D &centreBottomBase, const Kernel::V3D &symmetryAxis, double innerRadius, double outerRadius, double height)
sets the geometry handler for a hollow cylinder
void setCuboid(const Kernel::V3D &, const Kernel::V3D &, const Kernel::V3D &, const Kernel::V3D &)
sets the geometry handler for a cuboid
Definition ShapeInfo.cpp:68
void setHexahedron(const Kernel::V3D &, const Kernel::V3D &, const Kernel::V3D &, const Kernel::V3D &, const Kernel::V3D &, const Kernel::V3D &, const Kernel::V3D &, const Kernel::V3D &)
sets the geometry handler for a hexahedron
Definition ShapeInfo.cpp:76
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
Numerical Matrix class.
Definition Matrix.h:41
void identityMatrix()
Makes the matrix an idenity matrix.
Definition Matrix.cpp:661
Matrix< T > Tprime() const
Transpose the matrix.
Definition Matrix.cpp:766
size_t numRows() const
Return the number of rows in the matrix.
Definition Matrix.h:143
size_t numCols() const
Return the number of columns in the matrix.
Definition Matrix.h:146
std::pair< size_t, size_t > size() const
Access matrix sizes.
Definition Matrix.h:140
Class for quaternions.
Definition Quat.h:38
void rotate(V3D &) const
Rotate a vector.
Definition Quat.cpp:397
Class for 3D vectors.
Definition V3D.h:35
double normalize()
Make a normalized vector (return norm value)
Definition V3D.cpp:129
void spherical(const double R, const double theta, const double phi) noexcept
Sets the vector position based on spherical coordinates.
Definition V3D.cpp:56
void rotate(const Matrix< double > &) noexcept
Rotate a point by a matrix.
Definition V3D.cpp:214
Mantid::Kernel::Logger g_log("Goniometer")
MANTID_KERNEL_DLL V3D normalize(V3D v)
Normalizes a V3D.
Definition V3D.h:353
std::string to_string(const wide_integer< Bits, Signed > &n)
void rotatePoints(const std::vector< double > &rotationMatrix)
void rotatePoints(const std::vector< double > &rotationMatrix)