#include "../libslic3r.h" #include "../Model.hpp" #include "../TriangleMesh.hpp" #include "OBJ.hpp" #include "objparser.hpp" #include #include #ifdef _WIN32 #define DIR_SEPARATOR '\\' #else #define DIR_SEPARATOR '/' #endif namespace Slic3r { bool load_obj(const char *path, TriangleMesh *meshptr) { if (meshptr == nullptr) return false; // Parse the OBJ file. ObjParser::ObjData data; if (! ObjParser::objparse(path, data)) { BOOST_LOG_TRIVIAL(error) << "load_obj: failed to parse " << 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(); ++ i) { // Find the end of face. size_t j = i; for (; j < data.vertices.size() && data.vertices[j].coordIdx != -1; ++ j) ; if (size_t num_face_vertices = j - i; num_face_vertices > 0) { if (num_face_vertices > 4) { // Non-triangular and non-quad faces are not supported as of now. BOOST_LOG_TRIVIAL(error) << "load_obj: failed to parse " << path << ". The file contains polygons with more than 4 vertices."; return false; } else if (num_face_vertices < 3) { // Non-triangular and non-quad faces are not supported as of now. BOOST_LOG_TRIVIAL(error) << "load_obj: failed to parse " << path << ". The file contains polygons with less than 2 vertices."; return false; } if (num_face_vertices == 4) ++ num_quads; ++ num_faces; i = j; } } // Convert ObjData into indexed triangle set. indexed_triangle_set its; size_t num_vertices = data.coordinates.size() / 4; its.vertices.reserve(num_vertices); its.indices.reserve(num_faces + num_quads); for (size_t i = 0; i < num_vertices; ++ i) { size_t j = i << 2; its.vertices.emplace_back(data.coordinates[j], data.coordinates[j + 1], data.coordinates[j + 2]); } int indices[4]; for (size_t i = 0; i < data.vertices.size();) if (data.vertices[i].coordIdx == -1) ++ i; else { int cnt = 0; while (i < data.vertices.size()) if (const ObjParser::ObjVertex &vertex = data.vertices[i ++]; vertex.coordIdx == -1) { break; } else { assert(cnt < 4); if (vertex.coordIdx < 0 || vertex.coordIdx >= int(its.vertices.size())) { BOOST_LOG_TRIVIAL(error) << "load_obj: failed to parse " << path << ". The file contains invalid vertex index."; return false; } indices[cnt ++] = vertex.coordIdx; } if (cnt) { assert(cnt == 3 || cnt == 4); // Insert one or two faces (triangulate a quad). its.indices.emplace_back(indices[0], indices[1], indices[2]); if (cnt == 4) its.indices.emplace_back(indices[0], indices[2], indices[3]); } } *meshptr = TriangleMesh(std::move(its)); if (meshptr->empty()) { BOOST_LOG_TRIVIAL(error) << "load_obj: This OBJ file couldn't be read because it's empty. " << path; return false; } if (meshptr->volume() < 0) meshptr->flip_triangles(); return true; } bool load_obj(const char *path, Model *model, const char *object_name_in) { TriangleMesh mesh; bool ret = load_obj(path, &mesh); if (ret) { 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 ret; } bool store_obj(const char *path, TriangleMesh *mesh) { //FIXME returning false even if write failed. mesh->WriteOBJFile(path); return true; } bool store_obj(const char *path, ModelObject *model_object) { TriangleMesh mesh = model_object->mesh(); return store_obj(path, &mesh); } bool store_obj(const char *path, Model *model) { TriangleMesh mesh = model->mesh(); return store_obj(path, &mesh); } }; // namespace Slic3r