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"
42using Poco::XML::Document;
43using Poco::XML::DOMParser;
44using Poco::XML::DOMWriter;
45using Poco::XML::Element;
47using Poco::XML::NodeList;
51using namespace Kernel;
54const V3D DEFAULT_CENTRE(0, 0, 0);
55const V3D DEFAULT_AXIS(0, 0, 1);
58Logger
g_log(
"ShapeFactory");
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; });
81 shapeXML =
"<type name=\"userShape\"> " + shapeXML +
" </type>";
85 Poco::AutoPtr<Document> pDoc;
87 pDoc = pParser.parseString(shapeXML);
89 g_log.
warning(
"Unable to parse XML string " + shapeXML +
" . Empty geometry Object is returned.");
91 return std::make_shared<CSGObject>();
94 Element *pRootElem = pDoc->documentElement();
110 std::stringstream xmlstream;
112 writer.writeNode(xmlstream, pElem);
113 std::string shapeXML = xmlstream.str();
114 auto retVal = std::make_shared<CSGObject>(shapeXML);
117 bool defaultAlgebra(
false);
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");
127 g_log.
warning() <<
"More than one algebra string defined for this shape. "
128 <<
"Maximum one allowed. Therefore empty shape is returned.";
133 Poco::AutoPtr<NodeList> pNL_gonio = pElem->getElementsByTagName(
"goniometer");
134 auto *pElemGonio =
static_cast<Element *
>(pNL_gonio->item(0));
142 Poco::AutoPtr<NodeList> pNL_applied = pElem->getElementsByTagName(
"applied-goniometer");
143 auto *pElemApplied =
static_cast<Element *
>(pNL_applied->item(0));
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) {
156 retVal->setAppliedGoniometerRotation(bakedRotation);
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));
168 std::map<std::string, std::string> idMatching;
171 Poco::AutoPtr<NodeList> pNL = pElem->childNodes();
172 unsigned long pNL_length = pNL->length();
173 int numPrimitives = 0;
176 std::map<int, std::shared_ptr<Surface>> primitives;
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));
188 if (pE->hasAttribute(
"id")) {
189 std::string idFromUser = pE->getAttribute(
"id");
191 std::string primitiveName = pE->tagName();
199 if (primitiveName ==
"sphere") {
201 idMatching[idFromUser] =
parseSphere(pE, primitives, l_id);
203 }
else if (primitiveName ==
"infinite-plane") {
205 retVal->setFiniteGeometryFlag(
false);
207 }
else if (primitiveName ==
"infinite-cylinder") {
209 retVal->setFiniteGeometryFlag(
false);
211 }
else if (primitiveName ==
"cylinder") {
213 idMatching[idFromUser] =
parseCylinder(pE, primitives, l_id);
215 }
else if (primitiveName ==
"hollow-cylinder") {
219 }
else if (primitiveName ==
"cuboid") {
221 idMatching[idFromUser] =
parseCuboid(pE, primitives, l_id);
223 }
else if (primitiveName ==
"infinite-cone") {
225 retVal->setFiniteGeometryFlag(
false);
227 }
else if (primitiveName ==
"cone") {
229 idMatching[idFromUser] =
parseCone(pE, primitives, l_id);
231 }
else if (primitiveName ==
"hexahedron") {
235 }
else if (primitiveName ==
"tapered-guide") {
238 }
else if (primitiveName ==
"torus") {
239 idMatching[idFromUser] =
parseTorus(pE, primitives, l_id);
241 }
else if (primitiveName ==
"slice-of-cylinder-ring") {
245 g_log.
warning(primitiveName +
" not a recognised geometric shape. This shape is ignored.");
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.";
252 g_log.
warning() <<
" Problem with parsing XML string for <" << primitiveName <<
">. This shape is ignored.";
258 if (!defaultAlgebra) {
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);
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.";
275 allFound[found] = iter->first;
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) {
285 algebraFromUser.replace(iter2->first, (iter2->second).size(), idMatching[iter2->second]);
289 if (defaultAlgebra) {
290 algebraFromUser =
"";
291 std::map<std::string, std::string>::iterator iter;
292 for (iter = idMatching.begin(); iter != idMatching.end(); ++iter) {
293 algebraFromUser.append(iter->second +
" ");
301 if (numPrimitives == 0)
304 retVal->setObject(21, algebraFromUser);
305 retVal->populate(primitives);
307 if (numPrimitives == 1 && lastElement !=
nullptr)
314 Poco::AutoPtr<NodeList> pNL_boundingBox = pElem->getElementsByTagName(
"bounding-box");
315 if (pNL_boundingBox->length() != 1)
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"));
327 retVal->defineBoundingBox(xmax, ymax, zmax, xmin, ymin, zmin);
362 prim[l_id] = std::make_shared<Sphere>(
centre, radius);
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);
415 auto pPlane = std::make_shared<Plane>();
416 pPlane->setPlane(
centre, normVec);
419 std::stringstream retAlgebraMatch;
420 retAlgebraMatch <<
"(" << l_id <<
")";
422 return retAlgebraMatch.str();
437 std::map<
int, std::shared_ptr<Surface>> &prim,
int &l_id) {
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);
468 auto pCylinder = std::make_shared<Cylinder>();
469 pCylinder->setNorm(normVec);
470 pCylinder->setCentre(
centre);
472 pCylinder->setRadius(radius);
473 prim[l_id] = pCylinder;
475 std::stringstream retAlgebraMatch;
476 retAlgebraMatch <<
"(-" << l_id <<
")";
478 return retAlgebraMatch.str();
507 auto pCylinder = std::make_shared<Cylinder>();
510 pCylinder->setRadius(radius);
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);
531 pCylinder->setNorm(normVec);
532 pCylinder->setCentre(
centre);
534 prim[l_id] = pCylinder;
535 std::stringstream retAlgebraMatch;
536 retAlgebraMatch <<
"(-" << l_id <<
" ";
540 auto pPlaneTop = std::make_shared<Plane>();
543 pPlaneTop->setPlane(pointInPlaneTop, normVec);
544 prim[l_id] = pPlaneTop;
545 retAlgebraMatch <<
"-" << l_id <<
" ";
549 auto pPlaneBottom = std::make_shared<Plane>();
551 pPlaneBottom->setPlane(pointInPlaneBottom, normVec);
552 prim[l_id] = pPlaneBottom;
553 retAlgebraMatch <<
"" << l_id <<
")";
556 return retAlgebraMatch.str();
581 if (innerRadius <= 0.0) {
582 throw std::runtime_error(
"ShapeFactory::parseHollowCylinder(): inner-radius < 0.0");
585 if (outerRadius <= 0.0) {
586 throw std::runtime_error(
"ShapeFactory::parseHollowCylinder(): outer-radius < 0.0");
588 if (innerRadius > outerRadius) {
589 throw std::runtime_error(
"ShapeFactory::parseHollowCylinder(): inner-radius > outer-radius.");
593 throw std::runtime_error(
"ShapeFactory::parseHollowCylinder(): height < 0.0");
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);
619 auto outerCylinder = std::make_shared<Cylinder>();
620 outerCylinder->setCentre(
centre);
621 outerCylinder->setNorm(normVec);
622 outerCylinder->setRadius(outerRadius);
623 prim[l_id] = outerCylinder;
625 std::stringstream retAlgebraMatch;
626 retAlgebraMatch <<
"(-" << l_id <<
" ";
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 <<
" ";
639 auto pPlaneTop = std::make_shared<Plane>();
642 pPlaneTop->setPlane(pointInPlaneTop, normVec);
643 prim[l_id] = pPlaneTop;
644 retAlgebraMatch <<
"-" << l_id <<
" ";
648 auto pPlaneBottom = std::make_shared<Plane>();
650 pPlaneBottom->setPlane(pointInPlaneBottom, normVec);
651 prim[l_id] = pPlaneBottom;
652 retAlgebraMatch <<
"" << l_id <<
")";
655 return retAlgebraMatch.str();
684 const bool usingPointSyntax = pElem_lfb && pElem_lft && pElem_lbb && pElem_rfb;
685 const bool usingAlternateSyntax = pElem_height && pElem_width && pElem_depth;
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;
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.";
697 if (usingPointSyntax && !usingAlternateSyntax) {
698 if (usedAlternateSyntaxField)
699 throw std::invalid_argument(SYNTAX_ERROR_MSG);
705 }
else if (usingAlternateSyntax && !usingPointSyntax) {
706 if (usedPointSyntaxField)
707 throw std::invalid_argument(SYNTAX_ERROR_MSG);
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);
725 const Quat rotate(DEFAULT_AXIS, axis);
737 std::vector<double> rotateAngles = DegreesToRadians(
parsePosition(pElem_rot));
738 const std::vector<double> rotateMatrix =
generateMatrix(rotateAngles[0], rotateAngles[1], rotateAngles[2]);
757 throw std::invalid_argument(SYNTAX_ERROR_MSG);
778 const V3D pointTowardBack =
normalize(corners.lbb - corners.lfb);
781 auto pPlaneFrontCutoff = std::make_shared<Plane>();
783 pPlaneFrontCutoff->setPlane(corners.lfb, pointTowardBack);
784 }
catch (std::invalid_argument &) {
787 prim[l_id] = pPlaneFrontCutoff;
789 std::stringstream retAlgebraMatch;
790 retAlgebraMatch <<
"(" << l_id <<
" ";
794 auto pPlaneBackCutoff = std::make_shared<Plane>();
796 pPlaneBackCutoff->setPlane(corners.lbb, pointTowardBack);
797 }
catch (std::invalid_argument &) {
800 prim[l_id] = pPlaneBackCutoff;
801 retAlgebraMatch <<
"-" << l_id <<
" ";
804 const V3D pointTowardRight =
normalize(corners.rfb - corners.lfb);
807 auto pPlaneLeftCutoff = std::make_shared<Plane>();
809 pPlaneLeftCutoff->setPlane(corners.lfb, pointTowardRight);
810 }
catch (std::invalid_argument &) {
813 prim[l_id] = pPlaneLeftCutoff;
814 retAlgebraMatch <<
"" << l_id <<
" ";
818 auto pPlaneRightCutoff = std::make_shared<Plane>();
820 pPlaneRightCutoff->setPlane(corners.rfb, pointTowardRight);
821 }
catch (std::invalid_argument &) {
824 prim[l_id] = pPlaneRightCutoff;
825 retAlgebraMatch <<
"-" << l_id <<
" ";
828 const V3D pointTowardTop =
normalize(corners.lft - corners.lfb);
831 auto pPlaneBottomCutoff = std::make_shared<Plane>();
833 pPlaneBottomCutoff->setPlane(corners.lfb, pointTowardTop);
834 }
catch (std::invalid_argument &) {
837 prim[l_id] = pPlaneBottomCutoff;
838 retAlgebraMatch <<
"" << l_id <<
" ";
842 auto pPlaneTopCutoff = std::make_shared<Plane>();
844 pPlaneTopCutoff->setPlane(corners.lft, pointTowardTop);
845 }
catch (std::invalid_argument &) {
848 prim[l_id] = pPlaneTopCutoff;
849 retAlgebraMatch <<
"-" << l_id <<
")";
852 return retAlgebraMatch.str();
878 auto pCone = std::make_shared<Cone>();
880 pCone->setNorm(normVec);
881 pCone->setAngle(angle);
884 std::stringstream retAlgebraMatch;
885 retAlgebraMatch <<
"(" << l_id <<
" ";
889 auto pPlaneBottom = std::make_shared<Plane>();
890 pPlaneBottom->setPlane(
parsePosition(pElemTipPoint), normVec);
891 prim[l_id] = pPlaneBottom;
892 retAlgebraMatch <<
"-" << l_id <<
")";
895 return retAlgebraMatch.str();
923 auto pCone = std::make_shared<Cone>();
925 pCone->setNorm(normVec);
926 pCone->setAngle(angle);
929 std::stringstream retAlgebraMatch;
930 retAlgebraMatch <<
"(" << l_id <<
" ";
934 auto pPlaneTop = std::make_shared<Plane>();
936 pointInPlane -= (normVec *
height);
937 pPlaneTop->setPlane(pointInPlane, normVec);
938 prim[l_id] = pPlaneTop;
939 retAlgebraMatch <<
"" << l_id <<
" ";
943 auto pPlaneBottom = std::make_shared<Plane>();
944 pPlaneBottom->setPlane(
parsePosition(pElemTipPoint), normVec);
945 prim[l_id] = pPlaneBottom;
946 retAlgebraMatch <<
"-" << l_id <<
")";
949 return retAlgebraMatch.str();
959 std::map<
int, std::shared_ptr<Surface>> &prim,
int &l_id) {
961 auto pPlaneFrontCutoff = std::make_shared<Plane>();
962 auto normal = (hex.
rfb - hex.
lfb).cross_prod(hex.
lft - hex.
lfb);
965 if (normal.scalar_prod(hex.
rfb - hex.
rbb) < 0)
967 pPlaneFrontCutoff->setPlane(hex.
lfb, normal);
968 prim[l_id] = pPlaneFrontCutoff;
969 std::stringstream retAlgebraMatch;
970 retAlgebraMatch <<
"(-" << l_id <<
" ";
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)
978 pPlaneBackCutoff->setPlane(hex.
lbb, normal);
979 prim[l_id] = pPlaneBackCutoff;
980 retAlgebraMatch <<
"" << l_id <<
" ";
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)
988 pPlaneLeftCutoff->setPlane(hex.
lfb, normal);
989 prim[l_id] = pPlaneLeftCutoff;
990 retAlgebraMatch <<
"" << l_id <<
" ";
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)
998 pPlaneRightCutoff->setPlane(hex.
rfb, normal);
999 prim[l_id] = pPlaneRightCutoff;
1000 retAlgebraMatch <<
"-" << l_id <<
" ";
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)
1008 pPlaneTopCutoff->setPlane(hex.
lft, normal);
1009 prim[l_id] = pPlaneTopCutoff;
1010 retAlgebraMatch <<
"-" << l_id <<
" ";
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)
1018 pPlaneBottomCutoff->setPlane(hex.
lfb, normal);
1019 prim[l_id] = pPlaneBottomCutoff;
1020 retAlgebraMatch <<
"" << l_id <<
")";
1023 return retAlgebraMatch.str();
1035 Element *pElem_lfb =
getShapeElement(pElem,
"left-front-bottom-point");
1037 Element *pElem_lbb =
getShapeElement(pElem,
"left-back-bottom-point");
1039 Element *pElem_rfb =
getShapeElement(pElem,
"right-front-bottom-point");
1041 Element *pElem_rbb =
getShapeElement(pElem,
"right-back-bottom-point");
1045 const bool isValid =
1046 pElem_lfb && pElem_lft && pElem_lbb && pElem_lbt && pElem_rfb && pElem_rft && pElem_rbb && pElem_rbt;
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";
1054 ERROR_MSG <<
"left-front-bottom-point\n";
1056 ERROR_MSG <<
"left-front-top-point\n";
1058 ERROR_MSG <<
"left-back-bottom-point\n";
1060 ERROR_MSG <<
"left-back-top-point\n";
1062 ERROR_MSG <<
"right-front-bottom-point\n";
1064 ERROR_MSG <<
"right-front-top-point\n";
1066 ERROR_MSG <<
"right-back-bottom-point\n";
1068 ERROR_MSG <<
"right-back-top-point\n";
1071 throw std::invalid_argument(ERROR_MSG.str());
1086 std::vector<double> rotateAngles = DegreesToRadians(
parsePosition(pElem_rot));
1087 const std::vector<double> rotateMatrix =
generateMatrix(rotateAngles[0], rotateAngles[1], rotateAngles[2]);
1134 Element *pElemApertureStart =
getShapeElement(pElem,
"aperture-start");
1152 const double halfSW = apertureStartWidth / 2;
1153 const double halfSH = apertureStartHeight / 2;
1154 const double halfEW = apertureEndWidth / 2;
1155 const double halfEH = apertureEndHeight / 2;
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);
1169 if (axis != DEFAULT_AXIS) {
1170 const Quat q(DEFAULT_AXIS, axis);
1185 std::vector<double> rotateAngles = DegreesToRadians(
parsePosition(pElem_rot));
1186 const std::vector<double> rotateMatrix =
generateMatrix(rotateAngles[0], rotateAngles[1], rotateAngles[2]);
1228 Element *pElemRadiusFromCentre =
getShapeElement(pElem,
"radius-from-centre-to-tube");
1238 auto pTorus = std::make_shared<Torus>();
1240 pTorus->setNorm(normVec);
1241 pTorus->setDistanceFromCentreToTube(radiusCentre);
1242 pTorus->setTubeRadius(radiusTube);
1243 prim[l_id] = pTorus;
1245 std::stringstream retAlgebraMatch;
1246 retAlgebraMatch <<
"(-" << l_id <<
")";
1249 return retAlgebraMatch.str();
1265 std::map<
int, std::shared_ptr<Surface>> &prim,
int &l_id) {
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.";
1279 const double middleRadius = (outerRadius + innerRadius) / 2.0;
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);
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);
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 <<
" ";
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 <<
" ";
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 <<
" ";
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 <<
" ";
1351 auto pPlaneSlice1 = std::make_shared<Plane>();
1352 pPlaneSlice1->setPlane(centrePoint, planeSlice1);
1353 prim[l_id] = pPlaneSlice1;
1354 retAlgebraMatch <<
"-" << l_id <<
" ";
1357 auto pPlaneSlice2 = std::make_shared<Plane>();
1358 pPlaneSlice2->setPlane(centrePoint, planeSlice2);
1359 prim[l_id] = pPlaneSlice2;
1360 retAlgebraMatch <<
"" << l_id <<
")";
1363 return retAlgebraMatch.str();
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 +
">.");
1384 auto *retVal =
static_cast<Element *
>(pNL->item(0));
1401 Poco::AutoPtr<NodeList> pNL = pElem->getElementsByTagName(
name);
1402 if (pNL->length() == 0)
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 +
">.");
1408 auto *retVal =
static_cast<Element *
>(pNL->item(0));
1423 if (pElem->hasAttribute(
name)) {
1424 return std::stod(pElem->getAttribute(
name));
1426 throw std::invalid_argument(
"XML element: <" + pElem->tagName() +
"> does not have the attribute: " +
name +
".");
1438 if (pElem->hasAttribute(
"R") || pElem->hasAttribute(
"theta") || pElem->hasAttribute(
"phi")) {
1439 double R = 0.0, theta = 0.0, phi = 0.0;
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"));
1449 }
else if (pElem->hasAttribute(
"r") || pElem->hasAttribute(
"t") || pElem->hasAttribute(
"p"))
1454 double R = 0.0, theta = 0.0, phi = 0.0;
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"));
1465 double x = 0.0,
y = 0.0,
z = 0.0;
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"));
1487 const int surfaceID = 1;
1488 const std::map<int, std::shared_ptr<Surface>> primitives{{surfaceID, std::make_shared<Sphere>(
centre, radius)}};
1490 auto shape = std::make_shared<CSGObject>();
1492 shape->populate(primitives);
1494 auto handler = std::make_shared<GeometryHandler>(shape);
1495 shape->setGeometryHandler(handler);
1498 handler->setShapeInfo(std::move(shapeInfo));
1500 shape->defineBoundingBox(radius, radius, radius, -radius, -radius, -radius);
1517 double ylb,
double ylf,
double yrf,
double yrb) {
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);
1529 std::map<int, std::shared_ptr<Surface>> prim;
1533 auto shape = std::make_shared<CSGObject>();
1534 shape->setObject(21, algebra);
1535 shape->populate(prim);
1537 auto handler = std::make_shared<GeometryHandler>(shape);
1539 shape->setGeometryHandler(handler);
1543 handler->setShapeInfo(std::move(shapeInfo));
1545 shape->defineBoundingBox(std::max(xrb, xrf), yrf, ZDEPTH, std::min(xlf, xlb), ylb, 0);
1553 auto geomHandler = std::make_shared<GeometryHandler>(Obj);
1555 Obj->setGeometryHandler(geomHandler);
1557 if (pElem->tagName() ==
"cuboid") {
1559 shapeInfo.
setCuboid(corners.lfb, corners.lft, corners.lbb, corners.rfb);
1560 }
else if (pElem->tagName() ==
"hexahedron") {
1562 shapeInfo.
setHexahedron(corners.lbb, corners.lfb, corners.rfb, corners.rbb, corners.lbt, corners.lft, corners.rft,
1564 }
else if (pElem->tagName() ==
"sphere") {
1570 shapeInfo.
setSphere(
centre, std::stod(pElemRadius->getAttribute(
"val")));
1571 }
else if (pElem->tagName() ==
"cylinder") {
1572 Element *pElemCentre =
getShapeElement(pElem,
"centre-of-bottom-base");
1578 std::stod(pElemHeight->getAttribute(
"val")));
1579 }
else if (pElem->tagName() ==
"hollow-cylinder") {
1580 Element *pElemCentre =
getShapeElement(pElem,
"centre-of-bottom-base");
1588 std::stod(pElemOuterRadius->getAttribute(
"val")),
1589 std::stod(pElemHeight->getAttribute(
"val")));
1590 }
else if (pElem->tagName() ==
"cone") {
1597 const double height = std::stod(pElemHeight->getAttribute(
"val"));
1598 const double radius =
height * tan(M_PI * std::stod(pElemAngle->getAttribute(
"val")) / 180.0);
1602 geomHandler->setShapeInfo(std::move(shapeInfo));
1618 return zMatrix * yMatrix * xMatrix;
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};
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};
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};
1660 for (
size_t i = 0; i < 3; ++i) {
1661 for (
size_t j = 0; j < 3; ++j) {
1673 const std::string openTag =
"<" + tagName;
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);
1684 std::size_t tagPlace = xml.find(
"</type>");
1685 if (tagPlace == std::string::npos) {
1686 tagPlace = xml.find(
"</samplegeometry");
1688 if (tagPlace == std::string::npos) {
1689 tagPlace = xml.
size();
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] <<
"' ";
1703 xml.insert(tagPlace, tag.str());
1713 return insertMatrixTag(
"applied-goniometer", bakedRotation, std::move(xml));
1719 const std::string &tagName) {
1720 Poco::AutoPtr<Document> pDoc;
1723 pDoc = DOMParser().parseString(
"<type name=\"userShape\"> " + xml +
" </type>");
1725 return std::nullopt;
1727 Poco::AutoPtr<NodeList> pNL = pDoc->getElementsByTagName(tagName);
1728 if (pNL->length() == 0) {
1729 return std::nullopt;
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 > ¤tBake)
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 ¢re, 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 ¢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.
Matrix< T > Tprime() const
Transpose the 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.
std::pair< size_t, size_t > size() const
Access matrix sizes.
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)