FreeCAD

Форк
0
/
Writer3MF.cpp 
212 строк · 7.4 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2022 Werner Mayer <wmayer[at]users.sourceforge.net>     *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
6
 *   This library is free software; you can redistribute it and/or         *
7
 *   modify it under the terms of the GNU Library General Public           *
8
 *   License as published by the Free Software Foundation; either          *
9
 *   version 2 of the License, or (at your option) any later version.      *
10
 *                                                                         *
11
 *   This library  is distributed in the hope that it will be useful,      *
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14
 *   GNU Library General Public License for more details.                  *
15
 *                                                                         *
16
 *   You should have received a copy of the GNU Library General Public     *
17
 *   License along with this library; see the file COPYING.LIB. If not,    *
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
19
 *   Suite 330, Boston, MA  02111-1307, USA                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23
#include "PreCompiled.h"
24
#ifndef _PreComp_
25
#include <ostream>
26
#include <sstream>
27
#endif
28

29
#include "Core/Evaluation.h"
30
#include "Core/MeshKernel.h"
31
#include <Base/Tools.h>
32

33
#include "Writer3MF.h"
34

35

36
using namespace MeshCore;
37

38
Writer3MF::Writer3MF(std::ostream& str)
39
    : zip(str)
40
{
41
    zip.putNextEntry("3D/3dmodel.model");
42
    Initialize(zip);
43
}
44

45
Writer3MF::Writer3MF(const std::string& filename)
46
    : zip(filename)
47
{
48
    zip.putNextEntry("3D/3dmodel.model");
49
    Initialize(zip);
50
}
51

52
void Writer3MF::SetForceModel(bool model)
53
{
54
    forceModel = model;
55
}
56

57
void Writer3MF::Initialize(std::ostream& str)
58
{
59
    str << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
60
           "<model unit=\"millimeter\" xml:lang=\"en-US\" "
61
           "xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\">\n"
62
           " <metadata name=\"Application\">FreeCAD</metadata>\n";
63
    str << Base::blanks(1) << "<resources>\n";
64
}
65

66
void Writer3MF::Finish(std::ostream& str)
67
{
68
    str << Base::blanks(1) << "</resources>\n";
69
    str << Base::blanks(1) << "<build>\n";
70
    for (const auto& it : items) {
71
        str << Base::blanks(2) << it;
72
    }
73
    str << Base::blanks(1) << "</build>\n";
74
    str << "</model>\n";
75
}
76

77
bool Writer3MF::AddMesh(const MeshKernel& mesh, const Base::Matrix4D& mat)
78
{
79
    int id = ++objectIndex;
80
    SaveBuildItem(id, mat);
81
    return SaveObject(zip, id, mesh);
82
}
83

84
void Writer3MF::AddResource(const Resource3MF& res)
85
{
86
    resources.emplace_back(res);
87
}
88

89
bool Writer3MF::Save()
90
{
91
    Finish(zip);
92
    zip.closeEntry();
93

94
    zip.putNextEntry("_rels/.rels");
95
    if (!SaveRels(zip)) {
96
        return false;
97
    }
98
    zip.closeEntry();
99

100
    zip.putNextEntry("[Content_Types].xml");
101
    if (!SaveContent(zip)) {
102
        return false;
103
    }
104
    zip.closeEntry();
105
    for (const auto& it : resources) {
106
        zip.putNextEntry(it.fileNameInZip);
107
        zip.write(it.fileContent.data(), static_cast<std::streamsize>(it.fileContent.size()));
108
        zip.closeEntry();
109
    }
110

111
    return true;
112
}
113

114
bool Writer3MF::SaveObject(std::ostream& str, int id, const MeshKernel& mesh) const
115
{
116
    // NOLINTBEGIN(readability-magic-numbers, cppcoreguidelines-avoid-magic-numbers)
117
    const MeshPointArray& rPoints = mesh.GetPoints();
118
    const MeshFacetArray& rFacets = mesh.GetFacets();
119

120
    if (!str || str.bad()) {
121
        return false;
122
    }
123

124
    str << Base::blanks(2) << "<object id=\"" << id << "\" type=\"" << GetType(mesh) << "\">\n";
125
    str << Base::blanks(3) << "<mesh>\n";
126

127
    // vertices
128
    str << Base::blanks(4) << "<vertices>\n";
129
    std::size_t index = 0;
130
    for (auto it = rPoints.begin(); it != rPoints.end(); ++it, ++index) {
131
        str << Base::blanks(5) << "<vertex x=\"" << it->x << "\" y=\"" << it->y << "\" z=\""
132
            << it->z << "\" />\n";
133
    }
134
    str << Base::blanks(4) << "</vertices>\n";
135

136
    // facet indices
137
    str << Base::blanks(4) << "<triangles>\n";
138
    for (const auto& it : rFacets) {
139
        str << Base::blanks(5) << "<triangle v1=\"" << it._aulPoints[0] << "\" v2=\""
140
            << it._aulPoints[1] << "\" v3=\"" << it._aulPoints[2] << "\" />\n";
141
    }
142
    str << Base::blanks(4) << "</triangles>\n";
143

144
    str << Base::blanks(3) << "</mesh>\n";
145
    str << Base::blanks(2) << "</object>\n";
146
    // NOLINTEND(readability-magic-numbers, cppcoreguidelines-avoid-magic-numbers)
147

148
    return true;
149
}
150

151
std::string Writer3MF::GetType(const MeshKernel& mesh) const
152
{
153
    bool isSolid = (forceModel || MeshEvalSolid(mesh).Evaluate());
154
    return isSolid ? "model" : "surface";
155
}
156

157
void Writer3MF::SaveBuildItem(int id, const Base::Matrix4D& mat)
158
{
159
    std::stringstream str;
160
    str << "<item objectid=\"" << id << "\" transform=\"" << DumpMatrix(mat) << "\" />\n";
161
    items.push_back(str.str());
162
}
163

164
std::string Writer3MF::DumpMatrix(const Base::Matrix4D& mat)
165
{
166
    // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
167
    // The matrix representation in the specs is the transposed version of Matrix4D
168
    // This means that for the 3x3 sub-matrix the indices must be swapped
169
    //
170
    // 3D Manufacturing Format / Core Specification & Reference Guide v1.2.3
171
    // Chapter: 3.3 3D Matrices (page 9)
172
    std::stringstream str;
173
    str << mat[0][0] << " " << mat[1][0] << " " << mat[2][0] << " " << mat[0][1] << " " << mat[1][1]
174
        << " " << mat[2][1] << " " << mat[0][2] << " " << mat[1][2] << " " << mat[2][2] << " "
175
        << mat[0][3] << " " << mat[1][3] << " " << mat[2][3];
176
    return str.str();
177
    // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
178
}
179

180
bool Writer3MF::SaveRels(std::ostream& str) const
181
{
182
    // NOLINTBEGIN(modernize-raw-string-literal)
183
    int ids = 1;
184
    str << "<?xml version='1.0' encoding='UTF-8'?>\n"
185
        << "<Relationships "
186
           "xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n"
187
        << " <Relationship Target=\"/3D/3dmodel.model\" Id=\"rel0\""
188
        << " Type=\"http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel\" />\n";
189
    for (const auto& it : resources) {
190
        str << " <Relationship Target=\"" << it.relationshipTarget << "\" Id=\"rel" << ++ids
191
            << "\" Type=\"" << it.relationshipType << "\" />\n";
192
    }
193
    str << "</Relationships>\n";
194
    return true;
195
    // NOLINTEND(modernize-raw-string-literal)
196
}
197

198
bool Writer3MF::SaveContent(std::ostream& str) const
199
{
200
    str << "<?xml version='1.0' encoding='UTF-8'?>\n"
201
        << "<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">\n"
202
        << " <Default Extension=\"rels\" "
203
           "ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/>\n"
204
        << " <Default Extension=\"model\" "
205
           "ContentType=\"application/vnd.ms-package.3dmanufacturing-3dmodel+xml\"/>\n";
206
    for (const auto& it : resources) {
207
        str << " <Default Extension=\"" << it.extension << "\" ContentType=\"" << it.contentType
208
            << "\"/>\n";
209
    }
210
    str << "</Types>";
211
    return true;
212
}
213

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.