diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 098131e008..c551b22898 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -56,9 +56,11 @@ set(SLIC3R_SOURCES ElephantFootCompensation.hpp Emboss.cpp Emboss.hpp + EmbossShape.hpp enum_bitmask.hpp ExPolygon.cpp ExPolygon.hpp + ExPolygonSerialize.hpp ExPolygonsIndex.cpp ExPolygonsIndex.hpp Extruder.cpp diff --git a/src/libslic3r/EmbossShape.hpp b/src/libslic3r/EmbossShape.hpp new file mode 100644 index 0000000000..bbb37d39a7 --- /dev/null +++ b/src/libslic3r/EmbossShape.hpp @@ -0,0 +1,64 @@ +#ifndef slic3r_EmbossShape_hpp_ +#define slic3r_EmbossShape_hpp_ + +#include +#include +#include +#include +#include +#include "Point.hpp" // Transform3d +#include "ExPolygon.hpp" +#include "ExPolygonSerialize.hpp" + +namespace Slic3r { + +/// +/// Contain plane shape information to be able emboss it and edit it +/// +struct EmbossShape +{ + // shape defined by integer point consist only by lines not curves + ExPolygons shape; + + // scale of shape, multiplier to get 3d point in mm from integer shape + double shape_scale; + + // Emboss depth + double depth; // [in world mm] + + // Flag that result volume use surface cutted from source objects + bool use_surface = false; + + // distance from surface point + // used for move over model surface + // When not set value is zero and is not stored + std::optional distance; // [in mm] + + // !!! Volume stored in .3mf has transformed vertices. + // (baked transformation into vertices position) + // Only place for fill this is when load from .3mf + // This is correction for volume transformation + // Stored_Transform3d * fix_3mf_tr = Transform3d_before_store_to_3mf + std::optional fix_3mf_tr; + + // file(.svg) path to source of shape + std::string svg_file_path; + + // undo / redo stack recovery + template void save(Archive &ar) const + { + ar(shape, shape_scale, depth, use_surface, svg_file_path); + cereal::save(ar, distance); + cereal::save(ar, fix_3mf_tr); + } + template void load(Archive &ar) + { + ar(shape, shape_scale, depth, use_surface, svg_file_path); + cereal::load(ar, distance); + cereal::load(ar, fix_3mf_tr); + } +}; + +} // namespace Slic3r + +#endif // slic3r_EmbossShape_hpp_ diff --git a/src/libslic3r/ExPolygonSerialize.hpp b/src/libslic3r/ExPolygonSerialize.hpp new file mode 100644 index 0000000000..712d4706d5 --- /dev/null +++ b/src/libslic3r/ExPolygonSerialize.hpp @@ -0,0 +1,28 @@ +#ifndef slic3r_ExPolygonSerialize_hpp_ +#define slic3r_ExPolygonSerialize_hpp_ + +#include "ExPolygon.hpp" +#include "Point.hpp" // Cereal serialization of Point +#include +#include + +/// +/// External Cereal serialization of ExPolygons +/// + +// Serialization through the Cereal library +#include +namespace cereal { + +template +void serialize(Archive &archive, Slic3r::Polygon &polygon) { + archive(polygon.points); +} + +template +void serialize(Archive &archive, Slic3r::ExPolygon &expoly) { + archive(expoly.contour, expoly.holes); +} + +} // namespace Slic3r +#endif // slic3r_ExPolygonSerialize_hpp_ diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 08fa794810..5056ccf696 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -15,6 +15,7 @@ #include "CustomGCode.hpp" #include "enum_bitmask.hpp" #include "TextConfiguration.hpp" +#include "EmbossShape.hpp" #include #include @@ -824,6 +825,10 @@ public: // Contain information how to re-create volume std::optional text_configuration; + // Is set only when volume is Embossed Shape + // Contain 2d information about embossed shape to be editabled + std::optional emboss_shape; + // A parent object owning this modifier volume. ModelObject* get_object() const { return this->object; } ModelVolumeType type() const { return m_type; } @@ -1011,8 +1016,7 @@ private: name(other.name), source(other.source), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation), supported_facets(other.supported_facets), seam_facets(other.seam_facets), mmu_segmentation_facets(other.mmu_segmentation_facets), - cut_info(other.cut_info), - text_configuration(other.text_configuration) + cut_info(other.cut_info), text_configuration(other.text_configuration), emboss_shape(other.emboss_shape) { assert(this->id().valid()); assert(this->config.id().valid()); @@ -1033,8 +1037,7 @@ private: // Providing a new mesh, therefore this volume will get a new unique ID assigned. ModelVolume(ModelObject *object, const ModelVolume &other, TriangleMesh &&mesh) : name(other.name), source(other.source), config(other.config), object(object), m_mesh(new TriangleMesh(std::move(mesh))), m_type(other.m_type), m_transformation(other.m_transformation), - cut_info(other.cut_info), - text_configuration(other.text_configuration) + cut_info(other.cut_info), text_configuration(other.text_configuration), emboss_shape(other.emboss_shape) { assert(this->id().valid()); assert(this->config.id().valid()); @@ -1082,6 +1085,7 @@ private: cereal::load_by_value(ar, mmu_segmentation_facets); cereal::load_by_value(ar, config); cereal::load(ar, text_configuration); + cereal::load(ar, emboss_shape); assert(m_mesh); if (has_convex_hull) { cereal::load_optional(ar, m_convex_hull); @@ -1099,6 +1103,7 @@ private: cereal::save_by_value(ar, mmu_segmentation_facets); cereal::save_by_value(ar, config); cereal::save(ar, text_configuration); + cereal::save(ar, emboss_shape); if (has_convex_hull) cereal::save_optional(ar, m_convex_hull); } diff --git a/tests/libslic3r/test_emboss.cpp b/tests/libslic3r/test_emboss.cpp index 2d98b1d4d4..90eaa01447 100644 --- a/tests/libslic3r/test_emboss.cpp +++ b/tests/libslic3r/test_emboss.cpp @@ -491,7 +491,7 @@ TEST_CASE("Cut surface", "[]") #include #include #include -TEST_CASE("UndoRedo serialization", "[Emboss]") +TEST_CASE("UndoRedo TextConfiguration serialization", "[Emboss]") { TextConfiguration tc; tc.text = "Dovede-li se člověk zasmát sám sobě, nevyjde ze smíchu po celý život."; @@ -523,6 +523,39 @@ TEST_CASE("UndoRedo serialization", "[Emboss]") CHECK(tc.fix_3mf_tr.has_value() == tc_loaded.fix_3mf_tr.has_value()); } +#include "libslic3r/EmbossShape.hpp" +TEST_CASE("UndoRedo EmbossShape serialization", "[Emboss]") +{ + EmbossShape emboss; + emboss.shape = {{{0, 0}, {10, 0}, {10, 10}, {0, 10}}, {{5, 5}, {6, 5}, {6, 6}, {5, 6}}}; + emboss.shape_scale = 2.; + emboss.depth = 5.; + emboss.use_surface = true; + emboss.distance = 3.f; + emboss.fix_3mf_tr = Transform3d::Identity(); + emboss.svg_file_path = "Everything starts somewhere, though many physicists disagree.\ + But people have always been dimly aware of the problem with the start of things.\ + They wonder how the snowplough driver gets to work,\ + or how the makers of dictionaries look up the spelling of words."; + std::stringstream ss; // any stream can be used + { + cereal::BinaryOutputArchive oarchive(ss); // Create an output archive + + oarchive(emboss); + } // archive goes out of scope, ensuring all contents are flushed + + EmbossShape emboss_loaded; + { + cereal::BinaryInputArchive iarchive(ss); // Create an input archive + iarchive(emboss_loaded); + } + CHECK(emboss.shape == emboss_loaded.shape); + CHECK(emboss.shape_scale == emboss_loaded.shape_scale); + CHECK(emboss.depth == emboss_loaded.depth); + CHECK(emboss.use_surface == emboss_loaded.use_surface); + CHECK(emboss.distance == emboss_loaded.distance); +} + #include #include diff --git a/tests/libslic3r/test_expolygon.cpp b/tests/libslic3r/test_expolygon.cpp index 63d763e2f6..3810af5ed5 100644 --- a/tests/libslic3r/test_expolygon.cpp +++ b/tests/libslic3r/test_expolygon.cpp @@ -65,3 +65,32 @@ SCENARIO("Basics", "[ExPolygon]") { } } } + +#include +#include +#include +#include "libslic3r/ExPolygonSerialize.hpp" +TEST_CASE("Serialization of expolygons", "[ExPolygon, Cereal, serialization]") +{ + ExPolygons expolys{{ + // expolygon 1 - without holes + {{0,0}, {10,0}, {10,10}, {0,10}}, // contour + // expolygon 2 - with rect 1px hole + {{{0,0}, {10,0}, {10,10}, {0,10}}, + {{5, 5}, {6, 5}, {6, 6}, {5, 6}}} + }}; + + std::stringstream ss; // any stream can be used + { + cereal::BinaryOutputArchive oarchive(ss); // Create an output archive + oarchive(expolys); + } // archive goes out of scope, ensuring all contents are flushed + + ExPolygons expolys_loaded; + { + cereal::BinaryInputArchive iarchive(ss); // Create an input archive + iarchive(expolys_loaded); + } + + CHECK(expolys == expolys_loaded); +}