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
path: root/src
diff options
context:
space:
mode:
authorVojtech Bubnik <bubnikv@gmail.com>2021-01-27 11:35:39 +0300
committerVojtech Bubnik <bubnikv@gmail.com>2021-01-27 11:35:39 +0300
commit05f9910c8fb94fd64ec4fb0b3bd8f9296891ac5c (patch)
tree38dd202ab1c0f2103e3da49bcdd509d583ccf7c7 /src
parent7a6c0384802b8f368048b36bba3e09b72ab9055f (diff)
Fixes after merge.
Diffstat (limited to 'src')
-rw-r--r--src/libslic3r/Format/3mf.cpp155
1 files changed, 120 insertions, 35 deletions
diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp
index 70b9d5e1b..200e6a490 100644
--- a/src/libslic3r/Format/3mf.cpp
+++ b/src/libslic3r/Format/3mf.cpp
@@ -21,6 +21,7 @@
#include <boost/filesystem/operations.hpp>
#include <boost/nowide/fstream.hpp>
#include <boost/nowide/cstdio.hpp>
+#include <boost/spirit/include/karma.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
@@ -31,6 +32,12 @@ namespace pt = boost::property_tree;
#include <Eigen/Dense>
#include "miniz_extension.hpp"
+// Slightly faster than sprintf("%.9g"), but there is an issue with the karma floating point formatter,
+// https://github.com/boostorg/spirit/pull/586
+// where the exported string is one digit shorter than it should be to guarantee lossless round trip.
+// The code is left here for the ocasion boost guys improve.
+#define EXPORT_3MF_USE_SPIRIT_KARMA_FP 0
+
// VERSION NUMBERS
// 0 : .3mf, files saved by older slic3r or other applications. No version definition in them.
// 1 : Introduction of 3mf versioning. No other change in data saved into 3mf files.
@@ -2030,7 +2037,7 @@ namespace Slic3r {
bool _add_relationships_file_to_archive(mz_zip_archive& archive);
bool _add_model_file_to_archive(const std::string& filename, mz_zip_archive& archive, const Model& model, IdToObjectDataMap& objects_data);
bool _add_object_to_model_stream(mz_zip_writer_staged_context &context, unsigned int& object_id, ModelObject& object, BuildItemsList& build_items, VolumeToOffsetsMap& volumes_offsets);
- bool _add_mesh_to_object_stream(mz_zip_writer_staged_context &context, std::stringstream& stream, ModelObject& object, VolumeToOffsetsMap& volumes_offsets);
+ bool _add_mesh_to_object_stream(mz_zip_writer_staged_context &context, ModelObject& object, VolumeToOffsetsMap& volumes_offsets);
bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items);
bool _add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model);
bool _add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model);
@@ -2360,7 +2367,10 @@ namespace Slic3r {
if (id == 0)
{
- if (!_add_mesh_to_object_stream(context, stream, object, volumes_offsets))
+ std::string buf = stream.str();
+ reset_stream(stream);
+ if ((! buf.empty() && ! mz_zip_writer_add_staged_data(&context, buf.data(), buf.size())) ||
+ ! _add_mesh_to_object_stream(context, object, volumes_offsets))
{
add_error("Unable to add mesh to archive");
return false;
@@ -2388,28 +2398,76 @@ namespace Slic3r {
return buf.empty() || mz_zip_writer_add_staged_data(&context, buf.data(), buf.size());
}
- bool _3MF_Exporter::_add_mesh_to_object_stream(mz_zip_writer_staged_context &context, std::stringstream& stream, ModelObject& object, VolumeToOffsetsMap& volumes_offsets)
+#if EXPORT_3MF_USE_SPIRIT_KARMA_FP
+ template <typename Num>
+ struct coordinate_policy_fixed : boost::spirit::karma::real_policies<Num>
{
- stream << " <" << MESH_TAG << ">\n";
- stream << " <" << VERTICES_TAG << ">\n";
-
- // Flush at the rate of 6400 lines per miniz invocation,
- // that corresponds to roughly 5x 64kB blocks.
- size_t lines = 6400;
- auto flush = [this, &lines, &context, &stream]() {
- if (lines == 0) {
- lines = 6400;
- std::string buf = stream.str();
- reset_stream(stream);
- if (! buf.empty() && ! mz_zip_writer_add_staged_data(&context, buf.data(), buf.size())) {
+ static int floatfield(Num n) { return fmtflags::fixed; }
+ // Number of decimal digits to maintain float accuracy when storing into a text file and parsing back.
+ static unsigned precision(Num /* n */) { return std::numeric_limits<Num>::max_digits10 + 1; }
+ // No trailing zeros, thus for fmtflags::fixed usually much less than max_digits10 decimal numbers will be produced.
+ static bool trailing_zeros(Num /* n */) { return false; }
+ };
+ template <typename Num>
+ struct coordinate_policy_scientific : coordinate_policy_fixed<Num>
+ {
+ static int floatfield(Num n) { return fmtflags::scientific; }
+ };
+ // Define a new generator type based on the new coordinate policy.
+ using coordinate_type_fixed = boost::spirit::karma::real_generator<float, coordinate_policy_fixed<float>>;
+ using coordinate_type_scientific = boost::spirit::karma::real_generator<float, coordinate_policy_scientific<float>>;
+#endif // EXPORT_3MF_USE_SPIRIT_KARMA_FP
+
+ bool _3MF_Exporter::_add_mesh_to_object_stream(mz_zip_writer_staged_context &context, ModelObject& object, VolumeToOffsetsMap& volumes_offsets)
+ {
+ std::string output_buffer;
+ output_buffer += " <";
+ output_buffer += MESH_TAG;
+ output_buffer += ">\n <";
+ output_buffer += VERTICES_TAG;
+ output_buffer += ">\n";
+
+ auto flush = [this, &output_buffer, &context](bool force = false) {
+ if ((force && ! output_buffer.empty()) || output_buffer.size() >= 65536 * 16) {
+ if (! mz_zip_writer_add_staged_data(&context, output_buffer.data(), output_buffer.size())) {
add_error("Error during writing or compression");
return false;
}
- } else
- -- lines;
+ output_buffer.clear();
+ }
return true;
};
+ auto format_coordinate = [](float f, char *buf) -> char* {
+#if EXPORT_3MF_USE_SPIRIT_KARMA_FP
+ // Slightly faster than sprintf("%.9g"), but there is an issue with the karma floating point formatter,
+ // https://github.com/boostorg/spirit/pull/586
+ // where the exported string is one digit shorter than it should be to guarantee lossless round trip.
+ // The code is left here for the ocasion boost guys improve.
+ coordinate_type_fixed const coordinate_fixed = coordinate_type_fixed();
+ coordinate_type_scientific const coordinate_scientific = coordinate_type_scientific();
+ // Format "f" in a fixed format.
+ char *ptr = buf;
+ boost::spirit::karma::generate(ptr, coordinate_fixed, f);
+ // Format "f" in a scientific format.
+ char *ptr2 = ptr;
+ boost::spirit::karma::generate(ptr2, coordinate_scientific, f);
+ // Return end of the shorter string.
+ auto len2 = ptr2 - ptr;
+ if (ptr - buf > len2) {
+ // Move the shorter scientific form to the front.
+ memcpy(buf, ptr, len2);
+ ptr = buf + len2;
+ }
+ // Return pointer to the end.
+ return ptr;
+#else
+ // Round-trippable float, shortest possible.
+ return buf + sprintf(buf, "%.9g", f);
+#endif
+ };
+
+ char buf[256];
unsigned int vertices_count = 0;
for (ModelVolume* volume : object.volumes)
{
@@ -2436,18 +2494,27 @@ namespace Slic3r {
for (size_t i = 0; i < its.vertices.size(); ++i)
{
- stream << " <" << VERTEX_TAG << " ";
Vec3f v = (matrix * its.vertices[i].cast<double>()).cast<float>();
- stream << "x=\"" << v(0) << "\" ";
- stream << "y=\"" << v(1) << "\" ";
- stream << "z=\"" << v(2) << "\" />\n";
+ char *ptr = buf;
+ boost::spirit::karma::generate(ptr, boost::spirit::lit(" <") << VERTEX_TAG << " x=\"");
+ ptr = format_coordinate(v.x(), ptr);
+ boost::spirit::karma::generate(ptr, "\" y=\"");
+ ptr = format_coordinate(v.y(), ptr);
+ boost::spirit::karma::generate(ptr, "\" z=\"");
+ ptr = format_coordinate(v.z(), ptr);
+ boost::spirit::karma::generate(ptr, "\" />\n");
+ *ptr = '\0';
+ output_buffer += buf;
if (! flush())
return false;
}
}
- stream << " </" << VERTICES_TAG << ">\n";
- stream << " <" << TRIANGLES_TAG << ">\n";
+ output_buffer += " </";
+ output_buffer += VERTICES_TAG;
+ output_buffer += ">\n <";
+ output_buffer += TRIANGLES_TAG;
+ output_buffer += ">\n";
unsigned int triangles_count = 0;
for (ModelVolume* volume : object.volumes)
@@ -2467,33 +2534,51 @@ namespace Slic3r {
for (int i = 0; i < int(its.indices.size()); ++ i)
{
- stream << " <" << TRIANGLE_TAG << " ";
- for (int j = 0; j < 3; ++j)
{
- stream << "v" << j + 1 << "=\"" << its.indices[i][j] + volume_it->second.first_vertex_id << "\" ";
+ const Vec3i &idx = its.indices[i];
+ char *ptr = buf;
+ boost::spirit::karma::generate(ptr, boost::spirit::lit(" <") << TRIANGLE_TAG <<
+ " v1=\"" << boost::spirit::int_ <<
+ "\" v2=\"" << boost::spirit::int_ <<
+ "\" v3=\"" << boost::spirit::int_ << "\" ",
+ idx[0] + volume_it->second.first_vertex_id,
+ idx[1] + volume_it->second.first_vertex_id,
+ idx[2] + volume_it->second.first_vertex_id);
+ *ptr = '\0';
+ output_buffer += buf;
}
std::string custom_supports_data_string = volume->supported_facets.get_triangle_as_string(i);
- if (! custom_supports_data_string.empty())
- stream << CUSTOM_SUPPORTS_ATTR << "=\"" << custom_supports_data_string << "\" ";
+ if (! custom_supports_data_string.empty()) {
+ output_buffer += CUSTOM_SUPPORTS_ATTR;
+ output_buffer += "=\"";
+ output_buffer += custom_supports_data_string;
+ output_buffer += "\" ";
+ }
std::string custom_seam_data_string = volume->seam_facets.get_triangle_as_string(i);
- if (! custom_seam_data_string.empty())
- stream << CUSTOM_SEAM_ATTR << "=\"" << custom_seam_data_string << "\" ";
+ if (! custom_seam_data_string.empty()) {
+ output_buffer += CUSTOM_SEAM_ATTR;
+ output_buffer += "=\"";
+ output_buffer += custom_seam_data_string;
+ output_buffer += "\" ";
+ }
- stream << "/>\n";
+ output_buffer += "/>\n";
if (! flush())
return false;
}
}
- stream << " </" << TRIANGLES_TAG << ">\n";
- stream << " </" << MESH_TAG << ">\n";
+ output_buffer += " </";
+ output_buffer += TRIANGLES_TAG;
+ output_buffer += ">\n </";
+ output_buffer += MESH_TAG;
+ output_buffer += ">\n";
// Force flush.
- lines = 0;
- return flush();
+ return flush(true);
}
bool _3MF_Exporter::_add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items)