23#ifndef VCL_LOAD_SAVE_STL_SAVE_H
24#define VCL_LOAD_SAVE_STL_SAVE_H
26#include <vclib/algorithms/core/polygon.h>
27#include <vclib/io/write.h>
28#include <vclib/load_save/settings.h>
29#include <vclib/misc/logger.h>
30#include <vclib/space/complex/mesh_info.h>
36inline void writeStlHeader(std::ostream& fp,
const SaveSettings& settings)
38 std::string header =
"solid STL generated by VCLib";
39 if (settings.binary) {
40 if (settings.magicsMode) {
42 for (uint i = 0; i < 3; i++)
43 p.push_back((
char) 0x7f);
44 header =
"COLOR=" + p +
" MATERIAL=" + p +
" " + p +
" " + p;
46 while (header.size() < 80)
47 header.push_back(
' ');
55template<Po
int3Concept Po
intType, Po
int3Concept NormalType>
63 const SaveSettings& settings)
65 if (settings.binary) {
66 for (uint i = 0; i < 3; ++i)
67 io::writeFloat(fp, n[i]);
69 for (uint i = 0; i < 3; ++i)
70 io::writeFloat(fp, p0[i]);
72 for (uint i = 0; i < 3; ++i)
73 io::writeFloat(fp, p1[i]);
75 for (uint i = 0; i < 3; ++i)
76 io::writeFloat(fp, p2[i]);
78 io::writeUShort(fp, attributes);
81 fp <<
" facet normal " << n.x() <<
" " << n.y() <<
" " << n.z()
83 fp <<
" outer loop" << std::endl;
85 fp <<
" vertex " << p0.x() <<
" " << p0.y() <<
" " << p0.z()
87 fp <<
" vertex " << p1.x() <<
" " << p1.y() <<
" " << p1.z()
89 fp <<
" vertex " << p2.x() <<
" " << p2.y() <<
" " << p2.z()
92 fp <<
" endloop" << std::endl;
93 fp <<
" endfacet" << std::endl;
99template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
104 const SaveSettings& settings = SaveSettings())
106 MeshInfo meshInfo(m);
112 if (!settings.info.isEmpty())
113 meshInfo = settings.info.intersect(meshInfo);
115 log.log(0,
"Saving STL file");
117 detail::writeStlHeader(fp, settings);
119 if constexpr (HasFaces<MeshType>) {
120 using FaceType = MeshType::FaceType;
122 if (settings.binary) {
123 io::writeInt(fp, m.faceNumber());
126 log.startProgress(
"Saving STL file", m.faceNumber());
128 for (
const FaceType& f : m.
faces()) {
132 unsigned short attributes = 0;
134 if constexpr (HasPerFaceColor<MeshType>) {
135 if (meshInfo.hasFaceColors()) {
136 if (settings.magicsMode)
137 attributes = 32768 | f.color().bgr5();
139 attributes = 32768 | f.color().rgb5();
143 if (f.vertexNumber() == 3) {
144 detail::writeSTLTriangle(
146 f.vertex(0)->coord(),
147 f.vertex(1)->coord(),
148 f.vertex(2)->coord(),
154 std::vector<uint> tris =
earCut(f);
155 for (uint i = 0; i < tris.size(); i += 3) {
156 detail::writeSTLTriangle(
158 f.vertex(tris[i])->coord(),
159 f.vertex(tris[i + 1])->coord(),
160 f.vertex(tris[i + 2])->coord(),
167 log.progress(m.index(f));
173 if (!settings.binary) {
174 fp <<
"endsolid VCLib" << std::endl;
178template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
182 const SaveSettings& settings,
185 saveStl(m, fp, log, settings);
188template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
191 const std::string& filename,
193 const SaveSettings& settings = SaveSettings())
195 std::ofstream fp = openOutputFileStream(filename,
"stl");
197 saveStl(m, fp, log, settings);
200template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
203 const std::string& filename,
204 const SaveSettings& settings,
207 saveStl(m, filename, log, settings);
FaceType::VertexType::CoordType faceNormal(const FaceType &f)
Computes the normal of a face, without modifying the face. Works both for triangle and polygonal face...
Definition geometry.h:45
std::vector< uint > earCut(Iterator begin, Iterator end)
Triangulates a simple polygon with no holes using the ear-cutting algorithm.
Definition ear_cut.h:92
NullLogger nullLogger
The nullLogger object is an object of type NullLogger that is used as default argument in the functio...
Definition null_logger.h:125
constexpr detail::FacesView faces
A view that allows to iterate overt the Face elements of an object.
Definition face.h:52