Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/libslic3r/Format/PRUS.cpp')
-rw-r--r--src/libslic3r/Format/PRUS.cpp399
1 files changed, 399 insertions, 0 deletions
diff --git a/src/libslic3r/Format/PRUS.cpp b/src/libslic3r/Format/PRUS.cpp
new file mode 100644
index 000000000..45eb56c63
--- /dev/null
+++ b/src/libslic3r/Format/PRUS.cpp
@@ -0,0 +1,399 @@
+#ifdef SLIC3R_PRUS
+
+#include <string.h>
+
+#include <boost/nowide/convert.hpp>
+
+#include <wx/string.h>
+#include <wx/wfstream.h>
+#include <wx/zipstrm.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 for the wxInputStream.
+class LineReader
+{
+public:
+ LineReader(wxInputStream &input_stream, const char *initial_data, int initial_len) :
+ m_input_stream(input_stream),
+ m_pos(0),
+ m_len(initial_len)
+ {
+ assert(initial_len >= 0 && initial_len < m_bufsize);
+ memcpy(m_buffer, initial_data, initial_len);
+ }
+
+ const char* next_line() {
+ for (;;) {
+ // 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) {
+ // Empty buffer, fill it from the input stream.
+ m_pos = 0;
+ m_input_stream.Read(m_buffer, m_bufsize - 1);
+ m_len = m_input_stream.LastRead();
+ assert(m_len >= 0 && m_len < m_bufsize);
+ if (m_len == 0)
+ // End of file.
+ return nullptr;
+ // Skip empty lines etc.
+ continue;
+ }
+ // 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;
+ if (end == m_len && ! m_input_stream.Eof() && m_len < m_bufsize) {
+ // Move the buffer content to the buffer start and fill the rest of the buffer.
+ assert(m_pos > 0);
+ memmove(m_buffer, m_buffer + m_pos, m_len - m_pos);
+ m_len -= m_pos;
+ assert(m_len >= 0 && m_len < m_bufsize);
+ m_pos = 0;
+ m_input_stream.Read(m_buffer + m_len, m_bufsize - 1 - m_len);
+ int new_data = m_input_stream.LastRead();
+ if (new_data > 0) {
+ m_len += new_data;
+ assert(m_len >= 0 && m_len < m_bufsize);
+ continue;
+ }
+ }
+ char *ptr_out = m_buffer + m_pos;
+ m_pos = end + 1;
+ m_buffer[end] = 0;
+ if (m_pos >= m_len) {
+ m_pos = 0;
+ m_len = 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:
+ wxInputStream &m_input_stream;
+ static const int m_bufsize = 4096;
+ char m_buffer[m_bufsize];
+ int m_pos = 0;
+ int m_len = 0;
+};
+
+// Load a PrusaControl project file into a provided model.
+bool load_prus(const char *path, Model *model)
+{
+ // To receive the content of the zipped 'scene.xml' file.
+ std::vector<char> scene_xml_data;
+ wxFFileInputStream in(
+#ifdef WIN32
+ // On Windows, convert to a 16bit unicode string.
+ boost::nowide::widen(path).c_str()
+#else
+ path
+#endif
+ );
+ wxZipInputStream zip(in);
+ std::unique_ptr<wxZipEntry> entry;
+ size_t num_models = 0;
+ std::map<int, ModelObject*> group_to_model_object;
+ while (entry.reset(zip.GetNextEntry()), entry.get() != NULL) {
+ wxString name = entry->GetName();
+ if (name == "scene.xml") {
+ if (! scene_xml_data.empty()) {
+ // scene.xml has been found more than once in the archive.
+ return false;
+ }
+ size_t size_last = 0;
+ size_t size_incr = 4096;
+ scene_xml_data.resize(size_incr);
+ while (! zip.Read(scene_xml_data.data() + size_last, size_incr).Eof()) {
+ size_last += zip.LastRead();
+ if (scene_xml_data.size() < size_last + size_incr)
+ scene_xml_data.resize(size_last + size_incr);
+ }
+ size_last += zip.LastRead();
+ if (scene_xml_data.size() == size_last)
+ scene_xml_data.resize(size_last + 1);
+ else if (scene_xml_data.size() > size_last + 1)
+ scene_xml_data.erase(scene_xml_data.begin() + size_last + 1, scene_xml_data.end());
+ scene_xml_data[size_last] = 0;
+ }
+ else if (name.EndsWith(".stl") || name.EndsWith(".STL")) {
+ // Find the model entry in the XML data.
+ const wxScopedCharBuffer name_utf8 = name.ToUTF8();
+ char model_name_tag[1024];
+ sprintf(model_name_tag, "<model name=\"%s\">", name_utf8.data());
+ 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 };
+ double instance_rotation = 0.;
+ double instance_scaling_factor = 1.f;
+#if ENABLE_MODELINSTANCE_3D_OFFSET
+ Vec3d instance_offset = Vec3d::Zero();
+#else
+ Vec2d instance_offset(0., 0.);
+#endif // ENABLE_MODELINSTANCE_3D_OFFSET
+ 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) {
+ if (scale[0] == scale[1] && scale[1] == scale[2]) {
+ instance_scaling_factor = scale[0];
+ scale[0] = scale[1] = scale[2] = 1.;
+ }
+ if (rotation[0] == 0. && rotation[1] == 0.) {
+ instance_rotation = - rotation[2];
+ rotation[2] = 0.;
+ }
+ 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);
+ }
+#if ENABLE_MODELINSTANCE_3D_OFFSET
+ instance_offset = Vec3d((double)(position[0] - zero[0]), (double)(position[1] - zero[1]), (double)(position[2] - zero[2]));
+#else
+ instance_offset(0) = position[0] - zero[0];
+ instance_offset(1) = position[1] - zero[1];
+#endif // ENABLE_MODELINSTANCE_3D_OFFSET
+ trafo[2][3] = position[2] / instance_scaling_factor;
+ 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) {
+ // Extract the STL.
+ StlHeader header;
+ TriangleMesh mesh;
+ bool mesh_valid = false;
+ bool stl_ascii = false;
+ if (!zip.Read((void*)&header, sizeof(StlHeader)).Eof()) {
+ 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 && zip.ReadAll((void*)stl.facet_start, 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(zip, (char*)&header, zip.LastRead());
+ 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 = facets.size();
+ stl.stats.original_num_facets = 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) {
+ // 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_utf8.data(), path, std::move(mesh));
+ volume = model_object->volumes.front();
+ ModelInstance *instance = model_object->add_instance();
+ instance->rotation = instance_rotation;
+ instance->scaling_factor = instance_scaling_factor;
+#if ENABLE_MODELINSTANCE_3D_OFFSET
+ instance->set_offset(instance_offset);
+#else
+ instance->offset = instance_offset;
+#endif // ENABLE_MODELINSTANCE_3D_OFFSET
+ ++num_models;
+ 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_utf8.data();
+ }
+ // 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);
+ }
+ }
+ }
+ }
+ }
+ return num_models > 0;
+}
+
+}; // namespace Slic3r
+
+#endif /* SLIC3R_PRUS */