diff --git a/src/Mod/Mesh/App/Core/MeshIO.cpp b/src/Mod/Mesh/App/Core/MeshIO.cpp
index 09d1ad91dcff..9fde9d851559 100644
--- a/src/Mod/Mesh/App/Core/MeshIO.cpp
+++ b/src/Mod/Mesh/App/Core/MeshIO.cpp
@@ -41,6 +41,7 @@
#include
#include
#include
+#include
#include
#include
@@ -1947,6 +1948,7 @@ std::vector MeshOutput::supportedMeshFormats()
fmt.emplace_back("wrz");
fmt.emplace_back("amf");
fmt.emplace_back("asy");
+ fmt.emplace_back("3mf");
return fmt;
}
@@ -2004,6 +2006,9 @@ MeshIO::Format MeshOutput::GetFormat(const char* FileName)
else if (file.hasExtension("amf")) {
return MeshIO::AMF;
}
+ else if (file.hasExtension("3mf")) {
+ return MeshIO::ThreeMF;
+ }
else if (file.hasExtension("smf")) {
return MeshIO::SMF;
}
@@ -2113,6 +2118,11 @@ bool MeshOutput::SaveAny(const char* FileName, MeshIO::Format format) const
if (!SaveX3DOM(str))
throw Base::FileException("Export of X3DOM failed",FileName);
}
+ else if (fileformat == MeshIO::ThreeMF) {
+ // write file
+ if (!Save3MF(str))
+ throw Base::FileException("Export of 3MF failed",FileName);
+ }
else if (fileformat == MeshIO::PY) {
// write file
if (!SavePython(str))
@@ -2183,6 +2193,8 @@ bool MeshOutput::SaveFormat(std::ostream &str, MeshIO::Format fmt) const
case MeshIO::WRZ:
// it's up to the client to create the needed stream
return SaveVRML(str);
+ case MeshIO::ThreeMF:
+ return Save3MF(str);
case MeshIO::NAS:
return SaveNastran(str);
case MeshIO::PLY:
@@ -2974,6 +2986,99 @@ void MeshOutput::SaveXML (Base::Writer &writer) const
writer.decInd();
}
+/** Saves the mesh object into a 3MF file. */
+bool MeshOutput::Save3MF(std::ostream &str) const
+{
+ zipios::ZipOutputStream zip(str);
+ zip.putNextEntry("/3D/3dmodel.model");
+ if (!Save3MFModel(zip))
+ return false;
+ zip.closeEntry();
+
+ zip.putNextEntry("_rels/.rels");
+ if (!Save3MFRels(zip))
+ return false;
+ zip.closeEntry();
+
+ zip.putNextEntry("[Content_Types].xml");
+ if (!Save3MFContent(zip))
+ return false;
+ zip.closeEntry();
+ return true;
+}
+
+bool MeshOutput::Save3MFRels(std::ostream &str) const
+{
+ str << "\n"
+ << ""
+ ""
+ "";
+ return true;
+}
+
+bool MeshOutput::Save3MFContent(std::ostream &str) const
+{
+ str << "\n"
+ << ""
+ ""
+ ""
+ "";
+ return true;
+}
+
+bool MeshOutput::Save3MFModel (std::ostream &str) const
+{
+ const MeshPointArray& rPoints = _rclMesh.GetPoints();
+ const MeshFacetArray& rFacets = _rclMesh.GetFacets();
+
+ if (!str || str.bad() == true)
+ return false;
+
+ str << "\n"
+ << "\n"
+ << "FreeCAD\n";
+ str << Base::blanks(2) << "\n";
+ str << Base::blanks(4) << "\n";
+ str << Base::blanks(2) << "\n";
+ str << Base::blanks(2) << "\n";
+ str << Base::blanks(4) << " \n";
+ str << Base::blanks(2) << "\n";
+ str << "\n";
+ return true;
+}
+
/** Writes an IDTF file. */
bool MeshOutput::SaveIDTF (std::ostream &str) const
{
diff --git a/src/Mod/Mesh/App/Core/MeshIO.h b/src/Mod/Mesh/App/Core/MeshIO.h
index fdb369c348ec..4e2fc61f0ca9 100644
--- a/src/Mod/Mesh/App/Core/MeshIO.h
+++ b/src/Mod/Mesh/App/Core/MeshIO.h
@@ -60,7 +60,8 @@ namespace MeshIO {
PY,
AMF,
SMF,
- ASY
+ ASY,
+ ThreeMF
};
enum Binding {
OVERALL,
@@ -197,6 +198,8 @@ class MeshExport MeshOutput
bool SaveAsymptote (std::ostream &rstrOut) const;
/** Saves the mesh object into an XML file. */
void SaveXML (Base::Writer &writer) const;
+ /** Saves the mesh object into a 3MF file. */
+ bool Save3MF (std::ostream &str) const;
/** Saves a node to an OpenInventor file. */
bool SaveMeshNode (std::ostream &rstrIn);
/** Writes an IDTF file. */
@@ -223,6 +226,9 @@ class MeshExport MeshOutput
protected:
/** Writes an X3D file. */
bool SaveX3DContent (std::ostream &rstrOut, bool exportViewpoints) const;
+ bool Save3MFModel(std::ostream &str) const;
+ bool Save3MFRels(std::ostream &str) const;
+ bool Save3MFContent(std::ostream &str) const;
protected:
const MeshKernel &_rclMesh; /**< reference to mesh data structure */
diff --git a/src/Mod/Mesh/App/MeshPyImp.cpp b/src/Mod/Mesh/App/MeshPyImp.cpp
index 4f47e92368c7..3876f0ff91f4 100644
--- a/src/Mod/Mesh/App/MeshPyImp.cpp
+++ b/src/Mod/Mesh/App/MeshPyImp.cpp
@@ -222,6 +222,7 @@ PyObject* MeshPy::write(PyObject *args, PyObject *kwds)
ext["APLY" ] = MeshCore::MeshIO::APLY;
ext["PY" ] = MeshCore::MeshIO::PY;
ext["ASY" ] = MeshCore::MeshIO::ASY;
+ ext["3MF" ] = MeshCore::MeshIO::ThreeMF;
static char* keywords_path[] = {"Filename","Format","Name","Material",NULL};
if (PyArg_ParseTupleAndKeywords(args, kwds, "et|ssO", keywords_path, "utf-8",
diff --git a/src/Mod/Mesh/Gui/Command.cpp b/src/Mod/Mesh/Gui/Command.cpp
index f92ca4673510..52f078b09949 100644
--- a/src/Mod/Mesh/Gui/Command.cpp
+++ b/src/Mod/Mesh/Gui/Command.cpp
@@ -524,6 +524,7 @@ void CmdMeshExport::activated(int)
ext << qMakePair(QString::fromLatin1("%1 (*.nas *.bdf)").arg(QObject::tr("Nastran")), "NAS");
ext << qMakePair(QString::fromLatin1("%1 (*.py)").arg(QObject::tr("Python module def")), "PY");
ext << qMakePair(QString::fromLatin1("%1 (*.asy)").arg(QObject::tr("Asymptote Format")), "ASY");
+ ext << qMakePair(QString::fromLatin1("%1 (*.3mf)").arg(QObject::tr("3D Manufacturing Format")), "3MF");
ext << qMakePair(QString::fromLatin1("%1 (*.*)").arg(QObject::tr("All Files")), ""); // Undefined
QStringList filter;
for (QList >::iterator it = ext.begin(); it != ext.end(); ++it)