mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-23 14:44:19 -06:00
Merged branch 'dev_native' into lm_sla_supports_auto
Added igl library files
This commit is contained in:
commit
7681d00ee5
2865 changed files with 142806 additions and 22325 deletions
2134
src/libslic3r/Format/3mf.cpp
Normal file
2134
src/libslic3r/Format/3mf.cpp
Normal file
File diff suppressed because it is too large
Load diff
18
src/libslic3r/Format/3mf.hpp
Normal file
18
src/libslic3r/Format/3mf.hpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef slic3r_Format_3mf_hpp_
|
||||
#define slic3r_Format_3mf_hpp_
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class Model;
|
||||
class Print;
|
||||
|
||||
// Load the content of a 3mf file into the given model and preset bundle.
|
||||
extern bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model);
|
||||
|
||||
// Save the given model and the config data contained in the given Print into a 3mf file.
|
||||
// The model could be modified during the export process if meshes are not repaired or have no shared vertices
|
||||
extern bool store_3mf(const char* path, Model* model, Print* print, bool export_print_config);
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_Format_3mf_hpp_ */
|
1048
src/libslic3r/Format/AMF.cpp
Normal file
1048
src/libslic3r/Format/AMF.cpp
Normal file
File diff suppressed because it is too large
Load diff
18
src/libslic3r/Format/AMF.hpp
Normal file
18
src/libslic3r/Format/AMF.hpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef slic3r_Format_AMF_hpp_
|
||||
#define slic3r_Format_AMF_hpp_
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class Model;
|
||||
class Print;
|
||||
|
||||
// Load the content of an amf file into the given model and configuration.
|
||||
extern bool load_amf(const char *path, DynamicPrintConfig *config, Model *model);
|
||||
|
||||
// Save the given model and the config data contained in the given Print into an amf file.
|
||||
// The model could be modified during the export process if meshes are not repaired or have no shared vertices
|
||||
extern bool store_amf(const char *path, Model *model, Print* print, bool export_print_config);
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_Format_AMF_hpp_ */
|
118
src/libslic3r/Format/OBJ.cpp
Normal file
118
src/libslic3r/Format/OBJ.cpp
Normal file
|
@ -0,0 +1,118 @@
|
|||
#include "../libslic3r.h"
|
||||
#include "../Model.hpp"
|
||||
#include "../TriangleMesh.hpp"
|
||||
|
||||
#include "OBJ.hpp"
|
||||
#include "objparser.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define DIR_SEPARATOR '\\'
|
||||
#else
|
||||
#define DIR_SEPARATOR '/'
|
||||
#endif
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
bool load_obj(const char *path, Model *model, const char *object_name_in)
|
||||
{
|
||||
// Parse the OBJ file.
|
||||
ObjParser::ObjData data;
|
||||
if (! ObjParser::objparse(path, data)) {
|
||||
// die "Failed to parse $file\n" if !-e $path;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Count the faces and verify, that all faces are triangular.
|
||||
size_t num_faces = 0;
|
||||
size_t num_quads = 0;
|
||||
for (size_t i = 0; i < data.vertices.size(); ) {
|
||||
size_t j = i;
|
||||
for (; j < data.vertices.size() && data.vertices[j].coordIdx != -1; ++ j) ;
|
||||
if (i == j)
|
||||
continue;
|
||||
size_t face_vertices = j - i;
|
||||
if (face_vertices != 3 && face_vertices != 4) {
|
||||
// Non-triangular and non-quad faces are not supported as of now.
|
||||
return false;
|
||||
}
|
||||
if (face_vertices == 4)
|
||||
++ num_quads;
|
||||
++ num_faces;
|
||||
i = j + 1;
|
||||
}
|
||||
|
||||
// Convert ObjData into STL.
|
||||
TriangleMesh mesh;
|
||||
stl_file &stl = mesh.stl;
|
||||
stl.stats.type = inmemory;
|
||||
stl.stats.number_of_facets = int(num_faces + num_quads);
|
||||
stl.stats.original_num_facets = int(num_faces + num_quads);
|
||||
// stl_allocate clears all the allocated data to zero, all normals are set to zeros as well.
|
||||
stl_allocate(&stl);
|
||||
size_t i_face = 0;
|
||||
for (size_t i = 0; i < data.vertices.size(); ++ i) {
|
||||
if (data.vertices[i].coordIdx == -1)
|
||||
continue;
|
||||
stl_facet &facet = stl.facet_start[i_face ++];
|
||||
size_t num_normals = 0;
|
||||
stl_normal normal(stl_normal::Zero());
|
||||
for (unsigned int v = 0; v < 3; ++ v) {
|
||||
const ObjParser::ObjVertex &vertex = data.vertices[i++];
|
||||
memcpy(facet.vertex[v].data(), &data.coordinates[vertex.coordIdx*4], 3 * sizeof(float));
|
||||
if (vertex.normalIdx != -1) {
|
||||
normal(0) += data.normals[vertex.normalIdx*3];
|
||||
normal(1) += data.normals[vertex.normalIdx*3+1];
|
||||
normal(2) += data.normals[vertex.normalIdx*3+2];
|
||||
++ num_normals;
|
||||
}
|
||||
}
|
||||
if (data.vertices[i].coordIdx != -1) {
|
||||
// This is a quad. Produce the other triangle.
|
||||
stl_facet &facet2 = stl.facet_start[i_face++];
|
||||
facet2.vertex[0] = facet.vertex[0];
|
||||
facet2.vertex[1] = facet.vertex[2];
|
||||
const ObjParser::ObjVertex &vertex = data.vertices[i++];
|
||||
memcpy(facet2.vertex[2].data(), &data.coordinates[vertex.coordIdx * 4], 3 * sizeof(float));
|
||||
if (vertex.normalIdx != -1) {
|
||||
normal(0) += data.normals[vertex.normalIdx*3];
|
||||
normal(1) += data.normals[vertex.normalIdx*3+1];
|
||||
normal(2) += data.normals[vertex.normalIdx*3+2];
|
||||
++ num_normals;
|
||||
}
|
||||
if (num_normals == 4) {
|
||||
// Normalize an average normal of a quad.
|
||||
float len = facet.normal.norm();
|
||||
if (len > EPSILON) {
|
||||
normal /= len;
|
||||
facet.normal = normal;
|
||||
facet2.normal = normal;
|
||||
}
|
||||
}
|
||||
} else if (num_normals == 3) {
|
||||
// Normalize an average normal of a triangle.
|
||||
float len = facet.normal.norm();
|
||||
if (len > EPSILON)
|
||||
facet.normal = normal / len;
|
||||
}
|
||||
}
|
||||
stl_get_size(&stl);
|
||||
mesh.repair();
|
||||
if (mesh.facets_count() == 0) {
|
||||
// die "This STL file couldn't be read because it's empty.\n"
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string object_name;
|
||||
if (object_name_in == nullptr) {
|
||||
const char *last_slash = strrchr(path, DIR_SEPARATOR);
|
||||
object_name.assign((last_slash == nullptr) ? path : last_slash + 1);
|
||||
} else
|
||||
object_name.assign(object_name_in);
|
||||
|
||||
model->add_object(object_name.c_str(), path, std::move(mesh));
|
||||
return true;
|
||||
}
|
||||
|
||||
}; // namespace Slic3r
|
14
src/libslic3r/Format/OBJ.hpp
Normal file
14
src/libslic3r/Format/OBJ.hpp
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef slic3r_Format_OBJ_hpp_
|
||||
#define slic3r_Format_OBJ_hpp_
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class TriangleMesh;
|
||||
class Model;
|
||||
|
||||
// Load an OBJ file into a provided model.
|
||||
extern bool load_obj(const char *path, Model *model, const char *object_name = nullptr);
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_Format_OBJ_hpp_ */
|
354
src/libslic3r/Format/PRUS.cpp
Normal file
354
src/libslic3r/Format/PRUS.cpp
Normal file
|
@ -0,0 +1,354 @@
|
|||
#include <string.h>
|
||||
#include <exception>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
|
||||
#include <miniz/miniz_zip.h>
|
||||
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
#include "../libslic3r.h"
|
||||
#include "../Model.hpp"
|
||||
|
||||
#include "PRUS.hpp"
|
||||
|
||||
#if 0
|
||||
// Enable debugging and assert in this file.
|
||||
#define DEBUG
|
||||
#define _DEBUG
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
|
||||
struct StlHeader
|
||||
{
|
||||
char comment[80];
|
||||
uint32_t nTriangles;
|
||||
};
|
||||
|
||||
static_assert(sizeof(StlHeader) == 84, "StlHeader size not correct");
|
||||
|
||||
// Buffered line reader to a string buffer.
|
||||
class LineReader
|
||||
{
|
||||
public:
|
||||
LineReader(std::vector<char> &data) : m_buffer(data), m_pos(0), m_len((int)data.size()) {}
|
||||
|
||||
const char* next_line() {
|
||||
// Skip empty lines.
|
||||
while (m_pos < m_len && (m_buffer[m_pos] == '\r' || m_buffer[m_pos] == '\n'))
|
||||
++ m_pos;
|
||||
if (m_pos == m_len) {
|
||||
// End of file.
|
||||
return nullptr;
|
||||
}
|
||||
// The buffer is nonempty and it does not start with end of lines. Find the first end of line.
|
||||
int end = m_pos + 1;
|
||||
while (end < m_len && m_buffer[end] != '\r' && m_buffer[end] != '\n')
|
||||
++ end;
|
||||
char *ptr_out = m_buffer.data() + m_pos;
|
||||
m_pos = end + 1;
|
||||
m_buffer[end] = 0;
|
||||
return ptr_out;
|
||||
}
|
||||
|
||||
int next_line_scanf(const char *format, ...)
|
||||
{
|
||||
const char *line = next_line();
|
||||
if (line == nullptr)
|
||||
return -1;
|
||||
int result;
|
||||
va_list arglist;
|
||||
va_start(arglist, format);
|
||||
result = vsscanf(line, format, arglist);
|
||||
va_end(arglist);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<char> &m_buffer;
|
||||
int m_pos;
|
||||
int m_len;
|
||||
};
|
||||
|
||||
static void extract_model_from_archive(
|
||||
// name of the model file
|
||||
const char *name,
|
||||
// path to the archive
|
||||
const char *path,
|
||||
// content of scene.xml
|
||||
const std::vector<char> &scene_xml_data,
|
||||
// loaded data of this STL
|
||||
std::vector<char> &data,
|
||||
// Model, to which the newly loaded objects will be added
|
||||
Model *model,
|
||||
// To map multiple STLs into a single model object for multi-material prints.
|
||||
std::map<int, ModelObject*> &group_to_model_object)
|
||||
{
|
||||
// Find the model entry in the XML data.
|
||||
char model_name_tag[1024];
|
||||
sprintf(model_name_tag, "<model name=\"%s\">", name);
|
||||
const char *model_xml = strstr(scene_xml_data.data(), model_name_tag);
|
||||
const char *zero_tag = "<zero>";
|
||||
const char *zero_xml = strstr(scene_xml_data.data(), zero_tag);
|
||||
float trafo[3][4] = { 0 };
|
||||
Vec3d instance_rotation = Vec3d::Zero();
|
||||
Vec3d instance_scaling_factor = Vec3d::Ones();
|
||||
Vec3d instance_offset = Vec3d::Zero();
|
||||
bool trafo_set = false;
|
||||
unsigned int group_id = (unsigned int)-1;
|
||||
unsigned int extruder_id = (unsigned int)-1;
|
||||
ModelObject *model_object = nullptr;
|
||||
if (model_xml != nullptr) {
|
||||
model_xml += strlen(model_name_tag);
|
||||
const char *position_tag = "<position>";
|
||||
const char *position_xml = strstr(model_xml, position_tag);
|
||||
const char *rotation_tag = "<rotation>";
|
||||
const char *rotation_xml = strstr(model_xml, rotation_tag);
|
||||
const char *scale_tag = "<scale>";
|
||||
const char *scale_xml = strstr(model_xml, scale_tag);
|
||||
float position[3], rotation[3], scale[3], zero[3];
|
||||
if (position_xml != nullptr && rotation_xml != nullptr && scale_xml != nullptr && zero_xml != nullptr &&
|
||||
sscanf(position_xml+strlen(position_tag),
|
||||
"[%f, %f, %f]", position, position+1, position+2) == 3 &&
|
||||
sscanf(rotation_xml+strlen(rotation_tag),
|
||||
"[%f, %f, %f]", rotation, rotation+1, rotation+2) == 3 &&
|
||||
sscanf(scale_xml+strlen(scale_tag),
|
||||
"[%f, %f, %f]", scale, scale+1, scale+2) == 3 &&
|
||||
sscanf(zero_xml+strlen(zero_tag),
|
||||
"[%f, %f, %f]", zero, zero+1, zero+2) == 3) {
|
||||
instance_scaling_factor = Vec3d((double)scale[0], (double)scale[1], (double)scale[2]);
|
||||
instance_rotation = Vec3d(-(double)rotation[0], -(double)rotation[1], -(double)rotation[2]);
|
||||
Eigen::Matrix3f mat_rot, mat_scale, mat_trafo;
|
||||
mat_rot = Eigen::AngleAxisf(-rotation[2], Eigen::Vector3f::UnitZ()) *
|
||||
Eigen::AngleAxisf(-rotation[1], Eigen::Vector3f::UnitY()) *
|
||||
Eigen::AngleAxisf(-rotation[0], Eigen::Vector3f::UnitX());
|
||||
mat_scale = Eigen::Scaling(scale[0], scale[1], scale[2]);
|
||||
mat_trafo = mat_rot * mat_scale;
|
||||
for (size_t r = 0; r < 3; ++ r) {
|
||||
for (size_t c = 0; c < 3; ++ c)
|
||||
trafo[r][c] += mat_trafo(r, c);
|
||||
}
|
||||
instance_offset = Vec3d((double)(position[0] - zero[0]), (double)(position[1] - zero[1]), (double)(position[2] - zero[2]));
|
||||
// CHECK_ME -> Is the following correct ?
|
||||
trafo[2][3] = position[2] / (float)instance_scaling_factor(2);
|
||||
trafo_set = true;
|
||||
}
|
||||
const char *group_tag = "<group>";
|
||||
const char *group_xml = strstr(model_xml, group_tag);
|
||||
const char *extruder_tag = "<extruder>";
|
||||
const char *extruder_xml = strstr(model_xml, extruder_tag);
|
||||
if (group_xml != nullptr) {
|
||||
int group = atoi(group_xml + strlen(group_tag));
|
||||
if (group > 0) {
|
||||
group_id = group;
|
||||
auto it = group_to_model_object.find(group_id);
|
||||
if (it != group_to_model_object.end())
|
||||
model_object = it->second;
|
||||
}
|
||||
}
|
||||
if (extruder_xml != nullptr) {
|
||||
int e = atoi(extruder_xml + strlen(extruder_tag));
|
||||
if (e > 0)
|
||||
extruder_id = e;
|
||||
}
|
||||
}
|
||||
if (! trafo_set)
|
||||
throw std::runtime_error(std::string("Archive ") + path + " does not contain a valid entry in scene.xml for " + name);
|
||||
|
||||
// Extract the STL.
|
||||
StlHeader header;
|
||||
TriangleMesh mesh;
|
||||
bool mesh_valid = false;
|
||||
bool stl_ascii = false;
|
||||
if (data.size() > sizeof(StlHeader)) {
|
||||
memcpy((char*)&header, data.data(), sizeof(StlHeader));
|
||||
if (strncmp(header.comment, "solid ", 6) == 0)
|
||||
stl_ascii = true;
|
||||
else {
|
||||
// Header has been extracted. Now read the faces.
|
||||
stl_file &stl = mesh.stl;
|
||||
stl.error = 0;
|
||||
stl.stats.type = inmemory;
|
||||
stl.stats.number_of_facets = header.nTriangles;
|
||||
stl.stats.original_num_facets = header.nTriangles;
|
||||
stl_allocate(&stl);
|
||||
if (header.nTriangles > 0 && data.size() == 50 * header.nTriangles + sizeof(StlHeader)) {
|
||||
memcpy((char*)stl.facet_start, data.data() + sizeof(StlHeader), 50 * header.nTriangles);
|
||||
if (sizeof(stl_facet) > SIZEOF_STL_FACET) {
|
||||
// The stl.facet_start is not packed tightly. Unpack the array of stl_facets.
|
||||
unsigned char *data = (unsigned char*)stl.facet_start;
|
||||
for (size_t i = header.nTriangles - 1; i > 0; -- i)
|
||||
memmove(data + i * sizeof(stl_facet), data + i * SIZEOF_STL_FACET, SIZEOF_STL_FACET);
|
||||
}
|
||||
// All the faces have been read.
|
||||
stl_get_size(&stl);
|
||||
mesh.repair();
|
||||
// Transform the model.
|
||||
stl_transform(&stl, &trafo[0][0]);
|
||||
if (std::abs(stl.stats.min(2)) < EPSILON)
|
||||
stl.stats.min(2) = 0.;
|
||||
// Add a mesh to a model.
|
||||
if (mesh.facets_count() > 0)
|
||||
mesh_valid = true;
|
||||
}
|
||||
}
|
||||
} else
|
||||
stl_ascii = true;
|
||||
|
||||
if (stl_ascii) {
|
||||
// Try to parse ASCII STL.
|
||||
char normal_buf[3][32];
|
||||
stl_facet facet;
|
||||
std::vector<stl_facet> facets;
|
||||
LineReader line_reader(data);
|
||||
std::string solid_name;
|
||||
facet.extra[0] = facet.extra[1] = 0;
|
||||
for (;;) {
|
||||
const char *line = line_reader.next_line();
|
||||
if (line == nullptr)
|
||||
// End of file.
|
||||
break;
|
||||
if (strncmp(line, "solid", 5) == 0) {
|
||||
// Opening the "solid" block.
|
||||
if (! solid_name.empty()) {
|
||||
// Error, solid block is already open.
|
||||
facets.clear();
|
||||
break;
|
||||
}
|
||||
solid_name = line + 5;
|
||||
if (solid_name.empty())
|
||||
solid_name = "unknown";
|
||||
continue;
|
||||
}
|
||||
if (strncmp(line, "endsolid", 8) == 0) {
|
||||
// Closing the "solid" block.
|
||||
if (solid_name.empty()) {
|
||||
// Error, no solid block is open.
|
||||
facets.clear();
|
||||
break;
|
||||
}
|
||||
solid_name.clear();
|
||||
continue;
|
||||
}
|
||||
// Line has to start with the word solid.
|
||||
int res_normal = sscanf(line, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]);
|
||||
assert(res_normal == 3);
|
||||
int res_outer_loop = line_reader.next_line_scanf(" outer loop");
|
||||
assert(res_outer_loop == 0);
|
||||
int res_vertex1 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2));
|
||||
assert(res_vertex1 == 3);
|
||||
int res_vertex2 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2));
|
||||
assert(res_vertex2 == 3);
|
||||
int res_vertex3 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2));
|
||||
assert(res_vertex3 == 3);
|
||||
int res_endloop = line_reader.next_line_scanf(" endloop");
|
||||
assert(res_endloop == 0);
|
||||
int res_endfacet = line_reader.next_line_scanf(" endfacet");
|
||||
if (res_normal != 3 || res_outer_loop != 0 || res_vertex1 != 3 || res_vertex2 != 3 || res_vertex3 != 3 || res_endloop != 0 || res_endfacet != 0) {
|
||||
// perror("Something is syntactically very wrong with this ASCII STL!");
|
||||
facets.clear();
|
||||
break;
|
||||
}
|
||||
// The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition.
|
||||
if (sscanf(normal_buf[0], "%f", &facet.normal(0)) != 1 ||
|
||||
sscanf(normal_buf[1], "%f", &facet.normal(1)) != 1 ||
|
||||
sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) {
|
||||
// Normal was mangled. Maybe denormals or "not a number" were stored?
|
||||
// Just reset the normal and silently ignore it.
|
||||
memset(&facet.normal, 0, sizeof(facet.normal));
|
||||
}
|
||||
facets.emplace_back(facet);
|
||||
}
|
||||
if (! facets.empty() && solid_name.empty()) {
|
||||
stl_file &stl = mesh.stl;
|
||||
stl.stats.type = inmemory;
|
||||
stl.stats.number_of_facets = (uint32_t)facets.size();
|
||||
stl.stats.original_num_facets = (int)facets.size();
|
||||
stl_allocate(&stl);
|
||||
memcpy((void*)stl.facet_start, facets.data(), facets.size() * 50);
|
||||
stl_get_size(&stl);
|
||||
mesh.repair();
|
||||
// Transform the model.
|
||||
stl_transform(&stl, &trafo[0][0]);
|
||||
// Add a mesh to a model.
|
||||
if (mesh.facets_count() > 0)
|
||||
mesh_valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (! mesh_valid)
|
||||
throw std::runtime_error(std::string("Archive ") + path + " does not contain a valid mesh for " + name);
|
||||
|
||||
// Add this mesh to the model.
|
||||
ModelVolume *volume = nullptr;
|
||||
if (model_object == nullptr) {
|
||||
// This is a first mesh of a group. Create a new object & volume.
|
||||
model_object = model->add_object(name, path, std::move(mesh));
|
||||
volume = model_object->volumes.front();
|
||||
ModelInstance *instance = model_object->add_instance();
|
||||
instance->set_rotation(instance_rotation);
|
||||
instance->set_scaling_factor(instance_scaling_factor);
|
||||
instance->set_offset(instance_offset);
|
||||
if (group_id != (size_t)-1)
|
||||
group_to_model_object[group_id] = model_object;
|
||||
} else {
|
||||
// This is not the 1st mesh of a group. Add it to the ModelObject.
|
||||
volume = model_object->add_volume(std::move(mesh));
|
||||
volume->name = name;
|
||||
}
|
||||
// Set the extruder to the volume.
|
||||
if (extruder_id != (unsigned int)-1) {
|
||||
char str_extruder[64];
|
||||
sprintf(str_extruder, "%ud", extruder_id);
|
||||
volume->config.set_deserialize("extruder", str_extruder);
|
||||
}
|
||||
}
|
||||
|
||||
// Load a PrusaControl project file into a provided model.
|
||||
bool load_prus(const char *path, Model *model)
|
||||
{
|
||||
mz_zip_archive archive;
|
||||
mz_zip_zero_struct(&archive);
|
||||
mz_bool res = mz_zip_reader_init_file(&archive, path, 0);
|
||||
size_t n_models_initial = model->objects.size();
|
||||
try {
|
||||
if (res == MZ_FALSE)
|
||||
throw std::runtime_error(std::string("Unable to init zip reader for ") + path);
|
||||
std::vector<char> scene_xml_data;
|
||||
// For grouping multiple STLs into a single ModelObject for multi-material prints.
|
||||
std::map<int, ModelObject*> group_to_model_object;
|
||||
mz_uint num_entries = mz_zip_reader_get_num_files(&archive);
|
||||
for (mz_uint i = 0; i < num_entries; ++ i) {
|
||||
mz_zip_archive_file_stat stat;
|
||||
if (! mz_zip_reader_file_stat(&archive, i, &stat))
|
||||
continue;
|
||||
std::vector<char> buffer;
|
||||
buffer.assign((size_t)stat.m_uncomp_size + 1, 0);
|
||||
res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (char*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
|
||||
if (res == MZ_FALSE)
|
||||
std::runtime_error(std::string("Error while extracting a file from ") + path);
|
||||
if (strcmp(stat.m_filename, "scene.xml") == 0) {
|
||||
if (! scene_xml_data.empty())
|
||||
throw std::runtime_error(std::string("Multiple scene.xml were found in the archive.") + path);
|
||||
scene_xml_data = std::move(buffer);
|
||||
} else if (boost::iends_with(stat.m_filename, ".stl")) {
|
||||
// May throw std::exception
|
||||
extract_model_from_archive(stat.m_filename, path, scene_xml_data, buffer, model, group_to_model_object);
|
||||
}
|
||||
}
|
||||
} catch (std::exception &ex) {
|
||||
mz_zip_reader_end(&archive);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
mz_zip_reader_end(&archive);
|
||||
return model->objects.size() > n_models_initial;
|
||||
}
|
||||
|
||||
}; // namespace Slic3r
|
11
src/libslic3r/Format/PRUS.hpp
Normal file
11
src/libslic3r/Format/PRUS.hpp
Normal file
|
@ -0,0 +1,11 @@
|
|||
#define slic3r_Format_PRUS_hpp_
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class TriangleMesh;
|
||||
class Model;
|
||||
|
||||
// Load a PrusaControl project file into a provided model.
|
||||
extern bool load_prus(const char *path, Model *model);
|
||||
|
||||
}; // namespace Slic3r
|
58
src/libslic3r/Format/STL.cpp
Normal file
58
src/libslic3r/Format/STL.cpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
#include "../libslic3r.h"
|
||||
#include "../Model.hpp"
|
||||
#include "../TriangleMesh.hpp"
|
||||
|
||||
#include "STL.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define DIR_SEPARATOR '\\'
|
||||
#else
|
||||
#define DIR_SEPARATOR '/'
|
||||
#endif
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
bool load_stl(const char *path, Model *model, const char *object_name_in)
|
||||
{
|
||||
TriangleMesh mesh;
|
||||
mesh.ReadSTLFile(path);
|
||||
if (mesh.stl.error) {
|
||||
// die "Failed to open $file\n" if !-e $path;
|
||||
return false;
|
||||
}
|
||||
mesh.repair();
|
||||
if (mesh.facets_count() == 0) {
|
||||
// die "This STL file couldn't be read because it's empty.\n"
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string object_name;
|
||||
if (object_name_in == nullptr) {
|
||||
const char *last_slash = strrchr(path, DIR_SEPARATOR);
|
||||
object_name.assign((last_slash == nullptr) ? path : last_slash + 1);
|
||||
} else
|
||||
object_name.assign(object_name_in);
|
||||
|
||||
model->add_object(object_name.c_str(), path, std::move(mesh));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool store_stl(const char *path, TriangleMesh *mesh, bool binary)
|
||||
{
|
||||
if (binary)
|
||||
mesh->write_binary(path);
|
||||
else
|
||||
mesh->write_ascii(path);
|
||||
//FIXME returning false even if write failed.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool store_stl(const char *path, ModelObject *model_object, bool binary)
|
||||
{
|
||||
TriangleMesh mesh = model_object->mesh();
|
||||
return store_stl(path, &mesh, binary);
|
||||
}
|
||||
|
||||
}; // namespace Slic3r
|
17
src/libslic3r/Format/STL.hpp
Normal file
17
src/libslic3r/Format/STL.hpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef slic3r_Format_STL_hpp_
|
||||
#define slic3r_Format_STL_hpp_
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class TriangleMesh;
|
||||
class ModelObject;
|
||||
|
||||
// Load an STL file into a provided model.
|
||||
extern bool load_stl(const char *path, Model *model, const char *object_name = nullptr);
|
||||
|
||||
extern bool store_stl(const char *path, TriangleMesh *mesh, bool binary);
|
||||
extern bool store_stl(const char *path, ModelObject *model_object, bool binary);
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_Format_STL_hpp_ */
|
540
src/libslic3r/Format/objparser.cpp
Normal file
540
src/libslic3r/Format/objparser.cpp
Normal file
|
@ -0,0 +1,540 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
|
||||
#include "objparser.hpp"
|
||||
|
||||
namespace ObjParser {
|
||||
|
||||
static bool obj_parseline(const char *line, ObjData &data)
|
||||
{
|
||||
#define EATWS() while (*line == ' ' || *line == '\t') ++ line
|
||||
|
||||
if (*line == 0)
|
||||
return true;
|
||||
|
||||
// Ignore whitespaces at the beginning of the line.
|
||||
//FIXME is this a good idea?
|
||||
EATWS();
|
||||
|
||||
char c1 = *line ++;
|
||||
switch (c1) {
|
||||
case '#':
|
||||
// Comment, ignore the rest of the line.
|
||||
break;
|
||||
case 'v':
|
||||
{
|
||||
// Parse vertex geometry (position, normal, texture coordinates)
|
||||
char c2 = *line ++;
|
||||
switch (c2) {
|
||||
case 't':
|
||||
{
|
||||
// vt - vertex texture parameter
|
||||
// u v [w], w == 0 (or w == 1)
|
||||
char c2 = *line ++;
|
||||
if (c2 != ' ' && c2 != '\t')
|
||||
return false;
|
||||
EATWS();
|
||||
char *endptr = 0;
|
||||
double u = strtod(line, &endptr);
|
||||
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t'))
|
||||
return false;
|
||||
line = endptr;
|
||||
EATWS();
|
||||
double v = 0;
|
||||
if (*line != 0) {
|
||||
v = strtod(line, &endptr);
|
||||
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
|
||||
return false;
|
||||
line = endptr;
|
||||
EATWS();
|
||||
}
|
||||
double w = 0;
|
||||
if (*line != 0) {
|
||||
w = strtod(line, &endptr);
|
||||
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
|
||||
return false;
|
||||
line = endptr;
|
||||
EATWS();
|
||||
}
|
||||
if (*line != 0)
|
||||
return false;
|
||||
data.textureCoordinates.push_back((float)u);
|
||||
data.textureCoordinates.push_back((float)v);
|
||||
data.textureCoordinates.push_back((float)w);
|
||||
break;
|
||||
}
|
||||
case 'n':
|
||||
{
|
||||
// vn - vertex normal
|
||||
// x y z
|
||||
char c2 = *line ++;
|
||||
if (c2 != ' ' && c2 != '\t')
|
||||
return false;
|
||||
EATWS();
|
||||
char *endptr = 0;
|
||||
double x = strtod(line, &endptr);
|
||||
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t'))
|
||||
return false;
|
||||
line = endptr;
|
||||
EATWS();
|
||||
double y = strtod(line, &endptr);
|
||||
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t'))
|
||||
return false;
|
||||
line = endptr;
|
||||
EATWS();
|
||||
double z = strtod(line, &endptr);
|
||||
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
|
||||
return false;
|
||||
line = endptr;
|
||||
EATWS();
|
||||
if (*line != 0)
|
||||
return false;
|
||||
data.normals.push_back((float)x);
|
||||
data.normals.push_back((float)y);
|
||||
data.normals.push_back((float)z);
|
||||
break;
|
||||
}
|
||||
case 'p':
|
||||
{
|
||||
// vp - vertex parameter
|
||||
char c2 = *line ++;
|
||||
if (c2 != ' ' && c2 != '\t')
|
||||
return false;
|
||||
EATWS();
|
||||
char *endptr = 0;
|
||||
double u = strtod(line, &endptr);
|
||||
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
|
||||
return false;
|
||||
line = endptr;
|
||||
EATWS();
|
||||
double v = strtod(line, &endptr);
|
||||
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
|
||||
return false;
|
||||
line = endptr;
|
||||
EATWS();
|
||||
double w = 0;
|
||||
if (*line != 0) {
|
||||
w = strtod(line, &endptr);
|
||||
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
|
||||
return false;
|
||||
line = endptr;
|
||||
EATWS();
|
||||
}
|
||||
if (*line != 0)
|
||||
return false;
|
||||
data.parameters.push_back((float)u);
|
||||
data.parameters.push_back((float)v);
|
||||
data.parameters.push_back((float)w);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// v - vertex geometry
|
||||
if (c2 != ' ' && c2 != '\t')
|
||||
return false;
|
||||
EATWS();
|
||||
char *endptr = 0;
|
||||
double x = strtod(line, &endptr);
|
||||
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t'))
|
||||
return false;
|
||||
line = endptr;
|
||||
EATWS();
|
||||
double y = strtod(line, &endptr);
|
||||
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t'))
|
||||
return false;
|
||||
line = endptr;
|
||||
EATWS();
|
||||
double z = strtod(line, &endptr);
|
||||
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
|
||||
return false;
|
||||
line = endptr;
|
||||
EATWS();
|
||||
double w = 1.0;
|
||||
if (*line != 0) {
|
||||
w = strtod(line, &endptr);
|
||||
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
|
||||
return false;
|
||||
line = endptr;
|
||||
EATWS();
|
||||
}
|
||||
if (*line != 0)
|
||||
return false;
|
||||
data.coordinates.push_back((float)x);
|
||||
data.coordinates.push_back((float)y);
|
||||
data.coordinates.push_back((float)z);
|
||||
data.coordinates.push_back((float)w);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'f':
|
||||
{
|
||||
// face
|
||||
EATWS();
|
||||
if (*line == 0)
|
||||
return false;
|
||||
// number of vertices of this face
|
||||
int n = 0;
|
||||
// current vertex to be parsed
|
||||
ObjVertex vertex;
|
||||
char *endptr = 0;
|
||||
while (*line != 0) {
|
||||
// Parse a single vertex reference.
|
||||
vertex.coordIdx = 0;
|
||||
vertex.normalIdx = 0;
|
||||
vertex.textureCoordIdx = 0;
|
||||
vertex.coordIdx = strtol(line, &endptr, 10);
|
||||
// Coordinate has to be defined
|
||||
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != '/' && *endptr != 0))
|
||||
return false;
|
||||
line = endptr;
|
||||
if (*line == '/') {
|
||||
++ line;
|
||||
// Texture coordinate index may be missing after a 1st slash, but then the normal index has to be present.
|
||||
if (*line != '/') {
|
||||
// Parse the texture coordinate index.
|
||||
vertex.textureCoordIdx = strtol(line, &endptr, 10);
|
||||
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != '/' && *endptr != 0))
|
||||
return false;
|
||||
line = endptr;
|
||||
}
|
||||
if (*line == '/') {
|
||||
// Parse normal index.
|
||||
++ line;
|
||||
vertex.normalIdx = strtol(line, &endptr, 10);
|
||||
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
|
||||
return false;
|
||||
line = endptr;
|
||||
}
|
||||
}
|
||||
if (vertex.coordIdx < 0)
|
||||
vertex.coordIdx += data.coordinates.size() / 4;
|
||||
else
|
||||
-- vertex.coordIdx;
|
||||
if (vertex.normalIdx < 0)
|
||||
vertex.normalIdx += data.normals.size() / 3;
|
||||
else
|
||||
-- vertex.normalIdx;
|
||||
if (vertex.textureCoordIdx < 0)
|
||||
vertex.textureCoordIdx += data.textureCoordinates.size() / 3;
|
||||
else
|
||||
-- vertex.textureCoordIdx;
|
||||
data.vertices.push_back(vertex);
|
||||
EATWS();
|
||||
}
|
||||
vertex.coordIdx = -1;
|
||||
vertex.normalIdx = -1;
|
||||
vertex.textureCoordIdx = -1;
|
||||
data.vertices.push_back(vertex);
|
||||
break;
|
||||
}
|
||||
case 'm':
|
||||
{
|
||||
if (*(line ++) != 't' ||
|
||||
*(line ++) != 'l' ||
|
||||
*(line ++) != 'l' ||
|
||||
*(line ++) != 'i' ||
|
||||
*(line ++) != 'b')
|
||||
return false;
|
||||
// mtllib [external .mtl file name]
|
||||
// printf("mtllib %s\r\n", line);
|
||||
EATWS();
|
||||
data.mtllibs.push_back(std::string(line));
|
||||
break;
|
||||
}
|
||||
case 'u':
|
||||
{
|
||||
if (*(line ++) != 's' ||
|
||||
*(line ++) != 'e' ||
|
||||
*(line ++) != 'm' ||
|
||||
*(line ++) != 't' ||
|
||||
*(line ++) != 'l')
|
||||
return false;
|
||||
// usemtl [material name]
|
||||
// printf("usemtl %s\r\n", line);
|
||||
EATWS();
|
||||
ObjUseMtl usemtl;
|
||||
usemtl.vertexIdxFirst = data.vertices.size();
|
||||
usemtl.name = line;
|
||||
data.usemtls.push_back(usemtl);
|
||||
break;
|
||||
}
|
||||
case 'o':
|
||||
{
|
||||
// o [object name]
|
||||
EATWS();
|
||||
const char *name = line;
|
||||
while (*line != ' ' && *line != '\t' && *line != 0)
|
||||
++ line;
|
||||
// copy name to line.
|
||||
EATWS();
|
||||
if (*line != 0)
|
||||
return false;
|
||||
ObjObject object;
|
||||
object.vertexIdxFirst = data.vertices.size();
|
||||
object.name = line;
|
||||
data.objects.push_back(object);
|
||||
break;
|
||||
}
|
||||
case 'g':
|
||||
{
|
||||
// g [group name]
|
||||
// printf("group %s\r\n", line);
|
||||
ObjGroup group;
|
||||
group.vertexIdxFirst = data.vertices.size();
|
||||
group.name = line;
|
||||
data.groups.push_back(group);
|
||||
break;
|
||||
}
|
||||
case 's':
|
||||
{
|
||||
// s 1 / off
|
||||
char c2 = *line ++;
|
||||
if (c2 != ' ' && c2 != '\t')
|
||||
return false;
|
||||
EATWS();
|
||||
char *endptr = 0;
|
||||
long g = strtol(line, &endptr, 10);
|
||||
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
|
||||
return false;
|
||||
line = endptr;
|
||||
EATWS();
|
||||
if (*line != 0)
|
||||
return false;
|
||||
ObjSmoothingGroup group;
|
||||
group.vertexIdxFirst = data.vertices.size();
|
||||
group.smoothingGroupID = g;
|
||||
data.smoothingGroups.push_back(group);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("ObjParser: Unknown command: %c\r\n", c1);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool objparse(const char *path, ObjData &data)
|
||||
{
|
||||
FILE *pFile = boost::nowide::fopen(path, "rt");
|
||||
if (pFile == 0)
|
||||
return false;
|
||||
|
||||
try {
|
||||
char buf[65536 * 2];
|
||||
size_t len = 0;
|
||||
size_t lenPrev = 0;
|
||||
while ((len = ::fread(buf + lenPrev, 1, 65536, pFile)) != 0) {
|
||||
len += lenPrev;
|
||||
size_t lastLine = 0;
|
||||
for (size_t i = 0; i < len; ++ i)
|
||||
if (buf[i] == '\r' || buf[i] == '\n') {
|
||||
buf[i] = 0;
|
||||
char *c = buf + lastLine;
|
||||
while (*c == ' ' || *c == '\t')
|
||||
++ c;
|
||||
obj_parseline(c, data);
|
||||
lastLine = i + 1;
|
||||
}
|
||||
lenPrev = len - lastLine;
|
||||
memmove(buf, buf + lastLine, lenPrev);
|
||||
}
|
||||
} catch (std::bad_alloc &ex) {
|
||||
printf("Out of memory\r\n");
|
||||
}
|
||||
::fclose(pFile);
|
||||
|
||||
// printf("vertices: %d\r\n", data.vertices.size() / 4);
|
||||
// printf("coords: %d\r\n", data.coordinates.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool savevector(FILE *pFile, const std::vector<T> &v)
|
||||
{
|
||||
size_t cnt = v.size();
|
||||
::fwrite(&cnt, 1, sizeof(cnt), pFile);
|
||||
//FIXME sizeof(T) works for data types leaving no gaps in the allocated vector because of alignment of the T type.
|
||||
if (! v.empty())
|
||||
::fwrite(&v.front(), 1, sizeof(T) * cnt, pFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool savevector(FILE *pFile, const std::vector<std::string> &v)
|
||||
{
|
||||
size_t cnt = v.size();
|
||||
::fwrite(&cnt, 1, sizeof(cnt), pFile);
|
||||
for (size_t i = 0; i < cnt; ++ i) {
|
||||
size_t len = v[i].size();
|
||||
::fwrite(&len, 1, sizeof(cnt), pFile);
|
||||
::fwrite(v[i].c_str(), 1, len, pFile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool savevectornameidx(FILE *pFile, const std::vector<T> &v)
|
||||
{
|
||||
size_t cnt = v.size();
|
||||
::fwrite(&cnt, 1, sizeof(cnt), pFile);
|
||||
for (size_t i = 0; i < cnt; ++ i) {
|
||||
::fwrite(&v[i].vertexIdxFirst, 1, sizeof(int), pFile);
|
||||
size_t len = v[i].name.size();
|
||||
::fwrite(&len, 1, sizeof(cnt), pFile);
|
||||
::fwrite(v[i].name.c_str(), 1, len, pFile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool loadvector(FILE *pFile, std::vector<T> &v)
|
||||
{
|
||||
v.clear();
|
||||
size_t cnt = 0;
|
||||
if (::fread(&cnt, sizeof(cnt), 1, pFile) != 1)
|
||||
return false;
|
||||
//FIXME sizeof(T) works for data types leaving no gaps in the allocated vector because of alignment of the T type.
|
||||
if (cnt != 0) {
|
||||
v.assign(cnt, T());
|
||||
if (::fread(&v.front(), sizeof(T), cnt, pFile) != cnt)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool loadvector(FILE *pFile, std::vector<std::string> &v)
|
||||
{
|
||||
v.clear();
|
||||
size_t cnt = 0;
|
||||
if (::fread(&cnt, sizeof(cnt), 1, pFile) != 1)
|
||||
return false;
|
||||
v.reserve(cnt);
|
||||
for (size_t i = 0; i < cnt; ++ i) {
|
||||
size_t len = 0;
|
||||
if (::fread(&len, sizeof(len), 1, pFile) != 1)
|
||||
return false;
|
||||
std::string s(" ", len);
|
||||
if (::fread(const_cast<char*>(s.c_str()), 1, len, pFile) != len)
|
||||
return false;
|
||||
v.push_back(std::move(s));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool loadvectornameidx(FILE *pFile, std::vector<T> &v)
|
||||
{
|
||||
v.clear();
|
||||
size_t cnt = 0;
|
||||
if (::fread(&cnt, sizeof(cnt), 1, pFile) != 1)
|
||||
return false;
|
||||
v.assign(cnt, T());
|
||||
for (size_t i = 0; i < cnt; ++ i) {
|
||||
if (::fread(&v[i].vertexIdxFirst, sizeof(int), 1, pFile) != 1)
|
||||
return false;
|
||||
size_t len = 0;
|
||||
if (::fread(&len, sizeof(len), 1, pFile) != 1)
|
||||
return false;
|
||||
v[i].name.assign(" ", len);
|
||||
if (::fread(const_cast<char*>(v[i].name.c_str()), 1, len, pFile) != len)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool objbinsave(const char *path, const ObjData &data)
|
||||
{
|
||||
FILE *pFile = boost::nowide::fopen(path, "wb");
|
||||
if (pFile == 0)
|
||||
return false;
|
||||
|
||||
size_t version = 1;
|
||||
::fwrite(&version, 1, sizeof(version), pFile);
|
||||
|
||||
bool result =
|
||||
savevector(pFile, data.coordinates) &&
|
||||
savevector(pFile, data.textureCoordinates) &&
|
||||
savevector(pFile, data.normals) &&
|
||||
savevector(pFile, data.parameters) &&
|
||||
savevector(pFile, data.mtllibs) &&
|
||||
savevectornameidx(pFile, data.usemtls) &&
|
||||
savevectornameidx(pFile, data.objects) &&
|
||||
savevectornameidx(pFile, data.groups) &&
|
||||
savevector(pFile, data.smoothingGroups) &&
|
||||
savevector(pFile, data.vertices);
|
||||
|
||||
::fclose(pFile);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool objbinload(const char *path, ObjData &data)
|
||||
{
|
||||
FILE *pFile = boost::nowide::fopen(path, "rb");
|
||||
if (pFile == 0)
|
||||
return false;
|
||||
|
||||
data.version = 0;
|
||||
if (::fread(&data.version, sizeof(data.version), 1, pFile) != 1)
|
||||
return false;
|
||||
if (data.version != 1)
|
||||
return false;
|
||||
|
||||
bool result =
|
||||
loadvector(pFile, data.coordinates) &&
|
||||
loadvector(pFile, data.textureCoordinates) &&
|
||||
loadvector(pFile, data.normals) &&
|
||||
loadvector(pFile, data.parameters) &&
|
||||
loadvector(pFile, data.mtllibs) &&
|
||||
loadvectornameidx(pFile, data.usemtls) &&
|
||||
loadvectornameidx(pFile, data.objects) &&
|
||||
loadvectornameidx(pFile, data.groups) &&
|
||||
loadvector(pFile, data.smoothingGroups) &&
|
||||
loadvector(pFile, data.vertices);
|
||||
|
||||
::fclose(pFile);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool vectorequal(const std::vector<T> &v1, const std::vector<T> &v2)
|
||||
{
|
||||
if (v1.size() != v2.size())
|
||||
return false;
|
||||
for (size_t i = 0; i < v1.size(); ++ i)
|
||||
if (! (v1[i] == v2[i]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vectorequal(const std::vector<std::string> &v1, const std::vector<std::string> &v2)
|
||||
{
|
||||
if (v1.size() != v2.size())
|
||||
return false;
|
||||
for (size_t i = 0; i < v1.size(); ++ i)
|
||||
if (v1[i].compare(v2[i]) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
extern bool objequal(const ObjData &data1, const ObjData &data2)
|
||||
{
|
||||
//FIXME ignore version number
|
||||
// version;
|
||||
|
||||
return
|
||||
vectorequal(data1.coordinates, data2.coordinates) &&
|
||||
vectorequal(data1.textureCoordinates, data2.textureCoordinates) &&
|
||||
vectorequal(data1.normals, data2.normals) &&
|
||||
vectorequal(data1.parameters, data2.parameters) &&
|
||||
vectorequal(data1.mtllibs, data2.mtllibs) &&
|
||||
vectorequal(data1.usemtls, data2.usemtls) &&
|
||||
vectorequal(data1.objects, data2.objects) &&
|
||||
vectorequal(data1.groups, data2.groups) &&
|
||||
vectorequal(data1.vertices, data2.vertices);
|
||||
}
|
||||
|
||||
} // namespace ObjParser
|
109
src/libslic3r/Format/objparser.hpp
Normal file
109
src/libslic3r/Format/objparser.hpp
Normal file
|
@ -0,0 +1,109 @@
|
|||
#ifndef slic3r_Format_objparser_hpp_
|
||||
#define slic3r_Format_objparser_hpp_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ObjParser {
|
||||
|
||||
struct ObjVertex
|
||||
{
|
||||
int coordIdx;
|
||||
int textureCoordIdx;
|
||||
int normalIdx;
|
||||
};
|
||||
|
||||
inline bool operator==(const ObjVertex &v1, const ObjVertex &v2)
|
||||
{
|
||||
return
|
||||
v1.coordIdx == v2.coordIdx &&
|
||||
v1.textureCoordIdx == v2.textureCoordIdx &&
|
||||
v1.normalIdx == v2.normalIdx;
|
||||
}
|
||||
|
||||
struct ObjUseMtl
|
||||
{
|
||||
int vertexIdxFirst;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
inline bool operator==(const ObjUseMtl &v1, const ObjUseMtl &v2)
|
||||
{
|
||||
return
|
||||
v1.vertexIdxFirst == v2.vertexIdxFirst &&
|
||||
v1.name.compare(v2.name) == 0;
|
||||
}
|
||||
|
||||
struct ObjObject
|
||||
{
|
||||
int vertexIdxFirst;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
inline bool operator==(const ObjObject &v1, const ObjObject &v2)
|
||||
{
|
||||
return
|
||||
v1.vertexIdxFirst == v2.vertexIdxFirst &&
|
||||
v1.name.compare(v2.name) == 0;
|
||||
}
|
||||
|
||||
struct ObjGroup
|
||||
{
|
||||
int vertexIdxFirst;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
inline bool operator==(const ObjGroup &v1, const ObjGroup &v2)
|
||||
{
|
||||
return
|
||||
v1.vertexIdxFirst == v2.vertexIdxFirst &&
|
||||
v1.name.compare(v2.name) == 0;
|
||||
}
|
||||
|
||||
struct ObjSmoothingGroup
|
||||
{
|
||||
int vertexIdxFirst;
|
||||
int smoothingGroupID;
|
||||
};
|
||||
|
||||
inline bool operator==(const ObjSmoothingGroup &v1, const ObjSmoothingGroup &v2)
|
||||
{
|
||||
return
|
||||
v1.vertexIdxFirst == v2.vertexIdxFirst &&
|
||||
v1.smoothingGroupID == v2.smoothingGroupID;
|
||||
}
|
||||
|
||||
struct ObjData {
|
||||
// Version of the data structure for load / store in the private binary format.
|
||||
int version;
|
||||
|
||||
// x, y, z, w
|
||||
std::vector<float> coordinates;
|
||||
// u, v, w
|
||||
std::vector<float> textureCoordinates;
|
||||
// x, y, z
|
||||
std::vector<float> normals;
|
||||
// u, v, w
|
||||
std::vector<float> parameters;
|
||||
|
||||
std::vector<std::string> mtllibs;
|
||||
std::vector<ObjUseMtl> usemtls;
|
||||
std::vector<ObjObject> objects;
|
||||
std::vector<ObjGroup> groups;
|
||||
std::vector<ObjSmoothingGroup> smoothingGroups;
|
||||
|
||||
// List of faces, delimited by an ObjVertex with all members set to -1.
|
||||
std::vector<ObjVertex> vertices;
|
||||
};
|
||||
|
||||
extern bool objparse(const char *path, ObjData &data);
|
||||
|
||||
extern bool objbinsave(const char *path, const ObjData &data);
|
||||
|
||||
extern bool objbinload(const char *path, ObjData &data);
|
||||
|
||||
extern bool objequal(const ObjData &data1, const ObjData &data2);
|
||||
|
||||
} // namespace ObjParser
|
||||
|
||||
#endif /* slic3r_Format_objparser_hpp_ */
|
Loading…
Add table
Add a link
Reference in a new issue