17#include <boost/algorithm/string/classification.hpp>
18#include <boost/algorithm/string/split.hpp>
36 "The workspace containing the sample whose orientation is to be rotated");
38 std::string axisHelp =
": degrees,x,y,z,1/-1 (1 for ccw, -1 for cw rotation).";
39 for (
size_t i = 0; i <
NUM_AXES; i++) {
40 std::ostringstream propName;
41 propName <<
"Axis" << i;
43 propName.str() + axisHelp);
51 auto ei = std::dynamic_pointer_cast<ExperimentInfo>(ws);
55 auto infos = std::dynamic_pointer_cast<MultipleExperimentInfos>(ws);
57 throw std::invalid_argument(
"Input workspace does not support RotateSampleShape");
59 if (infos->getNumExperimentInfo() < 1) {
61 infos->addExperimentInfo(info);
63 ei = infos->getExperimentInfo(0);
67 bool isMeshShape =
false;
69 throw std::runtime_error(
"Input sample does not have a valid shape!");
76 g_log.
warning() <<
"Empty goniometer created; will always return an "
77 "identity rotation matrix.\n";
79 const auto &sampleShapeRotation = gon.
getR();
82 g_log.
warning(
"Rotation matrix set via RotateSampleShape is an Identity matrix. Ignored rotating sample shape");
86 const auto &oldRotation = ei->run().getGoniometer().getR();
87 auto newSampleShapeRot = sampleShapeRotation * oldRotation;
89 auto meshShape = std::dynamic_pointer_cast<MeshObject>(ei->sample().getShapePtr());
90 meshShape->rotate(newSampleShapeRot);
99 if (ei->sample().hasShape()) {
100 const auto csgShape = std::dynamic_pointer_cast<CSGObject>(ei->sample().getShapePtr());
101 if (csgShape && csgShape->hasValidShape()) {
102 shapeXML = csgShape->getShapeXML();
103 if (!shapeXML.empty()) {
107 const auto meshShape = std::dynamic_pointer_cast<MeshObject>(ei->sample().getShapePtr());
108 if (meshShape && meshShape->hasValidShape()) {
118 for (
size_t i = 0; i <
NUM_AXES; i++) {
119 std::ostringstream propName;
120 propName <<
"Axis" << i;
122 if (!axisDesc.empty()) {
123 std::vector<std::string> tokens;
124 boost::split(tokens, axisDesc, boost::algorithm::detail::is_any_ofF<char>(
","));
125 if (tokens.size() != 5)
126 throw std::invalid_argument(
"Wrong number of arguments to parameter " + propName.str() +
127 ". Expected 5 comma-separated arguments.");
129 std::transform(tokens.begin(), tokens.end(), tokens.begin(),
130 [](
const std::string &str) { return Strings::strip(str); });
131 if (!std::all_of(tokens.begin(), tokens.end(), [](
const std::string &tokenStr) { return !tokenStr.empty(); })) {
132 throw std::invalid_argument(
"Empty axis parameters found!");
137 throw std::invalid_argument(
"Error converting angle string '" + tokens[0] +
"' to a number.");
140 std::string axisName =
"RotateSampleShapeAxis" +
Strings::toString(i) +
"_FixedValue";
141 double x = 0,
y = 0,
z = 0;
143 throw std::invalid_argument(
"Error converting x string '" + tokens[1] +
"' to a number.");
145 throw std::invalid_argument(
"Error converting y string '" + tokens[2] +
"' to a number.");
147 throw std::invalid_argument(
"Error converting z string '" + tokens[3] +
"' to a number.");
149 if (
vec.norm() < 1e-4)
150 throw std::invalid_argument(
"Rotation axis vector should be non-zero!");
154 throw std::invalid_argument(
"Error converting sense of roation '" + tokens[4] +
"' to a number.");
156 if (ccw != 1 && ccw != -1) {
157 throw std::invalid_argument(
"The sense of rotation parameter must only be 1 (ccw) or -1 (cw)");
#define DECLARE_ALGORITHM(classname)
std::vector< T > const * vec
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
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.
static void setSampleShape(API::ExperimentInfo &expt, const std::string &shapeXML, bool addTypeTag=true)
Set the shape via an XML string on the given experiment.
void exec() override
Run the algorithm.
bool checkIsValidShape(const API::ExperimentInfo_sptr &ei, std::string &shapeXML, bool &isMeshShape)
void prepareGoniometerAxes(Goniometer &gon)
void init() override
Initialise the properties.
Class to represent a particular goniometer setting, which is described by the rotation matrix.
size_t getNumberAxes() const
void pushAxis(const std::string &name, double axisx, double axisy, double axisz, double angle=0., int sense=CCW, int angUnit=angDegrees)
Add an additional axis to the goniometer, closer to the sample.
const Kernel::DblMatrix & getR() const
Return global rotation matrix.
Class originally intended to be used with the DataHandling 'LoadInstrument' algorithm.
std::string addGoniometerTag(const Kernel::Matrix< double > &rotateMatrix, std::string xml)
void warning(const std::string &msg)
Logs at warning level.
The concrete, templated class for properties.
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< ExperimentInfo > ExperimentInfo_sptr
Shared pointer to ExperimentInfo.
const size_t NUM_AXES
How many axes (max) to define.
int convert(const std::string &A, T &out)
Convert a string into a number.
std::string toString(const T &value)
Convert a number to a string.
@ InOut
Both an input & output workspace.
@ Input
An input workspace.