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>
34#include "boost/make_shared.hpp"
38using Poco::XML::Document;
39using Poco::XML::DOMParser;
40using Poco::XML::DOMWriter;
41using Poco::XML::Element;
43using Poco::XML::NodeList;
47using namespace Kernel;
50const V3D DEFAULT_CENTRE(0, 0, 0);
51const V3D DEFAULT_AXIS(0, 0, 1);
54Logger
g_log(
"ShapeFactory");
58std::vector<double> DegreesToRadians(
const std::vector<double> &anglesDegrees) {
59 std::vector<double> anglesRadians;
60 std::transform(anglesDegrees.cbegin(), anglesDegrees.cend(), std::back_inserter(anglesRadians),
61 [](
const auto angle) { return angle * M_PI / 180.0; });
77 shapeXML =
"<type name=\"userShape\"> " + shapeXML +
" </type>";
81 Poco::AutoPtr<Document> pDoc;
83 pDoc = pParser.parseString(shapeXML);
85 g_log.
warning(
"Unable to parse XML string " + shapeXML +
" . Empty geometry Object is returned.");
87 return std::make_shared<CSGObject>();
90 Element *pRootElem = pDoc->documentElement();
106 std::stringstream xmlstream;
108 writer.writeNode(xmlstream, pElem);
109 std::string shapeXML = xmlstream.str();
110 auto retVal = std::make_shared<CSGObject>(shapeXML);
113 bool defaultAlgebra(
false);
115 Poco::AutoPtr<NodeList> pNL_algebra = pElem->getElementsByTagName(
"algebra");
116 std::string algebraFromUser;
117 if (pNL_algebra->length() == 0) {
118 defaultAlgebra =
true;
119 }
else if (pNL_algebra->length() == 1) {
120 auto *pElemAlgebra =
static_cast<Element *
>(pNL_algebra->item(0));
121 algebraFromUser = pElemAlgebra->getAttribute(
"val");
123 g_log.
warning() <<
"More than one algebra string defined for this shape. "
124 <<
"Maximum one allowed. Therefore empty shape is returned.";
128 Poco::AutoPtr<NodeList> pNL_gonio = pElem->getElementsByTagName(
"goniometer");
129 auto *pElemGonio =
static_cast<Element *
>(pNL_gonio->item(0));
133 for (
size_t i = 0; i < 3; ++i) {
134 for (
size_t j = 0; j < 3; ++j) {
140 Poco::AutoPtr<NodeList> pNL_rotate_all = pElem->getElementsByTagName(
"rotate-all");
141 auto *pElemRotateAll =
static_cast<Element *
>(pNL_rotate_all->item(0));
143 if (pElemRotateAll) {
144 std::vector<double> rotateAngles = DegreesToRadians(
parsePosition(pElemRotateAll));
150 std::map<std::string, std::string> idMatching;
153 Poco::AutoPtr<NodeList> pNL = pElem->childNodes();
154 unsigned long pNL_length = pNL->length();
155 int numPrimitives = 0;
158 std::map<int, std::shared_ptr<Surface>> primitives;
163 Element *lastElement =
nullptr;
164 for (
unsigned int i = 0; i < pNL_length; i++) {
165 if ((pNL->item(i))->nodeType() == Node::ELEMENT_NODE) {
166 auto *pE =
static_cast<Element *
>(pNL->item(i));
170 if (pE->hasAttribute(
"id")) {
171 std::string idFromUser = pE->getAttribute(
"id");
173 std::string primitiveName = pE->tagName();
181 if (primitiveName ==
"sphere") {
183 idMatching[idFromUser] =
parseSphere(pE, primitives, l_id);
185 }
else if (primitiveName ==
"infinite-plane") {
187 retVal->setFiniteGeometryFlag(
false);
189 }
else if (primitiveName ==
"infinite-cylinder") {
191 retVal->setFiniteGeometryFlag(
false);
193 }
else if (primitiveName ==
"cylinder") {
195 idMatching[idFromUser] =
parseCylinder(pE, primitives, l_id);
197 }
else if (primitiveName ==
"hollow-cylinder") {
201 }
else if (primitiveName ==
"cuboid") {
203 idMatching[idFromUser] =
parseCuboid(pE, primitives, l_id);
205 }
else if (primitiveName ==
"infinite-cone") {
207 retVal->setFiniteGeometryFlag(
false);
209 }
else if (primitiveName ==
"cone") {
211 idMatching[idFromUser] =
parseCone(pE, primitives, l_id);
213 }
else if (primitiveName ==
"hexahedron") {
217 }
else if (primitiveName ==
"tapered-guide") {
220 }
else if (primitiveName ==
"torus") {
221 idMatching[idFromUser] =
parseTorus(pE, primitives, l_id);
223 }
else if (primitiveName ==
"slice-of-cylinder-ring") {
227 g_log.
warning(primitiveName +
" not a recognised geometric shape. This shape is ignored.");
229 }
catch (std::invalid_argument &e) {
230 g_log.
warning() << e.what() <<
" <" << primitiveName <<
"> shape is ignored.";
231 }
catch (std::runtime_error &e) {
232 g_log.
warning() << e.what() <<
" <" << primitiveName <<
"> shape is ignored.";
234 g_log.
warning() <<
" Problem with parsing XML string for <" << primitiveName <<
">. This shape is ignored.";
240 if (!defaultAlgebra) {
245 std::map<std::string, std::string>::iterator iter;
246 std::map<size_t, std::string, std::greater<size_t>> allFound;
247 for (iter = idMatching.begin(); iter != idMatching.end(); ++iter) {
248 size_t found = algebraFromUser.find(iter->first);
250 if (found == std::string::npos) {
251 defaultAlgebra =
true;
252 g_log.
warning() <<
"Algebra shape Warning: " + iter->first +
253 " not found in algebra string: " + algebraFromUser +
"\n" +
254 ". Default to equal shape to intersection of those defined.";
257 allFound[found] = iter->first;
263 if (allFound.size() == idMatching.size()) {
264 std::map<size_t, std::string, std::greater<size_t>>::iterator iter2;
265 for (iter2 = allFound.begin(); iter2 != allFound.end(); ++iter2) {
267 algebraFromUser.replace(iter2->first, (iter2->second).size(), idMatching[iter2->second]);
271 if (defaultAlgebra) {
272 algebraFromUser =
"";
273 std::map<std::string, std::string>::iterator iter;
274 for (iter = idMatching.begin(); iter != idMatching.end(); ++iter) {
275 algebraFromUser.append(iter->second +
" ");
283 if (numPrimitives == 0)
286 retVal->setObject(21, algebraFromUser);
287 retVal->populate(primitives);
289 if (numPrimitives == 1 && lastElement !=
nullptr)
296 Poco::AutoPtr<NodeList> pNL_boundingBox = pElem->getElementsByTagName(
"bounding-box");
297 if (pNL_boundingBox->length() != 1)
302 double xmin = std::stod((
getShapeElement(pElem,
"x-min"))->getAttribute(
"val"));
303 double ymin = std::stod((
getShapeElement(pElem,
"y-min"))->getAttribute(
"val"));
304 double zmin = std::stod((
getShapeElement(pElem,
"z-min"))->getAttribute(
"val"));
305 double xmax = std::stod((
getShapeElement(pElem,
"x-max"))->getAttribute(
"val"));
306 double ymax = std::stod((
getShapeElement(pElem,
"y-max"))->getAttribute(
"val"));
307 double zmax = std::stod((
getShapeElement(pElem,
"z-max"))->getAttribute(
"val"));
309 retVal->defineBoundingBox(xmax, ymax, zmax, xmin, ymin, zmin);
344 prim[l_id] = std::make_shared<Sphere>(centre,
radius);
381 std::vector<double> rotateAngles = DegreesToRadians(
parsePosition(pElem_rot));
382 const std::vector<double> rotateMatrix =
generateMatrix(rotateAngles[0], rotateAngles[1], rotateAngles[2]);
383 normVec.
rotate(rotateMatrix);
397 auto pPlane = std::make_shared<Plane>();
398 pPlane->setPlane(centre, normVec);
401 std::stringstream retAlgebraMatch;
402 retAlgebraMatch <<
"(" << l_id <<
")";
404 return retAlgebraMatch.str();
419 std::map<
int, std::shared_ptr<Surface>> &prim,
int &l_id) {
434 std::vector<double> rotateAngles = DegreesToRadians(
parsePosition(pElem_rot));
435 const std::vector<double> rotateMatrix =
generateMatrix(rotateAngles[0], rotateAngles[1], rotateAngles[2]);
436 normVec.
rotate(rotateMatrix);
450 auto pCylinder = std::make_shared<Cylinder>();
451 pCylinder->setNorm(normVec);
452 pCylinder->setCentre(centre);
454 pCylinder->setRadius(
radius);
455 prim[l_id] = pCylinder;
457 std::stringstream retAlgebraMatch;
458 retAlgebraMatch <<
"(-" << l_id <<
")";
460 return retAlgebraMatch.str();
489 auto pCylinder = std::make_shared<Cylinder>();
491 V3D centre = centreOfBottomBase + normVec * (0.5 *
height);
492 pCylinder->setRadius(
radius);
498 std::vector<double> rotateAngles = DegreesToRadians(
parsePosition(pElem_rot));
499 const std::vector<double> rotateMatrix =
generateMatrix(rotateAngles[0], rotateAngles[1], rotateAngles[2]);
500 normVec.
rotate(rotateMatrix);
513 pCylinder->setNorm(normVec);
514 pCylinder->setCentre(centre);
516 prim[l_id] = pCylinder;
517 std::stringstream retAlgebraMatch;
518 retAlgebraMatch <<
"(-" << l_id <<
" ";
522 auto pPlaneTop = std::make_shared<Plane>();
524 V3D pointInPlaneTop = centre + (normVec *
height * 0.5);
525 pPlaneTop->setPlane(pointInPlaneTop, normVec);
526 prim[l_id] = pPlaneTop;
527 retAlgebraMatch <<
"-" << l_id <<
" ";
531 auto pPlaneBottom = std::make_shared<Plane>();
532 V3D pointInPlaneBottom = centre - (normVec *
height * 0.5);
533 pPlaneBottom->setPlane(pointInPlaneBottom, normVec);
534 prim[l_id] = pPlaneBottom;
535 retAlgebraMatch <<
"" << l_id <<
")";
538 return retAlgebraMatch.str();
564 throw std::runtime_error(
"ShapeFactory::parseHollowCylinder(): inner-radius < 0.0");
567 if (outerRadius <= 0.0) {
568 throw std::runtime_error(
"ShapeFactory::parseHollowCylinder(): outer-radius < 0.0");
571 throw std::runtime_error(
"ShapeFactory::parseHollowCylinder(): inner-radius > outer-radius.");
575 throw std::runtime_error(
"ShapeFactory::parseHollowCylinder(): height < 0.0");
579 V3D centre = centreOfBottomBase + normVec * (0.5 *
height);
585 std::vector<double> rotateAngles = DegreesToRadians(
parsePosition(pElem_rot));
586 const std::vector<double> rotateMatrix =
generateMatrix(rotateAngles[0], rotateAngles[1], rotateAngles[2]);
587 normVec.
rotate(rotateMatrix);
601 auto outerCylinder = std::make_shared<Cylinder>();
602 outerCylinder->setCentre(centre);
603 outerCylinder->setNorm(normVec);
604 outerCylinder->setRadius(outerRadius);
605 prim[l_id] = outerCylinder;
607 std::stringstream retAlgebraMatch;
608 retAlgebraMatch <<
"(-" << l_id <<
" ";
612 auto innerCylinder = std::make_shared<Cylinder>();
613 innerCylinder->setCentre(centre);
614 innerCylinder->setNorm(normVec);
616 prim[l_id] = innerCylinder;
617 retAlgebraMatch << l_id <<
" ";
621 auto pPlaneTop = std::make_shared<Plane>();
623 V3D pointInPlaneTop = centre + (normVec *
height * 0.5);
624 pPlaneTop->setPlane(pointInPlaneTop, normVec);
625 prim[l_id] = pPlaneTop;
626 retAlgebraMatch <<
"-" << l_id <<
" ";
630 auto pPlaneBottom = std::make_shared<Plane>();
631 V3D pointInPlaneBottom = centre - (normVec *
height * 0.5);
632 pPlaneBottom->setPlane(pointInPlaneBottom, normVec);
633 prim[l_id] = pPlaneBottom;
634 retAlgebraMatch <<
"" << l_id <<
")";
637 return retAlgebraMatch.str();
666 const bool usingPointSyntax = pElem_lfb && pElem_lft && pElem_lbb && pElem_rfb;
667 const bool usingAlternateSyntax = pElem_height && pElem_width && pElem_depth;
669 const bool usedPointSyntaxField = pElem_lfb || pElem_lft || pElem_lbb || pElem_rfb;
670 const bool usedAlternateSyntaxField =
671 pElem_height || pElem_width || pElem_depth || pElem_centre || pElem_axis || pElem_rot;
673 const std::string SYNTAX_ERROR_MSG =
"XML element: <" + pElem->tagName() +
674 "> may contain EITHER corner points (LFB, LFT, LBB and RFB) OR " +
675 "height, width, depth, centre and axis values.";
679 if (usingPointSyntax && !usingAlternateSyntax) {
680 if (usedAlternateSyntaxField)
681 throw std::invalid_argument(SYNTAX_ERROR_MSG);
687 }
else if (usingAlternateSyntax && !usingPointSyntax) {
688 if (usedPointSyntaxField)
689 throw std::invalid_argument(SYNTAX_ERROR_MSG);
697 result.
lfb =
V3D(-deltaW, -deltaH, -deltaD);
698 result.
lft =
V3D(-deltaW, deltaH, -deltaD);
699 result.
lbb =
V3D(-deltaW, -deltaH, deltaD);
700 result.
rfb =
V3D(deltaW, -deltaH, -deltaD);
707 const Quat rotate(DEFAULT_AXIS, axis);
719 std::vector<double> rotateAngles = DegreesToRadians(
parsePosition(pElem_rot));
720 const std::vector<double> rotateMatrix =
generateMatrix(rotateAngles[0], rotateAngles[1], rotateAngles[2]);
734 result.
lfb += centre;
735 result.
lft += centre;
736 result.
lbb += centre;
737 result.
rfb += centre;
739 throw std::invalid_argument(SYNTAX_ERROR_MSG);
760 const V3D pointTowardBack =
normalize(corners.lbb - corners.lfb);
763 auto pPlaneFrontCutoff = std::make_shared<Plane>();
765 pPlaneFrontCutoff->setPlane(corners.lfb, pointTowardBack);
766 }
catch (std::invalid_argument &) {
769 prim[l_id] = pPlaneFrontCutoff;
771 std::stringstream retAlgebraMatch;
772 retAlgebraMatch <<
"(" << l_id <<
" ";
776 auto pPlaneBackCutoff = std::make_shared<Plane>();
778 pPlaneBackCutoff->setPlane(corners.lbb, pointTowardBack);
779 }
catch (std::invalid_argument &) {
782 prim[l_id] = pPlaneBackCutoff;
783 retAlgebraMatch <<
"-" << l_id <<
" ";
786 const V3D pointTowardRight =
normalize(corners.rfb - corners.lfb);
789 auto pPlaneLeftCutoff = std::make_shared<Plane>();
791 pPlaneLeftCutoff->setPlane(corners.lfb, pointTowardRight);
792 }
catch (std::invalid_argument &) {
795 prim[l_id] = pPlaneLeftCutoff;
796 retAlgebraMatch <<
"" << l_id <<
" ";
800 auto pPlaneRightCutoff = std::make_shared<Plane>();
802 pPlaneRightCutoff->setPlane(corners.rfb, pointTowardRight);
803 }
catch (std::invalid_argument &) {
806 prim[l_id] = pPlaneRightCutoff;
807 retAlgebraMatch <<
"-" << l_id <<
" ";
810 const V3D pointTowardTop =
normalize(corners.lft - corners.lfb);
813 auto pPlaneBottomCutoff = std::make_shared<Plane>();
815 pPlaneBottomCutoff->setPlane(corners.lfb, pointTowardTop);
816 }
catch (std::invalid_argument &) {
819 prim[l_id] = pPlaneBottomCutoff;
820 retAlgebraMatch <<
"" << l_id <<
" ";
824 auto pPlaneTopCutoff = std::make_shared<Plane>();
826 pPlaneTopCutoff->setPlane(corners.lft, pointTowardTop);
827 }
catch (std::invalid_argument &) {
830 prim[l_id] = pPlaneTopCutoff;
831 retAlgebraMatch <<
"-" << l_id <<
")";
834 return retAlgebraMatch.str();
860 auto pCone = std::make_shared<Cone>();
862 pCone->setNorm(normVec);
863 pCone->setAngle(angle);
866 std::stringstream retAlgebraMatch;
867 retAlgebraMatch <<
"(" << l_id <<
" ";
871 auto pPlaneBottom = std::make_shared<Plane>();
872 pPlaneBottom->setPlane(
parsePosition(pElemTipPoint), normVec);
873 prim[l_id] = pPlaneBottom;
874 retAlgebraMatch <<
"-" << l_id <<
")";
877 return retAlgebraMatch.str();
905 auto pCone = std::make_shared<Cone>();
907 pCone->setNorm(normVec);
908 pCone->setAngle(angle);
911 std::stringstream retAlgebraMatch;
912 retAlgebraMatch <<
"(" << l_id <<
" ";
916 auto pPlaneTop = std::make_shared<Plane>();
918 pointInPlane -= (normVec *
height);
919 pPlaneTop->setPlane(pointInPlane, normVec);
920 prim[l_id] = pPlaneTop;
921 retAlgebraMatch <<
"" << l_id <<
" ";
925 auto pPlaneBottom = std::make_shared<Plane>();
926 pPlaneBottom->setPlane(
parsePosition(pElemTipPoint), normVec);
927 prim[l_id] = pPlaneBottom;
928 retAlgebraMatch <<
"-" << l_id <<
")";
931 return retAlgebraMatch.str();
941 std::map<
int, std::shared_ptr<Surface>> &prim,
int &l_id) {
943 auto pPlaneFrontCutoff = std::make_shared<Plane>();
944 auto normal = (hex.
rfb - hex.
lfb).cross_prod(hex.
lft - hex.
lfb);
947 if (normal.scalar_prod(hex.
rfb - hex.
rbb) < 0)
949 pPlaneFrontCutoff->setPlane(hex.
lfb, normal);
950 prim[l_id] = pPlaneFrontCutoff;
951 std::stringstream retAlgebraMatch;
952 retAlgebraMatch <<
"(-" << l_id <<
" ";
956 auto pPlaneBackCutoff = std::make_shared<Plane>();
957 normal = (hex.
rbb - hex.
lbb).cross_prod(hex.
lbt - hex.
lbb);
958 if (normal.scalar_prod(hex.
rfb - hex.
rbb) < 0)
960 pPlaneBackCutoff->setPlane(hex.
lbb, normal);
961 prim[l_id] = pPlaneBackCutoff;
962 retAlgebraMatch <<
"" << l_id <<
" ";
966 auto pPlaneLeftCutoff = std::make_shared<Plane>();
967 normal = (hex.
lbb - hex.
lfb).cross_prod(hex.
lft - hex.
lfb);
968 if (normal.scalar_prod(hex.
rfb - hex.
lfb) < 0)
970 pPlaneLeftCutoff->setPlane(hex.
lfb, normal);
971 prim[l_id] = pPlaneLeftCutoff;
972 retAlgebraMatch <<
"" << l_id <<
" ";
976 auto pPlaneRightCutoff = std::make_shared<Plane>();
977 normal = (hex.
rbb - hex.
rfb).cross_prod(hex.
rft - hex.
rfb);
978 if (normal.scalar_prod(hex.
rfb - hex.
lfb) < 0)
980 pPlaneRightCutoff->setPlane(hex.
rfb, normal);
981 prim[l_id] = pPlaneRightCutoff;
982 retAlgebraMatch <<
"-" << l_id <<
" ";
986 auto pPlaneTopCutoff = std::make_shared<Plane>();
987 normal = (hex.
rft - hex.
lft).cross_prod(hex.
lbt - hex.
lft);
988 if (normal.scalar_prod(hex.
rft - hex.
rfb) < 0)
990 pPlaneTopCutoff->setPlane(hex.
lft, normal);
991 prim[l_id] = pPlaneTopCutoff;
992 retAlgebraMatch <<
"-" << l_id <<
" ";
996 auto pPlaneBottomCutoff = std::make_shared<Plane>();
997 normal = (hex.
rfb - hex.
lfb).cross_prod(hex.
lbb - hex.
lfb);
998 if (normal.scalar_prod(hex.
rft - hex.
rfb) < 0)
1000 pPlaneBottomCutoff->setPlane(hex.
lfb, normal);
1001 prim[l_id] = pPlaneBottomCutoff;
1002 retAlgebraMatch <<
"" << l_id <<
")";
1005 return retAlgebraMatch.str();
1017 Element *pElem_lfb =
getShapeElement(pElem,
"left-front-bottom-point");
1019 Element *pElem_lbb =
getShapeElement(pElem,
"left-back-bottom-point");
1021 Element *pElem_rfb =
getShapeElement(pElem,
"right-front-bottom-point");
1023 Element *pElem_rbb =
getShapeElement(pElem,
"right-back-bottom-point");
1027 const bool isValid =
1028 pElem_lfb && pElem_lft && pElem_lbb && pElem_lbt && pElem_rfb && pElem_rft && pElem_rbb && pElem_rbt;
1030 std::ostringstream ERROR_MSG;
1031 ERROR_MSG <<
"XML element: <" + pElem->tagName() +
""
1032 <<
"> contains invalid syntax for defining hexahedron. The "
1033 "following points have not been defined:\n\n";
1036 ERROR_MSG <<
"left-front-bottom-point\n";
1038 ERROR_MSG <<
"left-front-top-point\n";
1040 ERROR_MSG <<
"left-back-bottom-point\n";
1042 ERROR_MSG <<
"left-back-top-point\n";
1044 ERROR_MSG <<
"right-front-bottom-point\n";
1046 ERROR_MSG <<
"right-front-top-point\n";
1048 ERROR_MSG <<
"right-back-bottom-point\n";
1050 ERROR_MSG <<
"right-back-top-point\n";
1053 throw std::invalid_argument(ERROR_MSG.str());
1068 std::vector<double> rotateAngles = DegreesToRadians(
parsePosition(pElem_rot));
1069 const std::vector<double> rotateMatrix =
generateMatrix(rotateAngles[0], rotateAngles[1], rotateAngles[2]);
1116 Element *pElemApertureStart =
getShapeElement(pElem,
"aperture-start");
1134 const double halfSW = apertureStartWidth / 2;
1135 const double halfSH = apertureStartHeight / 2;
1136 const double halfEW = apertureEndWidth / 2;
1137 const double halfEH = apertureEndHeight / 2;
1141 hex.
lfb =
V3D(-halfSW, -halfSH, 0);
1142 hex.
lft =
V3D(-halfSW, halfSH, 0);
1143 hex.
lbb =
V3D(-halfEW, -halfEH, length);
1144 hex.
lbt =
V3D(-halfEW, halfEH, length);
1145 hex.
rfb =
V3D(halfSW, -halfSH, 0);
1146 hex.
rft =
V3D(halfSW, halfSH, 0);
1147 hex.
rbb =
V3D(halfEW, -halfEH, length);
1148 hex.
rbt =
V3D(halfEW, halfEH, length);
1151 if (axis != DEFAULT_AXIS) {
1152 const Quat q(DEFAULT_AXIS, axis);
1167 std::vector<double> rotateAngles = DegreesToRadians(
parsePosition(pElem_rot));
1168 const std::vector<double> rotateMatrix =
generateMatrix(rotateAngles[0], rotateAngles[1], rotateAngles[2]);
1210 Element *pElemRadiusFromCentre =
getShapeElement(pElem,
"radius-from-centre-to-tube");
1220 auto pTorus = std::make_shared<Torus>();
1222 pTorus->setNorm(normVec);
1223 pTorus->setDistanceFromCentreToTube(radiusCentre);
1224 pTorus->setTubeRadius(radiusTube);
1225 prim[l_id] = pTorus;
1227 std::stringstream retAlgebraMatch;
1228 retAlgebraMatch <<
"(-" << l_id <<
")";
1231 return retAlgebraMatch.str();
1247 std::map<
int, std::shared_ptr<Surface>> &prim,
int &l_id) {
1258 g_log.
warning() <<
"ShapeFactory::parseSliceOfCylinderRing(): inner-radius cannot be < 0.0 or = 0.0, so has been "
1259 "automatically set.";
1261 const double middleRadius = (outerRadius +
innerRadius) / 2.0;
1265 V3D normVec(0, 0, 1);
1266 V3D centrePoint(-middleRadius, 0, 0);
1267 V3D planeSlice1 =
V3D(cos(arc / 2.0 + M_PI / 2.0), sin(arc / 2.0 + M_PI / 2.0), 0);
1268 V3D planeSlice2 =
V3D(cos(-arc / 2.0 + M_PI / 2.0), sin(-arc / 2.0 + M_PI / 2.0), 0);
1274 std::vector<double> rotateAngles = DegreesToRadians(
parsePosition(pElem_rot));
1275 const std::vector<double> rotateMatrix =
generateMatrix(rotateAngles[0], rotateAngles[1], rotateAngles[2]);
1276 normVec.
rotate(rotateMatrix);
1277 planeSlice1.
rotate(rotateMatrix);
1278 planeSlice2.
rotate(rotateMatrix);
1296 auto pCylinder1 = std::make_shared<Cylinder>();
1297 pCylinder1->setCentre(centrePoint);
1298 pCylinder1->setNorm(normVec);
1300 prim[l_id] = pCylinder1;
1301 std::stringstream retAlgebraMatch;
1302 retAlgebraMatch <<
"(" << l_id <<
" ";
1306 auto pCylinder2 = std::make_shared<Cylinder>();
1307 pCylinder2->setCentre(centrePoint);
1308 pCylinder2->setNorm(normVec);
1309 pCylinder2->setRadius(outerRadius);
1310 prim[l_id] = pCylinder2;
1311 retAlgebraMatch <<
"-" << l_id <<
" ";
1315 auto pPlaneTop = std::make_shared<Plane>();
1316 V3D pointInPlaneTop = centrePoint + (normVec * depth * 0.5);
1317 pPlaneTop->setPlane(pointInPlaneTop, normVec);
1318 prim[l_id] = pPlaneTop;
1319 retAlgebraMatch <<
"-" << l_id <<
" ";
1324 auto pPlaneBottom = std::make_shared<Plane>();
1325 V3D pointInPlaneBottom = centrePoint - (normVec * depth * 0.5);
1326 pPlaneBottom->setPlane(pointInPlaneBottom, normVec);
1327 prim[l_id] = pPlaneBottom;
1328 retAlgebraMatch <<
"" << l_id <<
" ";
1333 auto pPlaneSlice1 = std::make_shared<Plane>();
1334 pPlaneSlice1->setPlane(centrePoint, planeSlice1);
1335 prim[l_id] = pPlaneSlice1;
1336 retAlgebraMatch <<
"-" << l_id <<
" ";
1339 auto pPlaneSlice2 = std::make_shared<Plane>();
1340 pPlaneSlice2->setPlane(centrePoint, planeSlice2);
1341 prim[l_id] = pPlaneSlice2;
1342 retAlgebraMatch <<
"" << l_id <<
")";
1345 return retAlgebraMatch.str();
1361 Poco::AutoPtr<NodeList> pNL = pElem->getElementsByTagName(name);
1362 if (pNL->length() != 1) {
1363 throw std::invalid_argument(
"XML element: <" + pElem->tagName() +
1364 "> must contain exactly one sub-element with name: <" + name +
">.");
1366 auto *retVal =
static_cast<Element *
>(pNL->item(0));
1383 Poco::AutoPtr<NodeList> pNL = pElem->getElementsByTagName(name);
1384 if (pNL->length() == 0)
1386 else if (pNL->length() > 1)
1387 throw std::invalid_argument(
"XML element: <" + pElem->tagName() +
1388 "> may contain at most one sub-element with name: <" + name +
">.");
1390 auto *retVal =
static_cast<Element *
>(pNL->item(0));
1405 if (pElem->hasAttribute(name)) {
1406 return std::stod(pElem->getAttribute(name));
1408 throw std::invalid_argument(
"XML element: <" + pElem->tagName() +
"> does not have the attribute: " + name +
".");
1420 if (pElem->hasAttribute(
"R") || pElem->hasAttribute(
"theta") || pElem->hasAttribute(
"phi")) {
1421 double R = 0.0, theta = 0.0, phi = 0.0;
1423 if (pElem->hasAttribute(
"R"))
1424 R = std::stod(pElem->getAttribute(
"R"));
1425 if (pElem->hasAttribute(
"theta"))
1426 theta = std::stod(pElem->getAttribute(
"theta"));
1427 if (pElem->hasAttribute(
"phi"))
1428 phi = std::stod(pElem->getAttribute(
"phi"));
1431 }
else if (pElem->hasAttribute(
"r") || pElem->hasAttribute(
"t") || pElem->hasAttribute(
"p"))
1436 double R = 0.0, theta = 0.0, phi = 0.0;
1438 if (pElem->hasAttribute(
"r"))
1439 R = std::stod(pElem->getAttribute(
"r"));
1440 if (pElem->hasAttribute(
"t"))
1441 theta = std::stod(pElem->getAttribute(
"t"));
1442 if (pElem->hasAttribute(
"p"))
1443 phi = std::stod(pElem->getAttribute(
"p"));
1447 double x = 0.0,
y = 0.0,
z = 0.0;
1449 if (pElem->hasAttribute(
"x"))
1450 x = std::stod(pElem->getAttribute(
"x"));
1451 if (pElem->hasAttribute(
"y"))
1452 y = std::stod(pElem->getAttribute(
"y"));
1453 if (pElem->hasAttribute(
"z"))
1454 z = std::stod(pElem->getAttribute(
"z"));
1469 const int surfaceID = 1;
1470 const std::map<int, std::shared_ptr<Surface>> primitives{{surfaceID, std::make_shared<Sphere>(centre,
radius)}};
1472 auto shape = std::make_shared<CSGObject>();
1474 shape->populate(primitives);
1476 auto handler = std::make_shared<GeometryHandler>(shape);
1477 shape->setGeometryHandler(handler);
1480 handler->setShapeInfo(std::move(shapeInfo));
1499 double ylb,
double ylf,
double yrf,
double yrb) {
1501 static const double ZDEPTH = 0.001;
1502 hex.
lbb =
V3D(xlb, ylb, 0);
1503 hex.
lbt =
V3D(xlb, ylb, ZDEPTH);
1504 hex.
lfb =
V3D(xlf, ylf, 0);
1505 hex.
lft =
V3D(xlf, ylf, ZDEPTH);
1506 hex.
rbb =
V3D(xrb, yrb, 0);
1507 hex.
rbt =
V3D(xrb, yrb, ZDEPTH);
1508 hex.
rfb =
V3D(xrf, yrf, 0);
1509 hex.
rft =
V3D(xrf, yrf, ZDEPTH);
1511 std::map<int, std::shared_ptr<Surface>> prim;
1515 auto shape = std::make_shared<CSGObject>();
1516 shape->setObject(21, algebra);
1517 shape->populate(prim);
1519 auto handler = std::make_shared<GeometryHandler>(shape);
1521 shape->setGeometryHandler(handler);
1525 handler->setShapeInfo(std::move(shapeInfo));
1527 shape->defineBoundingBox(std::max(xrb, xrf), yrf, ZDEPTH, std::min(xlf, xlb), ylb, 0);
1535 auto geomHandler = std::make_shared<GeometryHandler>(Obj);
1537 Obj->setGeometryHandler(geomHandler);
1539 if (pElem->tagName() ==
"cuboid") {
1541 shapeInfo.
setCuboid(corners.lfb, corners.lft, corners.lbb, corners.rfb);
1542 }
else if (pElem->tagName() ==
"hexahedron") {
1544 shapeInfo.
setHexahedron(corners.lbb, corners.lfb, corners.rfb, corners.rbb, corners.lbt, corners.lft, corners.rft,
1546 }
else if (pElem->tagName() ==
"sphere") {
1552 shapeInfo.
setSphere(centre, std::stod(pElemRadius->getAttribute(
"val")));
1553 }
else if (pElem->tagName() ==
"cylinder") {
1554 Element *pElemCentre =
getShapeElement(pElem,
"centre-of-bottom-base");
1560 std::stod(pElemHeight->getAttribute(
"val")));
1561 }
else if (pElem->tagName() ==
"hollow-cylinder") {
1562 Element *pElemCentre =
getShapeElement(pElem,
"centre-of-bottom-base");
1570 std::stod(pElemOuterRadius->getAttribute(
"val")),
1571 std::stod(pElemHeight->getAttribute(
"val")));
1572 }
else if (pElem->tagName() ==
"cone") {
1579 const double height = std::stod(pElemHeight->getAttribute(
"val"));
1580 const double radius =
height * tan(M_PI * std::stod(pElemAngle->getAttribute(
"val")) / 180.0);
1584 geomHandler->setShapeInfo(std::move(shapeInfo));
1600 return zMatrix * yMatrix * xMatrix;
1609 const double sinX = sin(xrotate);
1610 const double cosX = cos(xrotate);
1611 std::vector<double> matrixList = {1, 0, 0, 0, cosX, -sinX, 0, sinX, cosX};
1621 const double sinY = sin(yrotate);
1622 const double cosY = cos(yrotate);
1623 std::vector<double> matrixList = {cosY, 0, sinY, 0, 1, 0, -sinY, 0, cosY};
1633 const double sinZ = sin(zrotate);
1634 const double cosZ = cos(zrotate);
1635 std::vector<double> matrixList = {cosZ, -sinZ, 0, sinZ, cosZ, 0, 0, 0, 1};
1642 std::size_t foundGonioTag = xml.find(
"<goniometer");
1643 if (foundGonioTag != std::string::npos) {
1644 std::size_t gonioTagLength = xml.find(
">", foundGonioTag + 1) - foundGonioTag;
1645 xml.erase(foundGonioTag, gonioTagLength);
1649 std::size_t gonioPlace;
1650 std::size_t foundType = xml.find(
"</type>");
1651 std::size_t foundSampleGeometry = xml.find(
"</samplegeometry");
1653 if (foundType != std::string::npos) {
1655 gonioPlace = foundType;
1656 }
else if (foundSampleGeometry != std::string::npos) {
1658 gonioPlace = foundSampleGeometry;
1661 gonioPlace = xml.size();
1664 const std::vector<std::string> matrixElementNames = {
"a11",
"a12",
"a13",
"a21",
"a22",
"a23",
"a31",
"a32",
"a33"};
1665 std::string goniometerRotate =
" <goniometer ";
1666 for (
size_t i = 0; i < rotateMatrix.
numRows(); ++i) {
1667 for (
size_t j = 0; j < rotateMatrix.
numCols(); ++j) {
1668 goniometerRotate += matrixElementNames[3 * i + j] +
" = '" +
std::to_string(rotateMatrix[i][j]) +
"' ";
1671 goniometerRotate +=
"/>";
1672 xml.insert(gonioPlace, goniometerRotate);
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...
void createGeometryHandler(Poco::XML::Element *, const std::shared_ptr< CSGObject > &)
create a special geometry handler for the known finite primitives
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.
std::string addGoniometerTag(const Kernel::Matrix< double > &rotateMatrix, std::string xml)
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 ¢re, double radius)
Create a Sphere.
static Kernel::Matrix< double > generateZRotation(double zRotation)
Generates the z component of the rotate matrix.
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 parseCylinder(Poco::XML::Element *pElem, std::map< int, std::shared_ptr< Surface > > &prim, int &l_id)
Parse XML 'cylinder' element.
Hexahedron parseHexahedron(Poco::XML::Element *pElem)
Get all corners of a hexahedron from an XML element.
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.
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 ¢er, double radius)
sets the geometry handler for a sphere
void setCylinder(const Kernel::V3D ¢erBottomBase, const Kernel::V3D &symmetryAxis, double radius, double height)
sets the geometry handler for a cylinder
void setCone(const Kernel::V3D ¢er, const Kernel::V3D &symmetryAxis, double radius, double height)
sets the geometry handler for a cone
void setHollowCylinder(const Kernel::V3D ¢reBottomBase, 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
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
void warning(const std::string &msg)
Logs at warning level.
void identityMatrix()
Makes the matrix an idenity matrix.
size_t numRows() const
Return the number of rows in the matrix.
size_t numCols() const
Return the number of columns in the matrix.
void rotate(V3D &) const
Rotate a vector.
double normalize()
Make a normalized vector (return norm value)
void spherical(const double R, const double theta, const double phi) noexcept
Sets the vector position based on spherical coordinates.
void rotate(const Matrix< double > &) noexcept
Rotate a point by a matrix.
Mantid::Kernel::Logger g_log("Goniometer")
MANTID_KERNEL_DLL V3D normalize(V3D v)
Normalizes a V3D.
std::string to_string(const wide_integer< Bits, Signed > &n)
void rotatePoints(const std::vector< double > &rotationMatrix)
void rotatePoints(const std::vector< double > &rotationMatrix)