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/Node.h>
33#include <Poco/DOM/NodeFilter.h>
34#include <Poco/DOM/NodeIterator.h>
35#include <Poco/DOM/NodeList.h>
46bool isPointLike(
const std::string &tag) {
47 if (tag ==
"axis" || tag ==
"normal-to-plane")
50 if (tag ==
"centre" || tag ==
"centre-of-bottom-base" || tag ==
"tip" || tag ==
"point-in-plane")
53 if (tag.size() >= 6 && tag.rfind(
"-point") == tag.size() - 6)
59void shiftAttribute(Element *e,
const std::string &attr,
double d) {
62 if (!e->hasAttribute(attr))
64 const double v = std::stod(e->getAttribute(attr));
68Element *firstElem(Element *parent,
const std::string &tag) {
71 Poco::AutoPtr<NodeList> nl = parent->getElementsByTagName(tag);
72 if (nl && nl->length() > 0)
73 return static_cast<Poco::XML::Element *
>(nl->item(0));
78void addXYZ(Element *el,
double dx,
double dy,
double dz) {
79 if (el->hasAttribute(
"x") && el->hasAttribute(
"y") && el->hasAttribute(
"z")) {
80 shiftAttribute(el,
"x", dx);
81 shiftAttribute(el,
"y", dy);
82 shiftAttribute(el,
"z", dz);
87void shiftBoundingBox(Element *root,
double dx,
double dy,
double dz) {
90 Element *bb = firstElem(root,
"bounding-box");
94 shiftAttribute(firstElem(bb,
"x-min"),
"val", dx);
95 shiftAttribute(firstElem(bb,
"x-max"),
"val", dx);
96 shiftAttribute(firstElem(bb,
"y-min"),
"val", dy);
97 shiftAttribute(firstElem(bb,
"y-max"),
"val", dy);
98 shiftAttribute(firstElem(bb,
"z-min"),
"val", dz);
99 shiftAttribute(firstElem(bb,
"z-max"),
"val", dz);
104std::string writeOnlyElementChildNodes(Poco::XML::Element *root) {
106 return std::string();
108 std::ostringstream out;
112 for (Node *
n = root->firstChild();
n;
n =
n->nextSibling()) {
113 if (
n->nodeType() == Node::ELEMENT_NODE) {
114 writer.writeNode(out,
n);
122std::string removeTypeTagWrapper(
const std::string &xml) {
124 Poco::AutoPtr<Document> doc;
126 doc = parser.parseString(xml);
128 throw std::runtime_error(
"Invalid CSG XML encountered");
130 Element *root = doc ? doc->documentElement() :
nullptr;
134 const std::string tag = root->tagName();
136 return writeOnlyElementChildNodes(root);
143std::string translateCSG(
const std::string &xml,
double dx,
double dy,
double dz) {
145 Poco::AutoPtr<Document> doc = parser.parseString(xml);
148 Element *root = doc ? doc->documentElement() :
nullptr;
154 NodeIterator it(doc, NodeFilter::SHOW_ELEMENT);
155 for (Node *
n = it.nextNode();
n;
n = it.nextNode()) {
156 auto *el =
dynamic_cast<Element *
>(
n);
159 const std::string tag = el->tagName();
161 if (isPointLike(tag)) {
162 addXYZ(el, dx, dy, dz);
167 shiftBoundingBox(root, dx, dy, dz);
169 std::ostringstream out;
171 writer.writeNode(out, doc);
190 "The workspace containing the sample whose shape is to be translated");
195 "Vector by which to translate the loaded sample shape (metres)");
202 auto ei = std::dynamic_pointer_cast<ExperimentInfo>(ws);
203 const std::vector<double> translationVector =
getProperty(
"TranslationVector");
207 auto infos = std::dynamic_pointer_cast<MultipleExperimentInfos>(ws);
209 throw std::invalid_argument(
"Input workspace does not support TranslateSampleShape");
211 if (infos->getNumExperimentInfo() < 1) {
213 infos->addExperimentInfo(info);
215 ei = infos->getExperimentInfo(0);
218 std::string shapeXML;
219 bool isMeshShape =
false;
221 throw std::runtime_error(
"Input sample does not have a valid shape!");
224 const auto dx = translationVector[0];
225 const auto dy = translationVector[1];
226 const auto dz = translationVector[2];
230 auto meshShape = std::dynamic_pointer_cast<MeshObject>(ei->sample().getShapePtr());
231 meshShape->translate(
V3D(dx, dy, dz));
234 auto csgShape = std::dynamic_pointer_cast<CSGObject>(ei->sample().getShapePtr());
237 const std::string &origXML = csgShape->getShapeXML();
240 std::string translatedXML = translateCSG(origXML, dx, dy, dz);
243 translatedXML = removeTypeTagWrapper(translatedXML);
252 if (ei->sample().hasShape()) {
253 const auto csgShape = std::dynamic_pointer_cast<CSGObject>(ei->sample().getShapePtr());
254 if (csgShape && csgShape->hasValidShape()) {
255 shapeXML = csgShape->getShapeXML();
256 if (!shapeXML.empty()) {
260 const auto meshShape = std::dynamic_pointer_cast<MeshObject>(ei->sample().getShapePtr());
261 if (meshShape && meshShape->hasValidShape()) {
271 auto creator = AlgorithmManager::Instance().create(
"CreateSampleShape");
272 creator->initialize();
273 creator->setChild(
true);
274 creator->setProperty(
"InputWorkspace", ws);
275 creator->setPropertyValue(
"ShapeXML", translatedXML);
#define DECLARE_ALGORITHM(classname)
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
This class is shared by a few Workspace types and holds information related to a particular experimen...
A property class for workspaces.
bool checkIsValidShape(const API::ExperimentInfo_sptr &ei, std::string &shapeXML, bool &isMeshShape)
void setSampleShape(const API::Workspace_sptr &ws, std::string &translatedXML)
void exec() override
Run the algorithm.
void init() override
Initialise the properties.
ArrayLenghtValidator : Validate length of an array property.
Support for a property that holds an array of values.
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< ExperimentInfo > ExperimentInfo_sptr
Shared pointer to ExperimentInfo.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ InOut
Both an input & output workspace.