23#ifndef VCL_LOAD_SAVE_STL_LOAD_H
24#define VCL_LOAD_SAVE_STL_LOAD_H
26#include <vclib/io/read.h>
27#include <vclib/load_save/settings.h>
28#include <vclib/misc/logger.h>
29#include <vclib/space/complex/mesh_info.h>
35inline bool isBinStlMalformed(
36 const std::string& filename,
40 fsize = FileInfo::fileSize(filename);
41 isBinary = FileInfo::isFileBinary(filename);
45 std::ifstream fp = openInputFileStream(filename);
47 uint fnum = io::readUInt<uint>(fp, std::endian::little);
48 std::size_t expectedFileSize =
52 3 * 3 *
sizeof(
float) +
53 sizeof(
unsigned short));
54 if (expectedFileSize != fsize) {
57 std::abs((
long int) expectedFileSize - (
long int) fsize);
58 if (diff > fsize / 20)
66inline bool isStlColored(std::istream& fp,
bool& magicsMode)
73 size_t cInd = s.rfind(
"COLOR=");
74 size_t mInd = s.rfind(
"MATERIAL=");
75 if (cInd != std::string::npos && mInd != std::string::npos)
79 uint fnum = io::readUInt<uint>(fp, std::endian::little);
80 static const uint fmax = 1000;
82 static const uint fdataSize = 12 *
sizeof(float);
84 for (uint i = 0; i < std::min(fnum, fmax); ++i) {
85 fp.seekg(fdataSize, std::ios::cur);
87 io::readShort<unsigned short>(fp, std::endian::little);
90 if (c != Color::White)
96template<MeshConcept MeshType, LoggerConcept LogType>
100 MeshInfo& loadedInfo,
102 const LoadSettings& settings)
104 bool magicsMode, colored;
105 colored = isStlColored(fp, magicsMode);
107 if (settings.enableOptionalComponents) {
109 loadedInfo.setFaceColors();
110 enableOptionalComponentsFromInfo(loadedInfo, m);
113 if constexpr (HasPerFaceColor<MeshType>) {
115 loadedInfo.setFaceColors();
120 uint fnum = io::readUInt<uint>(fp, std::endian::little);
122 loadedInfo.setTriangleMesh();
124 log.startProgress(
"Loading STL file", fnum);
126 m.addVertices(fnum * 3);
127 if constexpr (HasFaces<MeshType>) {
128 m.reserveFaces(fnum);
132 for (uint i = 0; i < fnum; ++i) {
134 norm.x() = io::readFloat<float>(fp, std::endian::little);
135 norm.y() = io::readFloat<float>(fp, std::endian::little);
136 norm.z() = io::readFloat<float>(fp, std::endian::little);
138 for (uint j = 0; j < 3; ++j) {
139 m.vertex(vi + j).coord().x() =
140 io::readFloat<float>(fp, std::endian::little);
141 m.vertex(vi + j).coord().y() =
142 io::readFloat<float>(fp, std::endian::little);
143 m.vertex(vi + j).coord().z() =
144 io::readFloat<float>(fp, std::endian::little);
147 unsigned short attr =
148 io::readShort<unsigned short>(fp, std::endian::little);
150 if constexpr (HasFaces<MeshType>) {
151 using FaceType = MeshType::FaceType;
153 uint fi = m.addFace();
154 FaceType& f = m.face(fi);
156 if constexpr (FaceType::VERTEX_NUMBER < 0) {
160 for (uint j = 0; j < 3; ++j)
161 f.setVertex(j, vi + j);
162 if (HasPerFaceNormal<MeshType>) {
163 using ST = FaceType::NormalType::ScalarType;
165 f.normal() = norm.cast<ST>();
168 if (HasPerFaceColor<MeshType>) {
187template<MeshConcept MeshType, LoggerConcept LogType>
191 MeshInfo& loadedInfo,
193 const LoadSettings& settings)
195 if (settings.enableOptionalComponents) {
196 enableOptionalComponentsFromInfo(loadedInfo, m);
200 std::size_t fsize = fp.tellg();
202 log.startProgress(
"Loading STL file", fsize);
204 Tokenizer tokens = readAndTokenizeNextNonEmptyLineNoThrow(fp);
208 Tokenizer::iterator token = tokens.begin();
209 if (token != tokens.end() && *token ==
"facet") {
214 uint vi = m.addVertices(3);
219 normal.x() = io::readFloat<float>(token, std::endian::little);
220 normal.y() = io::readFloat<float>(token, std::endian::little);
221 normal.z() = io::readFloat<float>(token, std::endian::little);
223 readAndTokenizeNextNonEmptyLine(fp);
225 tokens = readAndTokenizeNextNonEmptyLine(fp);
227 for (uint i = 0; i < 3; i++) {
228 token = tokens.begin();
231 m.vertex(vi + i).coord().x() =
232 io::readFloat<float>(token, std::endian::little);
233 m.vertex(vi + i).coord().y() =
234 io::readFloat<float>(token, std::endian::little);
235 m.vertex(vi + i).coord().z() =
236 io::readFloat<float>(token, std::endian::little);
239 tokens = readAndTokenizeNextNonEmptyLine(fp);
241 readAndTokenizeNextNonEmptyLine(fp);
243 if constexpr (HasFaces<MeshType>) {
244 using FaceType = MeshType::FaceType;
245 uint fi = m.addFace();
247 FaceType& f = m.face(fi);
249 if constexpr (FaceType::VERTEX_NUMBER < 0) {
253 for (uint j = 0; j < 3; ++j)
254 f.setVertex(j, vi + j);
255 if (HasPerFaceNormal<MeshType>) {
256 using ST = FaceType::NormalType::ScalarType;
258 f.normal() = normal.cast<ST>();
263 tokens = readAndTokenizeNextNonEmptyLineNoThrow(fp);
265 log.progress(fp.tellg());
268 if constexpr (HasFaces<MeshType>) {
269 if (m.faceNumber() > 0)
270 loadedInfo.setTriangleMesh();
309template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
314 bool isBinary =
false,
328 log.log(0,
"Loading STL file");
335 log.log(100,
"STL file loaded");
363template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
367 bool isBinary =
false,
405template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
409 bool isBinary =
false,
443template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
446 bool isBinary =
false,
479template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
487 log.log(0,
"Checking STL file");
494 log.log(0,
"Opening STL file");
496 std::ifstream
fp = openInputFileStream(
filename);
524template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
559template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
590template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
static std::string fileNameWithoutExtension(const std::string &fullpath)
Get the file name without extension of a file.
Definition file_info.h:217
A simple class that allows to store which elements and their components have been imported/loaded or ...
Definition mesh_info.h:76
A class representing a line segment in n-dimensional space. The class is parameterized by a PointConc...
Definition segment.h:43
HasFaces concepts is satisfied when at least one of its template types is (or inherits from) a vcl::m...
Definition face_container.h:133
Concept that checks if a Mesh has the Name component.
Definition per_mesh.h:95
bool isPerFaceNormalAvailable(const MeshType &m)
Returns true if the Normal component is available (enabled) in the Face element of the input mesh m.
Definition face_requirements.h:330
bool isPerFaceColorAvailable(const MeshType &m)
Returns true if the Color component is available (enabled) in the Face element of the input mesh m.
Definition face_requirements.h:214
void loadStl(MeshType &m, std::istream &inputStlStream, MeshInfo &loadedInfo, bool isBinary=false, LogType &log=nullLogger, const LoadSettings &settings=LoadSettings())
Loads from the given input stl stream and puts the content into the mesh m.
Definition load.h:310
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
Point3< float > Point3f
A convenience alias for a 3-dimensional Point with floating-point components.
Definition point.h:792
The LoadSettings structure contains the settings that can be used to load a mesh from a stream/file.
Definition settings.h:35