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; }; /**