diff --git a/src/Mod/Mesh/App/Core/IO/Writer3MF.cpp b/src/Mod/Mesh/App/Core/IO/Writer3MF.cpp
index f6b09fcd4d..1ad64b65b9 100644
--- a/src/Mod/Mesh/App/Core/IO/Writer3MF.cpp
+++ b/src/Mod/Mesh/App/Core/IO/Writer3MF.cpp
@@ -76,6 +76,11 @@ bool Writer3MF::AddMesh(const MeshKernel& mesh, const Base::Matrix4D& mat)
return SaveObject(zip, id, mesh);
}
+void Writer3MF::AddResource(const Resource3MF& res)
+{
+ resources.emplace_back(res);
+}
+
bool Writer3MF::Save()
{
Finish(zip);
@@ -90,6 +95,12 @@ bool Writer3MF::Save()
if (!SaveContent(zip))
return false;
zip.closeEntry();
+ for (const auto& it : resources) {
+ zip.putNextEntry(it.fileNameInZip);
+ zip.write(it.fileContent.data(), it.fileContent.size());
+ zip.closeEntry();
+ }
+
return true;
}
@@ -163,19 +174,24 @@ std::string Writer3MF::DumpMatrix(const Base::Matrix4D& mat) const
bool Writer3MF::SaveRels(std::ostream &str) const
{
+ int ids = 1;
str << "\n"
- << ""
- ""
- "";
+ << "\n"
+ << " \n";
+ for (const auto& it : resources)
+ str << " \n";
+ str << "\n";
return true;
}
bool Writer3MF::SaveContent(std::ostream &str) const
{
str << "\n"
- << ""
- ""
- ""
- "";
+ << "\n"
+ << " \n"
+ << " \n";
+ for (const auto& it : resources)
+ str << " \n";
+ str << "";
return true;
}
diff --git a/src/Mod/Mesh/App/Core/IO/Writer3MF.h b/src/Mod/Mesh/App/Core/IO/Writer3MF.h
index 8dbfe0e103..9a8b0ca6df 100644
--- a/src/Mod/Mesh/App/Core/IO/Writer3MF.h
+++ b/src/Mod/Mesh/App/Core/IO/Writer3MF.h
@@ -25,14 +25,26 @@
#define MESH_IO_WRITER_3MF_H
#include
-
-#include "Core/Elements.h"
#include
+#include
+
+namespace Base {
+class Matrix4D;
+}
namespace MeshCore
{
class MeshKernel;
+struct Resource3MF {
+ std::string extension;
+ std::string contentType;
+ std::string relationshipTarget;
+ std::string relationshipType;
+ std::string fileNameInZip;
+ std::string fileContent;
+};
+
/** Saves the mesh object into 3MF format. */
class MeshExport Writer3MF
{
@@ -58,6 +70,11 @@ public:
* \return true if the added mesh could be written successfully, false otherwise.
*/
bool AddMesh(const MeshKernel& mesh, const Base::Matrix4D& mat);
+ /*!
+ * \brief AddResource
+ * Add an additional resource to the 3MF file.
+ */
+ void AddResource(const Resource3MF&);
/*!
* \brief After having added the mesh objects with \ref AddMesh save the meta-information
* to the 3MF file.
@@ -79,6 +96,7 @@ private:
zipios::ZipOutputStream zip;
int objectIndex;
std::vector items;
+ std::vector resources;
};
} // namespace MeshCore
diff --git a/src/Mod/Mesh/App/Exporter.cpp b/src/Mod/Mesh/App/Exporter.cpp
index ed55bca16c..dea8d89fd3 100644
--- a/src/Mod/Mesh/App/Exporter.cpp
+++ b/src/Mod/Mesh/App/Exporter.cpp
@@ -229,12 +229,29 @@ bool MergeExporter::addMesh(const char *name, const MeshObject & mesh)
// ----------------------------------------------------------------------------
+void Extension3MFFactory::addProducer(AbstractExtensionProducer* ext)
+{
+ producer.emplace_back(ext);
+}
+
+std::vector Extension3MFFactory::create()
+{
+ std::vector ext;
+ for (const auto& it : producer)
+ ext.emplace_back(it->create());
+ return ext;
+}
+
+std::vector Extension3MFFactory::producer;
+
class Exporter3MF::Private {
public:
Private(const std::string& filename)
: writer3mf(filename) {
+ ext = Extension3MFFactory::create();
}
MeshCore::Writer3MF writer3mf;
+ std::vector ext;
};
Exporter3MF::Exporter3MF(std::string fileName)
@@ -251,7 +268,14 @@ Exporter3MF::~Exporter3MF()
bool Exporter3MF::addMesh(const char *name, const MeshObject & mesh)
{
boost::ignore_unused(name);
- return d->writer3mf.AddMesh(mesh.getKernel(), mesh.getTransform());
+ bool ok = d->writer3mf.AddMesh(mesh.getKernel(), mesh.getTransform());
+ if (ok) {
+ for (const auto& it : d->ext) {
+ d->writer3mf.AddResource(it->addMesh(mesh));
+ }
+ }
+
+ return ok;
}
void Exporter3MF::write()
@@ -410,7 +434,7 @@ bool ExporterAMF::addMesh(const char *name, const MeshObject & mesh)
*outputStreamPtr << "\t\t\t\n"
<< "\t\t\t\n";
-
+
// Now that we've output all the vertices, we can
// output the facets that refer to them!
for (auto triItr(facets.begin()); triItr != facets.end(); ) {
diff --git a/src/Mod/Mesh/App/Exporter.h b/src/Mod/Mesh/App/Exporter.h
index 36bc9a159e..bbdcac6cc4 100644
--- a/src/Mod/Mesh/App/Exporter.h
+++ b/src/Mod/Mesh/App/Exporter.h
@@ -34,6 +34,7 @@
#include "MeshFeature.h"
#include "Core/MeshIO.h"
#include "Core/MeshKernel.h"
+#include "Core/IO/Writer3MF.h"
namespace Mesh
{
@@ -91,6 +92,50 @@ protected:
std::string fName;
};
+/*!
+ * \brief The Extension3MF class
+ * Abstract base class for 3MF extensions
+ */
+class MeshExport Extension3MF
+{
+public:
+ using Resource = MeshCore::Resource3MF;
+ Extension3MF() = default;
+ virtual ~Extension3MF() = default;
+
+ virtual Resource addMesh(const MeshObject & mesh) = 0;
+};
+
+using Extension3MFPtr = std::shared_ptr;
+
+/*!
+ * \brief The AbstractExtensionProducer class
+ * Abstract base class to create an instance of an Extension3MF.
+ */
+class MeshExport AbstractExtensionProducer
+{
+public:
+ AbstractExtensionProducer() = default;
+ virtual ~AbstractExtensionProducer() = default;
+ virtual Extension3MFPtr create() const = 0;
+};
+
+using AbstractExtensionProducerPtr = std::shared_ptr;
+
+/*!
+ * \brief The Extension3MFFactory class
+ * Factor class to manage the producers of Extension3MF
+ */
+class MeshExport Extension3MFFactory
+{
+public:
+ static void addProducer(AbstractExtensionProducer* ext);
+ static std::vector create();
+
+private:
+ static std::vector producer;
+};
+
/// Used for exporting to 3D Manufacturing Format (3MF)
/*!
* The constructor and destructor write the beginning and end of the 3MF,
diff --git a/src/Mod/Mesh/Gui/AppMeshGui.cpp b/src/Mod/Mesh/Gui/AppMeshGui.cpp
index ccacd9eb86..25a870952a 100644
--- a/src/Mod/Mesh/Gui/AppMeshGui.cpp
+++ b/src/Mod/Mesh/Gui/AppMeshGui.cpp
@@ -43,6 +43,7 @@
#include
#include
+#include
#include "images.h"
#include "DlgEvaluateMeshImp.h"
@@ -52,6 +53,7 @@
#include "SoFCMeshObject.h"
#include "SoFCIndexedFaceSet.h"
#include "SoPolygon.h"
+#include "ThumbnailExtension.h"
#include "ViewProvider.h"
#include "ViewProviderMeshFaceSet.h"
#include "ViewProviderCurvature.h"
@@ -163,6 +165,8 @@ PyMOD_INIT_FUNC(MeshGui)
(void)new Gui::PrefPageProducer ("Display");
(void)new Gui::PrefPageProducer ( QT_TRANSLATE_NOOP("QObject", "Import-Export") );
+ Mesh::Extension3MFFactory::addProducer(new MeshGui::ThumbnailExtensionProducer);
+
MeshGui::SoFCMeshObjectElement ::initClass();
MeshGui::SoSFMeshObject ::initClass();
MeshGui::SoFCMeshObjectNode ::initClass();
diff --git a/src/Mod/Mesh/Gui/CMakeLists.txt b/src/Mod/Mesh/Gui/CMakeLists.txt
index 33ba8cd1c8..feed6b211c 100644
--- a/src/Mod/Mesh/Gui/CMakeLists.txt
+++ b/src/Mod/Mesh/Gui/CMakeLists.txt
@@ -144,6 +144,8 @@ SET(MeshGui_SRCS
MeshSelection.h
PropertyEditorMesh.cpp
PropertyEditorMesh.h
+ ThumbnailExtension.cpp
+ ThumbnailExtension.h
Workbench.cpp
Workbench.h
)
diff --git a/src/Mod/Mesh/Gui/ThumbnailExtension.cpp b/src/Mod/Mesh/Gui/ThumbnailExtension.cpp
new file mode 100644
index 0000000000..b7afe7ea20
--- /dev/null
+++ b/src/Mod/Mesh/Gui/ThumbnailExtension.cpp
@@ -0,0 +1,99 @@
+/***************************************************************************
+ * Copyright (c) 2022 Werner Mayer *
+ * *
+ * This file is part of the FreeCAD CAx development system. *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ * This library is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this library; see the file COPYING.LIB. If not, *
+ * write to the Free Software Foundation, Inc., 59 Temple Place, *
+ * Suite 330, Boston, MA 02111-1307, USA *
+ * *
+ ***************************************************************************/
+
+
+#include "PreCompiled.h"
+
+#ifndef _PreComp_
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#endif
+
+#include "ThumbnailExtension.h"
+#include "ViewProvider.h"
+#include
+
+using namespace MeshGui;
+
+Mesh::Extension3MF::Resource ThumbnailExtension3MF::addMesh(const Mesh::MeshObject &mesh)
+{
+ SoCoordinate3* coord = new SoCoordinate3();
+ SoIndexedFaceSet* faces = new SoIndexedFaceSet();
+
+ SoOrthographicCamera* cam = new SoOrthographicCamera();
+ SoSeparator* root = new SoSeparator();
+ root->ref();
+ root->addChild(cam);
+ root->addChild(new SoDirectionalLight);
+ root->addChild(coord);
+ root->addChild(faces);
+
+ ViewProviderMeshBuilder().createMesh(mesh.getKernel(), coord, faces);
+
+ SbRotation rot(-0.353553, -0.146447, -0.353553, -0.853553);
+ cam->orientation.setValue(rot);
+ SbViewportRegion vpr(256, 256);
+ cam->viewAll(root, vpr);
+
+ Gui::SoQtOffscreenRenderer renderer(vpr);
+ renderer.setBackgroundColor(SbColor4f(1.0f, 1.0f, 1.0f, 0.0f));
+ QImage img;
+ renderer.render(root);
+ renderer.writeToImage(img);
+ root->unref();
+
+ QByteArray data;
+ QBuffer buffer(&data);
+ buffer.open(QIODevice::WriteOnly);
+ img.save(&buffer, "PNG");
+ buffer.close();
+
+ Mesh::Extension3MF::Resource res;
+ res.extension = "png";
+ res.contentType = "image/png";
+ res.relationshipType = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail";
+ res.fileContent = std::string(data.data(), data.size());
+ setContentName(res);
+
+ index++;
+ return res;
+}
+
+void ThumbnailExtension3MF::setContentName(Mesh::Extension3MF::Resource& res)
+{
+ if (index == 0) {
+ res.relationshipTarget = "/Metadata/thumbnail.png";
+ res.fileNameInZip = "Metadata/thumbnail.png";
+ }
+ else {
+ std::string suf = std::to_string(index);
+ res.relationshipTarget = "/Metadata/thumbnail" + suf + ".png";
+ res.fileNameInZip = "Metadata/thumbnail" + suf + ".png";
+ }
+}
diff --git a/src/Mod/Mesh/Gui/ThumbnailExtension.h b/src/Mod/Mesh/Gui/ThumbnailExtension.h
new file mode 100644
index 0000000000..ff76b53a2e
--- /dev/null
+++ b/src/Mod/Mesh/Gui/ThumbnailExtension.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+ * Copyright (c) 2022 Werner Mayer *
+ * *
+ * This file is part of the FreeCAD CAx development system. *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ * This library is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this library; see the file COPYING.LIB. If not, *
+ * write to the Free Software Foundation, Inc., 59 Temple Place, *
+ * Suite 330, Boston, MA 02111-1307, USA *
+ * *
+ ***************************************************************************/
+
+#ifndef MESHGUI_THUMBNAIL_EXTENSION_H
+#define MESHGUI_THUMBNAIL_EXTENSION_H
+
+#include
+#include
+
+namespace MeshGui {
+
+class ThumbnailExtension3MF : public Mesh::Extension3MF {
+public:
+ Mesh::Extension3MF::Resource addMesh(const Mesh::MeshObject & mesh) override;
+
+private:
+ void setContentName(Mesh::Extension3MF::Resource&);
+
+private:
+ int index = 0;
+};
+
+class ThumbnailExtensionProducer : public Mesh::AbstractExtensionProducer {
+public:
+ Mesh::Extension3MFPtr create() const override {
+ return std::make_shared();
+ }
+};
+
+} // namespace MeshGui
+
+
+#endif // MESHGUI_THUMBNAIL_EXTENSION_H
diff --git a/src/Mod/Mesh/Gui/ViewProvider.cpp b/src/Mod/Mesh/Gui/ViewProvider.cpp
index 4d719115e5..c3158562cf 100644
--- a/src/Mod/Mesh/Gui/ViewProvider.cpp
+++ b/src/Mod/Mesh/Gui/ViewProvider.cpp
@@ -142,10 +142,15 @@ void ViewProviderMeshBuilder::createMesh(const App::Property* prop, SoCoordinate
{
const Mesh::PropertyMeshKernel* mesh = static_cast(prop);
const MeshCore::MeshKernel& rcMesh = mesh->getValue().getKernel();
+ createMesh(rcMesh, coords, faces);
+}
+
+void ViewProviderMeshBuilder::createMesh(const MeshCore::MeshKernel& kernal, SoCoordinate3* coords, SoIndexedFaceSet* faces) const
+{
// set the point coordinates
- const MeshCore::MeshPointArray& cP = rcMesh.GetPoints();
- coords->point.setNum(rcMesh.CountPoints());
+ const MeshCore::MeshPointArray& cP = kernal.GetPoints();
+ coords->point.setNum(kernal.CountPoints());
SbVec3f* verts = coords->point.startEditing();
int i=0;
for (MeshCore::MeshPointArray::_TConstIterator it = cP.begin(); it != cP.end(); ++it, i++) {
@@ -155,8 +160,8 @@ void ViewProviderMeshBuilder::createMesh(const App::Property* prop, SoCoordinate
// set the face indices
int j=0;
- const MeshCore::MeshFacetArray& cF = rcMesh.GetFacets();
- faces->coordIndex.setNum(4*rcMesh.CountFacets());
+ const MeshCore::MeshFacetArray& cF = kernal.GetFacets();
+ faces->coordIndex.setNum(4*kernal.CountFacets());
int32_t* indices = faces->coordIndex.startEditing();
for (MeshCore::MeshFacetArray::_TConstIterator it = cF.begin(); it != cF.end(); ++it, j++) {
for (int i=0; i<3; i++) {
diff --git a/src/Mod/Mesh/Gui/ViewProvider.h b/src/Mod/Mesh/Gui/ViewProvider.h
index 3be414fa11..f3a8c92046 100644
--- a/src/Mod/Mesh/Gui/ViewProvider.h
+++ b/src/Mod/Mesh/Gui/ViewProvider.h
@@ -82,6 +82,7 @@ public:
~ViewProviderMeshBuilder() override{}
void buildNodes(const App::Property*, std::vector&) const override;
void createMesh(const App::Property*, SoCoordinate3*, SoIndexedFaceSet*) const;
+ void createMesh(const MeshCore::MeshKernel&, SoCoordinate3*, SoIndexedFaceSet*) const;
};
/**