Mantid
Loading...
Searching...
No Matches
SaveSampleEnvironmentAndShape.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2019 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 +
11#include "MantidAPI/Sample.h"
12#ifdef ENABLE_LIB3MF
14#endif
19
20#include <filesystem>
21#include <memory>
22
23namespace Mantid::DataHandling {
24// Register the algorithm into the algorithm factory
25DECLARE_ALGORITHM(SaveSampleEnvironmentAndShape)
26
27using namespace Kernel;
28using namespace API;
29using namespace Geometry;
30
32 auto wsValidator = std::make_shared<InstrumentValidator>();
33
34 // input workspace
35 declareProperty(std::make_unique<WorkspaceProperty<>>("InputWorkspace", "", Direction::Input, wsValidator),
36 "The name of the workspace containing the environment to save ");
37
38 // Environment file
39 const std::vector<std::string> extensions{".stl", ".3mf"};
40 declareProperty(std::make_unique<FileProperty>("Filename", "", FileProperty::Save, extensions),
41 "The path name of the file to save");
42
43 // scale to use for stl
44 declareProperty("Scale", "m", "The scale of the stl: m, cm, or mm");
45}
46
48 const MeshObject &sampleShape, const std::vector<const Geometry::MeshObject *> &environmentPieces) {
49
50 if (environmentPieces.size() > 0) {
51
52 // get the sample vertices and triangles and add them into the vector
53 addMeshToVector(sampleShape);
54
55 // keep track of the current number of vertices added
56 size_t offset = sampleShape.numberOfVertices();
57
58 // go through the environment, adding the triangles and vertices to the
59 // vector
60 offset = std::accumulate(environmentPieces.begin(), environmentPieces.end(), offset,
61 [this](size_t currentOffset, const Geometry::MeshObject *mesh) {
62 return addMeshToVector(*mesh, currentOffset);
63 });
64 } else {
65 // get the sample vertices and triangles and add them into the vector
66 addMeshToVector(sampleShape);
67 }
68}
69
71 MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
72 // track the total number of triangles and vertices
73 size_t numTriangles = 0;
74 size_t numVertices = 0;
75
76 // Get the shape of the sample
77 const auto &sampleShape = toMeshObject(inputWS->sample().getShape());
78 if (!sampleShape.hasValidShape()) {
79 throw std::invalid_argument("Sample Shape is not complete");
80 }
81 numVertices += sampleShape.numberOfVertices();
82 numTriangles += (sampleShape.numberOfTriangles() * 3);
83
84 // Setup vector to store the pieces of the environment
85 std::vector<const MeshObject *> environmentPieces;
86
87 if (inputWS->sample().hasEnvironment()) {
88 // get the environment
89 auto environment = inputWS->sample().getEnvironment();
90
91 auto numElements = environment.nelements();
92 environmentPieces.reserve(numElements);
93
94 // get the shape the container of the environment and add it to the vector
95 bool environmentValid = true;
96 environmentPieces.emplace_back(&toMeshObject(environment.getContainer().getShape()));
97 environmentValid = environmentValid && environmentPieces[0]->hasValidShape();
98 numVertices += environmentPieces[0]->numberOfVertices();
99 numTriangles += (environmentPieces[0]->numberOfTriangles() * 3);
100
101 // get the shapes of the components and add them to the vector
102 for (size_t i = 1; i < numElements; ++i) { // start at 1 because element 0 is container
103 const MeshObject *temp = &toMeshObject(environment.getComponent(i));
104 numVertices += temp->numberOfVertices();
105 numTriangles += (temp->numberOfTriangles() * 3);
106 environmentValid = environmentValid && temp->hasValidShape();
107 environmentPieces.emplace_back(temp);
108 }
109 if (!environmentValid) {
110 throw std::invalid_argument("Environment Shape is not complete");
111 }
112 }
113 // get the scale to use
114 auto scale = getPropertyValue("Scale");
115 auto scaleType = getScaleTypeFromStr(scale);
116
117 // Save out the shape
118 auto filename = getPropertyValue("Filename");
119 std::string fileExt = std::filesystem::path(filename).extension().string().substr(1); // remove the '.'
120 std::transform(fileExt.begin(), fileExt.end(), fileExt.begin(), toupper);
121
122 if (fileExt == "STL") {
123 // setup vectors to store all triangles and vertices
124 m_vertices.reserve(numVertices);
125 m_triangle.reserve(numTriangles);
126 mergeSampleEnvironmentIntoSingleMesh(sampleShape, environmentPieces);
127 SaveStl writer = SaveStl(filename, m_triangle, m_vertices, scaleType);
128 writer.writeStl();
129 } else {
130#ifdef ENABLE_LIB3MF
131 Mantid3MFFileIO Mesh3MF;
132 auto samplePtr = MeshObject_const_sptr(&sampleShape);
133 Mesh3MF.writeMeshObjects(environmentPieces, samplePtr, scaleType);
134 Mesh3MF.saveFile(filename);
135#else
136 throw std::runtime_error("3MF format not supported on this platform");
137#endif
138 }
139}
140
148 auto vertices = mesh.getV3Ds();
149 auto triangles = mesh.getTriangles();
150 m_vertices.insert(std::end(m_vertices), std::begin(vertices), std::end(vertices));
151 m_triangle.insert(std::end(m_triangle), std::begin(triangles), std::end(triangles));
152}
153
165 auto vertices = mesh.getV3Ds();
166 auto triangles = mesh.getTriangles();
167
168 // increase the triangles by the offset, so they refer to the new index of
169 // the vertices
170 std::transform(std::begin(triangles), std::end(triangles), std::begin(triangles),
171 [&offset](const uint32_t &val) { return val + uint32_t(offset); });
172 m_vertices.insert(std::end(m_vertices), std::begin(vertices), std::end(vertices));
173 m_triangle.insert(std::end(m_triangle), std::begin(triangles), std::end(triangles));
174
175 // add the newly added vertices to the offset
176 return offset += vertices.size();
177}
178
186
187 try {
188 return dynamic_cast<const Geometry::MeshObject &>(object);
189 } catch (const std::bad_cast &) {
190 // if bad_cast is thrown the sample or environment is not a mesh_object, and
191 // therefore cannot be saved as an STL
192 throw std::invalid_argument("Attempted to Save out non mesh based Sample or Environment");
193 }
194}
195} // namespace Mantid::DataHandling
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
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.
@ Save
to specify a file to write to, the file may or may not exist
A property class for workspaces.
Class to load and save .3mf files .3mf format is a 3D manufacturing format for storing mesh descripti...
void writeMeshObjects(std::vector< const Geometry::MeshObject * > meshObjects, MeshObject_const_sptr &sample, DataHandling::ScaleUnits scale)
void init() override
Virtual method - must be overridden by concrete algorithm.
void addMeshToVector(const Mantid::Geometry::MeshObject &mesh)
Function to add the triangles and vertices of a mesh object into a vector to allow combining with mul...
void mergeSampleEnvironmentIntoSingleMesh(const Mantid::Geometry::MeshObject &sample, const std::vector< const Geometry::MeshObject * > &environmentPieces)
void exec() override
Virtual method - must be overridden by concrete algorithm.
Class to contain functionality for writing out STL files for SaveShapeAndEnvironment.
Definition SaveStl.h:30
void writeStl()
Function to write out the full mesh to an stl binary file.
Definition SaveStl.cpp:78
IObject : Interface for geometry objects.
Definition IObject.h:42
Triangular Mesh Object.
Definition MeshObject.h:53
size_t numberOfTriangles() const
Output functions for rendering, may also be used internally.
bool hasValidShape() const override
Return whether this object has a valid shape.
const std::vector< Kernel::V3D > & getV3Ds() const
get vertices in V3D form
size_t numberOfVertices() const
Read access to mesh object for rendering.
const std::vector< uint32_t > & getTriangles() const
get faces
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
const Mantid::Geometry::MeshObject & toMeshObject(const Mantid::Geometry::IObject &object)
Function to convert an IObject to a mesh, and throw if this can't be done.
std::shared_ptr< const Geometry::MeshObject > MeshObject_const_sptr
Typdef for a shared pointer to a const object.
ScaleUnits getScaleTypeFromStr(const std::string &scaleProperty)
Definition MeshFileIO.h:73
@ Input
An input workspace.
Definition Property.h:53