14#include "Poco/DOM/AutoPtr.h"
15#include "Poco/DOM/DOMParser.h"
16#include "Poco/DOM/Document.h"
17#include "Poco/DOM/NodeList.h"
18#include <Poco/DOM/Element.h>
19#include <boost/algorithm/string/trim.hpp>
23constexpr auto SAMPLE_OBJECT_NAME =
"SAMPLE";
24constexpr double M_TOLERANCE = 0.000001;
28namespace DataHandling {
38 Lib3MF::PReader reader =
model->QueryReader(
"3mf");
41 reader->SetStrictModeActive(
false);
42 reader->ReadFromFile(filename);
46 switch (
model->GetUnit()) {
47 case Lib3MF::eModelUnit::MilliMeter:
50 case Lib3MF::eModelUnit::CentiMeter:
53 case Lib3MF::eModelUnit::Meter:
59 g_log.
warning(
"Only m, cm and mm are supported in Mantid");
64 for (Lib3MF_uint32 iWarning = 0; iWarning < reader->GetWarningCount(); iWarning++) {
65 Lib3MF_uint32 nErrorCode;
66 std::string sWarningMessage = reader->GetWarning(iWarning, nErrorCode);
68 ss <<
"Encountered warning #" << nErrorCode <<
" : " << sWarningMessage << std::endl;
82 Lib3MF_uint64 nVertexCount = meshObject->GetVertexCount();
83 Lib3MF_uint64 nTriangleCount = meshObject->GetTriangleCount();
87 g_log.
debug(
"Name: \"" + meshObject->GetName() +
"\"");
88 g_log.
debug(
"PartNumber: \"" + meshObject->GetPartNumber() +
"\"");
92 uint32_t vertexCount = 0;
93 std::vector<Lib3MF::sTriangle> triangles;
94 meshObject->GetTriangleIndices(triangles);
99 for (
auto i : triangles) {
104 std::vector<Lib3MF::sPosition> vertices;
105 meshObject->GetVertices(vertices);
106 for (
auto i : vertices) {
113 Lib3MF_uint32 nResourceID;
114 Lib3MF_uint32 nPropertyID;
117 if (meshObject->GetObjectLevelProperty(nResourceID, nPropertyID)) {
119 Lib3MF::ePropertyType propType =
model->GetPropertyTypeByID(nResourceID);
121 if (propType == Lib3MF::ePropertyType::BaseMaterial) {
123 Lib3MF::PBaseMaterialGroup baseMaterialGroup =
model->GetBaseMaterialGroupByID(nResourceID);
125 std::string fullMaterialName = baseMaterialGroup->GetName(nPropertyID);
126 std::string materialName;
127 size_t openBracket = fullMaterialName.find(
"(");
128 size_t closeBracket = fullMaterialName.find(
")");
130 materialName = fullMaterialName.substr(0, openBracket);
131 boost::algorithm::trim(materialName);
132 std::string xmlString;
134 xmlString =
"<material id=\"" + materialName +
"\" formula=\"" + materialName +
"\"";
135 if ((openBracket != std::string::npos) && (closeBracket != std::string::npos)) {
136 std::string materialSpec = fullMaterialName.substr(openBracket + 1, closeBracket - openBracket - 1);
137 xmlString +=
" " + materialSpec;
139 xmlString +=
"></material>";
140 Poco::XML::DOMParser parser;
141 Poco::XML::AutoPtr<Poco::XML::Document> doc;
143 doc = parser.parseString(xmlString);
144 Poco::XML::AutoPtr<Poco::XML::NodeList> materialElements = doc->getElementsByTagName(
"material");
146 material = materialParser.
parse(
static_cast<Poco::XML::Element *
>(materialElements->item(0)),
m_filename);
147 }
catch (std::exception &e) {
148 g_log.
warning(
"Unable to parse material properties for " + fullMaterialName +
149 " so material will be ignored: " + e.what());
154 auto mesh = std::make_shared<Geometry::MeshObject>(std::move(
m_triangle), std::move(
m_vertices), material);
155 mesh->setID(meshObject->GetName());
162 for (
size_t i = 0; i < 4; i++) {
163 for (
size_t j = 0; j < 3; j++) {
164 transformMatrix[j][i] = buildTransform.m_Fields[i][j];
168 transformMatrix.
setRow(3, {0, 0, 0, 1});
170 for (
size_t i = 0; i < 3; i++) {
171 transformMatrix[i][3] =
scaleValue(transformMatrix[i][3]);
174 mesh->multiply(transformMatrix);
185 Lib3MF::PBuildItemIterator buildItemIterator =
model->GetBuildItems();
186 while (buildItemIterator->MoveNext()) {
187 Lib3MF::PBuildItem buildItem = buildItemIterator->GetCurrent();
188 uint32_t objectResourceID = buildItem->GetObjectResourceID();
189 sLib3MFTransform transform = buildItem->GetObjectTransform();
203 uint32_t objectResourceID, sLib3MFTransform transform) {
206 Lib3MF::PMeshObject meshObject =
model->GetMeshObjectByID(objectResourceID);
207 std::string objectName = meshObject->GetName();
208 std::transform(objectName.begin(), objectName.end(), objectName.begin(), toupper);
209 if (objectName == SAMPLE_OBJECT_NAME) {
214 }
catch (std::exception) {
226 uint32_t objectResourceID, sLib3MFTransform transform) {
227 Lib3MF::PComponentsObject componentsObject =
model->GetComponentsObjectByID(objectResourceID);
228 for (Lib3MF_uint32 nIndex = 0; nIndex < componentsObject->GetComponentCount(); nIndex++) {
229 Lib3MF::PComponent component = componentsObject->GetComponent(nIndex);
230 readMeshObject(meshObjects, sample, component->GetObjectResourceID(), transform);
241 Lib3MF::PMeshObject meshObject =
model->AddMeshObject();
242 meshObject->SetName(name);
243 std::vector<uint32_t> mantidTriangles = mantidMeshObject.
getTriangles();
244 std::vector<Kernel::V3D> mantidVertices = mantidMeshObject.
getV3Ds();
245 std::vector<sLib3MFTriangle> triangles;
246 std::vector<sLib3MFPosition> vertices;
249 for (
auto i : mantidVertices) {
250 sLib3MFPosition vertex = {
251 {
static_cast<Lib3MF_single
>(i.X()),
static_cast<Lib3MF_single
>(i.Y()),
static_cast<Lib3MF_single
>(i.Z())}};
252 vertices.push_back(vertex);
256 for (
size_t i = 0; i < numTriangles; i++) {
257 sLib3MFTriangle triangle;
259 Kernel::V3D a = mantidVertices[mantidTriangles[3 * i]];
260 Kernel::V3D b = mantidVertices[mantidTriangles[3 * i + 1]];
261 Kernel::V3D c = mantidVertices[mantidTriangles[3 * i + 2]];
270 auto firstLink = faceNormalTrack.
front();
272 if (firstLink.distInsideObject > M_TOLERANCE) {
273 g_log.
debug(
"Face normal pointing to interior of object on object " + mantidMeshObject.
id() +
274 ". Vertices swapped");
276 mantidVertices[3 * i + 1] = c;
277 mantidVertices[3 * i + 2] = b;
280 for (
int j = 0; j < 3; j++) {
281 triangle.m_Indices[j] = mantidTriangles[3 * i + j];
284 triangles.push_back(triangle);
286 meshObject->SetGeometry(vertices, triangles);
289 Lib3MF_uint32 materialPropertyID;
290 int baseMaterialsResourceID;
294 meshObject->SetObjectLevelProperty(baseMaterialsResourceID, materialPropertyID);
299 sLib3MFTransform mMatrix = {{{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, 0.0}}};
300 model->AddBuildItem(meshObject.get(), mMatrix);
308int Mantid3MFFileIO ::generateRandomColor() {
310 int rColor = (rand() % 256) << 16;
311 int gColor = (rand() % 256) << 8;
312 int bColor = (rand() % 256) << 0;
314 return rColor | gColor | bColor;
328 Lib3MF::eModelUnit scale;
331 scale = Lib3MF::eModelUnit::MilliMeter;
334 scale = Lib3MF::eModelUnit::CentiMeter;
337 scale = Lib3MF::eModelUnit::Meter;
340 throw "Units not supported";
342 model->SetUnit(scale);
346 for (
auto mantidMeshObject : meshObjects) {
361 Lib3MF_uint32 &materialPropertyID) {
363 bool materialNameExists =
false;
365 Lib3MF::PBaseMaterialGroupIterator materialIterator =
model->GetBaseMaterialGroups();
366 Lib3MF::PBaseMaterialGroup groupToAddTo;
368 if (materialIterator->Count() == 0) {
369 groupToAddTo =
model->AddBaseMaterialGroup();
371 while (materialIterator->MoveNext() && !materialNameExists) {
372 Lib3MF::PBaseMaterialGroup materialGroup = materialIterator->GetCurrentBaseMaterialGroup();
376 groupToAddTo = materialGroup;
378 std::vector<Lib3MF_uint32> materialPropertyIDs;
379 materialGroup->GetAllPropertyIDs(materialPropertyIDs);
380 for (
auto i : materialPropertyIDs) {
381 std::string existingMaterialName = materialGroup->GetName(i);
382 if (materialName == existingMaterialName) {
383 materialNameExists =
true;
384 groupToAddTo = materialGroup;
385 materialPropertyID = i;
391 Lib3MF_uint8 rColor = (materialColor & 0xFF0000) >> 16;
392 Lib3MF_uint8 gColor = (materialColor & 0x00FF00) >> 8;
393 Lib3MF_uint8 bColor = (materialColor & 0x0000FF) >> 0;
394 if (!materialNameExists) {
395 materialPropertyID = groupToAddTo->AddMaterial(materialName, Lib3MF::sColor{rColor, gColor, bColor, 255});
397 resourceID = groupToAddTo->GetResourceID();
410 Lib3MF_uint32 materialPropertyID;
411 int baseMaterialsResourceID;
412 AddBaseMaterial(materialName, materialColor, baseMaterialsResourceID, materialPropertyID);
414 Lib3MF::PMeshObjectIterator meshObjectIterator =
model->GetMeshObjects();
415 bool meshObjectFound =
false;
416 while (meshObjectIterator->MoveNext()) {
417 Lib3MF::PMeshObject meshObject = meshObjectIterator->GetCurrentMeshObject();
419 if (meshObject->GetName() == objectName) {
420 meshObjectFound =
true;
421 Lib3MF_uint32 resourceID, propertyID;
422 bool propExists = meshObject->GetObjectLevelProperty(resourceID, propertyID);
426 Lib3MF::ePropertyType propType =
model->GetPropertyTypeByID(resourceID);
427 if (baseMaterialsResourceID == resourceID) {
429 g_log.
debug(
"Existing material found for object " + objectName +
". Overwriting with material " +
430 materialName +
"supplied in csv file");
431 meshObject->SetObjectLevelProperty(baseMaterialsResourceID, materialPropertyID);
435 g_log.
debug(
"Existing non-material property found for object " + objectName +
436 ". Overwriting with material property with value " + materialName +
" supplied in csv file");
440 meshObject->ClearAllProperties();
441 meshObject->SetObjectLevelProperty(baseMaterialsResourceID, materialPropertyID);
445 meshObject->SetObjectLevelProperty(baseMaterialsResourceID, materialPropertyID);
449 if (!meshObjectFound) {
450 g_log.
debug(
"Object " + objectName +
" not found in 3MF file");
459 Lib3MF::PWriter writer =
model->QueryWriter(
"3mf");
460 writer->WriteToFile(filename);
void readMeshObject(std::vector< MeshObject_sptr > &meshObjects, MeshObject_sptr &sample, uint32_t objectResourceID, sLib3MFTransform transform)
Attempt to read a single mesh from a specified lib3mf resource id.
int generateRandomColor()
MeshObject_sptr loadMeshObject(Lib3MF::PMeshObject meshObject, sLib3MFTransform buildTransform)
Load a single mesh object into a Mantid Geometry::MeshObject.
void AddBaseMaterial(std::string materialName, int materialColor, int &resourceID, Lib3MF_uint32 &materialPropertyID)
void readComponents(std::vector< MeshObject_sptr > &meshObjects, MeshObject_sptr &sample, uint32_t objectResourceID, sLib3MFTransform transform)
void readMeshObjects(std::vector< MeshObject_sptr > &meshObjects, MeshObject_sptr &sample)
Read a set of mesh objects from the in memory lib3mf model object.
void writeMeshObjects(std::vector< const Geometry::MeshObject * > meshObjects, MeshObject_const_sptr &sample, DataHandling::ScaleUnits scale)
void writeMeshObject(const Geometry::MeshObject &meshObject, std::string name)
void LoadFile(std::string filename)
Load 3MF format file.
void saveFile(std::string filename)
void setMaterialOnObject(std::string objectName, std::string materialName, int materialColor)
std::vector< uint32_t > m_triangle
Kernel::V3D createScaledV3D(double xVal, double yVal, double zVal)
scales a 3D point according the units defined in the MeshFileIO class
double scaleValue(double val)
std::vector< Kernel::V3D > m_vertices
void setScaleType(const ScaleUnits scaleType)
size_t numberOfTriangles() const
Output functions for rendering, may also be used internally.
int interceptSurface(Geometry::Track &) const override
Given a track, fill the track with valid section.
std::vector< uint32_t > getTriangles() const
get faces
const std::vector< Kernel::V3D > & getV3Ds() const
get vertices in V3D form
const Kernel::Material & material() const override
const std::string & id() const override
Defines a track as a start point and a direction.
LType::reference front()
Returns a reference to the first link.
void debug(const std::string &msg)
Logs at debug level.
void warning(const std::string &msg)
Logs at warning level.
Read an XML definition of a Material and produce a new Material object.
Material parse(std::istream &istr) const
Takes a stream that is assumed to contain a single complete material definition, reads the definition...
A material is defined as being composed of a given element, defined as a PhysicalConstants::NeutronAt...
const std::string & name() const
Returns the name of the material.
void setRow(const size_t nRow, const std::vector< T > &newRow)
constexpr V3D cross_prod(const V3D &v) const noexcept
Cross product (this * argument)
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< Geometry::MeshObject > MeshObject_sptr
Typdef for a shared pointer.
std::shared_ptr< const Geometry::MeshObject > MeshObject_const_sptr
Typdef for a shared pointer to a const object.
MANTID_KERNEL_DLL V3D normalize(V3D v)
Normalizes a V3D.
Helper class which provides the Collimation Length for SANS instruments.
std::string to_string(const wide_integer< Bits, Signed > &n)
This struct contains the parameters for constructing a material, and gives them a default value for e...