diff --git a/src/libslic3r/EmbossShape.hpp b/src/libslic3r/EmbossShape.hpp index 0946235d87..1dccb58c65 100644 --- a/src/libslic3r/EmbossShape.hpp +++ b/src/libslic3r/EmbossShape.hpp @@ -2,6 +2,7 @@ #define slic3r_EmbossShape_hpp_ #include +#include #include #include #include @@ -12,6 +13,39 @@ namespace Slic3r { +struct EmbossProjection +{ + // Emboss depth, Size in local Z direction + double depth = 1.; // [in loacal mm] + // NOTE: User should see and modify mainly world size not local + + // Flag that result volume use surface cutted from source objects + bool use_surface = false; + + // enum class Align { + // left, + // right, + // center, + // top_left, + // top_right, + // top_center, + // bottom_left, + // bottom_right, + // bottom_center + // }; + //// change pivot of volume + //// When not set, center is used and is not stored + // std::optional align; + + // compare TextStyle + bool operator==(const EmbossProjection &other) const { + return depth == other.depth && use_surface == other.use_surface; + } + + // undo / redo stack recovery + template void serialize(Archive &ar) { ar(depth, use_surface); } +}; + /// /// Contain plane shape information to be able emboss it and edit it /// @@ -22,19 +56,9 @@ struct EmbossShape // scale of shape, multiplier to get 3d point in mm from integer shape double scale = 1.; - - // Emboss depth, Size in local Z direction - double depth = 1.; // [in loacal mm] - // NOTE: User should see and modify mainly world size not local - // 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 - // NOTE: Can't be used together with use_surface - std::optional distance; // [in mm] + // Define how to emboss shape + EmbossProjection projection; // !!! Volume stored in .3mf has transformed vertices. // (baked transformation into vertices position) @@ -50,14 +74,12 @@ struct EmbossShape // undo / redo stack recovery template void save(Archive &ar) const { - ar(shapes, scale, depth, use_surface, svg_file_path); - cereal::save(ar, distance); + ar(shapes, scale, projection, svg_file_path); cereal::save(ar, fix_3mf_tr); } template void load(Archive &ar) { - ar(shapes, scale, depth, use_surface, svg_file_path); - cereal::load(ar, distance); + ar(shapes, scale, projection, svg_file_path); cereal::load(ar, fix_3mf_tr); } }; diff --git a/src/libslic3r/TextConfiguration.hpp b/src/libslic3r/TextConfiguration.hpp index 1c1ce77567..ef1df301ba 100644 --- a/src/libslic3r/TextConfiguration.hpp +++ b/src/libslic3r/TextConfiguration.hpp @@ -26,15 +26,6 @@ struct FontProp // When not set value is zero and is not stored std::optional line_gap; // [in font point] - // Z depth of text - float emboss; // [in mm] - - // Flag that text should use surface cutted from object - // FontProp::distance should without value - // FontProp::emboss should be positive number - // Note: default value is false - bool use_surface; - // positive value mean wider character shape // negative value mean tiner character shape // When not set value is zero and is not stored @@ -45,35 +36,21 @@ struct FontProp // When not set value is zero and is not stored std::optional skew; // [ration x:y] - // 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] - - // Angle of rotation around emboss direction (Z axis) - // It is calculate on the fly from volume world transformation - // only StyleManager keep actual value for comparision with style - // When not set value is zero and is not stored - std::optional angle; // [in radians] form -Pi to Pi - // Parameter for True Type Font collections // Select index of font in collection std::optional collection_number; - //enum class Align { - // left, - // right, - // center, - // top_left, - // top_right, - // top_center, - // bottom_left, - // bottom_right, - // bottom_center - //}; - //// change pivot of text - //// When not set, center is used and is not stored - //std::optional align; + [[deprecated("Back compatibility only, now it is stored EmbossProjection like depth")]] + float emboss; + + [[deprecated("Back compatibility only, now it is stored EmbossProjection")]] + bool use_surface; + + [[deprecated("it is calculated on the fly")]] + std::optional distance; + + [[deprecated("it is calculated on the fly")]] + std::optional angle; ////// // Duplicit data to wxFontDescriptor @@ -104,45 +81,29 @@ struct FontProp return char_gap == other.char_gap && line_gap == other.line_gap && - use_surface == other.use_surface && - is_approx(emboss, other.emboss) && is_approx(size_in_mm, other.size_in_mm) && is_approx(boldness, other.boldness) && - is_approx(skew, other.skew) && - is_approx(distance, other.distance) && - is_approx(angle, other.angle); + is_approx(skew, other.skew); } // undo / redo stack recovery template void save(Archive &ar) const { - ar(emboss, use_surface, size_in_mm); + ar(size_in_mm); cereal::save(ar, char_gap); cereal::save(ar, line_gap); cereal::save(ar, boldness); cereal::save(ar, skew); - cereal::save(ar, distance); - cereal::save(ar, angle); cereal::save(ar, collection_number); - cereal::save(ar, family); - cereal::save(ar, face_name); - cereal::save(ar, style); - cereal::save(ar, weight); } template void load(Archive &ar) { - ar(emboss, use_surface, size_in_mm); + ar(size_in_mm); cereal::load(ar, char_gap); cereal::load(ar, line_gap); cereal::load(ar, boldness); cereal::load(ar, skew); - cereal::load(ar, distance); - cereal::load(ar, angle); cereal::load(ar, collection_number); - cereal::load(ar, family); - cereal::load(ar, face_name); - cereal::load(ar, style); - cereal::load(ar, weight); } }; @@ -196,9 +157,7 @@ struct EmbossStyle } // undo / redo stack recovery - template void serialize(Archive &ar){ - ar(name, path, type, prop); - } + template void serialize(Archive &ar){ ar(name, path, type, prop); } }; // Emboss style name inside vector is unique @@ -219,21 +178,11 @@ struct TextConfiguration // Embossed text value std::string text = "None"; - // !!! Volume stored in .3mf has transformed vertices. - // (baked transformation into vertices position) - // Only place for fill this is when load from .3mf - // This is correct volume transformation + [[deprecated("only for back compatibility, now it is stored in EmbossShape")]] std::optional fix_3mf_tr; // undo / redo stack recovery - template void save(Archive &ar) const{ - ar(text, style); - cereal::save(ar, fix_3mf_tr); - } - template void load(Archive &ar){ - ar(text, style); - cereal::load(ar, fix_3mf_tr); - } + template void serialize(Archive &ar) { ar(style, text); } }; } // namespace Slic3r diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 6db1456e3d..d252462a6c 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -258,8 +258,6 @@ set(SLIC3R_GUI_SOURCES Utils/Duet.hpp Utils/EmbossStyleManager.cpp Utils/EmbossStyleManager.hpp - Utils/EmbossStylesSerializable.cpp - Utils/EmbossStylesSerializable.hpp Utils/FlashAir.cpp Utils/FlashAir.hpp Utils/FontConfigHelp.cpp diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp index 9753fec088..c1671db2d7 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.cpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp @@ -291,12 +291,9 @@ void CreateObjectJob::process(Ctl &ctl) if (!check(m_input)) throw JobException("Bad input data for EmbossCreateObjectJob."); - if (m_input.base->shape.distance.has_value()) - m_input.base->shape.distance.reset(); - // can't create new object with using surface - if (m_input.base->shape.use_surface) - m_input.base->shape.use_surface = false; + if (m_input.base->shape.projection.use_surface) + m_input.base->shape.projection.use_surface = false; auto was_canceled = ::was_canceled(ctl, *m_input.base); m_result = create_mesh(*m_input.base, was_canceled, ctl); @@ -319,7 +316,7 @@ void CreateObjectJob::process(Ctl &ctl) bed_coor = bed.centroid().cast(); // TODO: need TextConfiguration refactor to work !!! - double z = m_input.base->shape.depth / 2; + double z = m_input.base->shape.projection.depth / 2; Vec3d offset(bed_coor.x(), bed_coor.y(), z); offset -= m_result.center(); @@ -658,6 +655,8 @@ bool check(const DataCreateVolume &input, bool is_main_thread) assert(input.volume_type != ModelVolumeType::INVALID); res &= input.volume_type != ModelVolumeType::INVALID; res &= check(input.gizmo); + assert(!input.base->shape.projection.use_surface); + res &= !input.base->shape.projection.use_surface; return res; } bool check(const DataCreateObject &input) @@ -673,6 +672,8 @@ bool check(const DataCreateObject &input) assert(input.bed_shape.size() >= 3); // at least triangle res &= input.bed_shape.size() >= 3; res &= check(input.gizmo); + assert(!input.base->shape.projection.use_surface); + res &= !input.base->shape.projection.use_surface; return res; } bool check(const DataUpdate &input, bool is_main_thread, bool use_surface) @@ -687,6 +688,8 @@ bool check(const DataUpdate &input, bool is_main_thread, bool use_surface) res &= input.base->cancel != nullptr; if (is_main_thread) assert(!input.base->cancel->load()); + assert(!input.base->shape.projection.use_surface); + res &= !input.base->shape.projection.use_surface; return res; } bool check(const CreateSurfaceVolumeData &input, bool is_main_thread) @@ -698,6 +701,8 @@ bool check(const CreateSurfaceVolumeData &input, bool is_main_thread) assert(!input.sources.empty()); res &= !input.sources.empty(); res &= check(input.gizmo); + assert(input.base->shape.projection.use_surface); + res &= input.base->shape.projection.use_surface; return res; } bool check(const UpdateSurfaceVolumeData &input, bool is_main_thread) @@ -708,6 +713,8 @@ bool check(const UpdateSurfaceVolumeData &input, bool is_main_thread) res &= check(*input.base, is_main_thread, use_surface); assert(!input.sources.empty()); res &= !input.sources.empty(); + assert(input.base->shape.projection.use_surface); + res &= input.base->shape.projection.use_surface; return res; } @@ -716,7 +723,7 @@ template TriangleMesh try_create_mesh(DataBase &base, const Fnc &w const EmbossShape &shape = base.create_shape(); if (shape.shapes.empty()) return {}; - double depth = shape.depth / shape.scale; + double depth = shape.projection.depth / shape.scale; auto projectZ = std::make_unique(depth); ProjectScale project(std::move(projectZ), shape.scale); if (was_canceled()) @@ -887,7 +894,7 @@ void create_volume(TriangleMesh &&mesh, if (trmat.has_value()) { volume->set_transformation(*trmat); } else { - assert(!data.shape.use_surface); + assert(!data.shape.projection.use_surface); // Create transformation for volume near from object(defined by glVolume) // Transformation is inspired add generic volumes in ObjectList::load_generic_subobject Vec3d volume_size = volume->mesh().bounding_box().size(); @@ -1064,7 +1071,7 @@ template TriangleMesh cut_surface(DataBase &base, const SurfaceVol return {}; // !! Projection needs to transform cut - OrthoProject3d projection = create_emboss_projection(input2.is_outside, static_cast(emboss_shape.depth), emboss_tr, cut); + OrthoProject3d projection = create_emboss_projection(input2.is_outside, static_cast(emboss_shape.projection.depth), emboss_tr, cut); indexed_triangle_set new_its = cut2model(cut, projection); assert(!new_its.empty()); if (was_canceled()) @@ -1132,7 +1139,7 @@ bool start_create_volume_job(Worker &worker, ModelVolumeType volume_type, GLGizmosManager::EType gizmo) { - bool &use_surface = data->shape.use_surface; + bool &use_surface = data->shape.projection.use_surface; std::unique_ptr job; if (use_surface) { // Model to cut surface from. @@ -1211,8 +1218,8 @@ bool start_create_volume_on_surface_job(CreateVolumeParams &input, DataBasePtr d // soo create transfomation on border of object // there is no point on surface so no use of surface will be applied - if (data_->shape.use_surface) - data_->shape.use_surface = false; + if (data_->shape.projection.use_surface) + data_->shape.projection.use_surface = false; if (object == nullptr) return false; diff --git a/src/slic3r/GUI/Jobs/EmbossJob.hpp b/src/slic3r/GUI/Jobs/EmbossJob.hpp index ae281c12b4..173eec399e 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.hpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.hpp @@ -168,7 +168,6 @@ SurfaceVolumeData::ModelSources create_volume_sources(const ModelVolume &volume) /// struct CreateVolumeParams { - GLCanvas3D &canvas; // Direction of ray into scene diff --git a/src/slic3r/Utils/EmbossStyleManager.cpp b/src/slic3r/Utils/EmbossStyleManager.cpp index 5740ac13aa..32e003c6d7 100644 --- a/src/slic3r/Utils/EmbossStyleManager.cpp +++ b/src/slic3r/Utils/EmbossStyleManager.cpp @@ -1,15 +1,15 @@ #include "EmbossStyleManager.hpp" +#include #include // Imgui texture #include // ImTextCharFromUtf8 -#include "WxFontUtils.hpp" -#include "libslic3r/Utils.hpp" // ScopeGuard +#include +#include // ScopeGuard +#include "WxFontUtils.hpp" #include "slic3r/GUI/3DScene.hpp" // ::glsafe #include "slic3r/GUI/Jobs/CreateFontStyleImagesJob.hpp" #include "slic3r/GUI/ImGuiWrapper.hpp" // check of font ranges -#include "slic3r/Utils/EmbossStylesSerializable.hpp" - using namespace Slic3r; using namespace Slic3r::Emboss; using namespace Slic3r::GUI::Emboss; @@ -28,11 +28,22 @@ StyleManager::~StyleManager() { free_style_images(); } +/// +/// For store/load emboss style to/from AppConfig +/// +namespace { +void store_style_index(AppConfig &cfg, unsigned index); +::std::optional load_style_index(const AppConfig &cfg); + +EmbossStyles load_styles(const AppConfig &cfg); +void store_styles(AppConfig &cfg, const EmbossStyles &styles); +} // namespace + void StyleManager::init(AppConfig *app_config) { m_app_config = app_config; EmbossStyles styles = (app_config != nullptr) ? - EmbossStylesSerializable::load_styles(*app_config) : + ::load_styles(*app_config) : EmbossStyles{}; if (styles.empty()) styles = m_create_default_styles(); @@ -42,7 +53,7 @@ void StyleManager::init(AppConfig *app_config) } std::optional active_index_opt = (app_config != nullptr) ? - EmbossStylesSerializable::load_style_index(*app_config) : + ::load_style_index(*app_config) : std::optional{}; size_t active_index = 0; @@ -83,13 +94,13 @@ bool StyleManager::store_styles_to_app_config(bool use_modification, bool store_ size_t style_index = exist_stored_style() ? m_style_cache.style_index : m_last_style_index; - EmbossStylesSerializable::store_style_index(*m_app_config, style_index); + store_style_index(*m_app_config, style_index); } EmbossStyles styles; styles.reserve(m_style_items.size()); for (const Item &item : m_style_items) styles.push_back(item.style); - EmbossStylesSerializable::store_styles(*m_app_config, styles); + store_styles(*m_app_config, styles); return true; } @@ -542,3 +553,229 @@ bool StyleManager::set_wx_font(const wxFont &wx_font, std::unique_ptr clear_imgui_font(); return true; } + +#include +#include "WxFontUtils.hpp" +#include "fast_float/fast_float.h" + +// StylesSerializable +namespace { + +using namespace Slic3r; +using namespace Slic3r::GUI; +using Section = std::map; + +const std::string APP_CONFIG_FONT_NAME = "name"; +const std::string APP_CONFIG_FONT_DESCRIPTOR = "descriptor"; +const std::string APP_CONFIG_FONT_LINE_HEIGHT = "line_height"; +const std::string APP_CONFIG_FONT_DEPTH = "depth"; +const std::string APP_CONFIG_FONT_USE_SURFACE = "use_surface"; +const std::string APP_CONFIG_FONT_BOLDNESS = "boldness"; +const std::string APP_CONFIG_FONT_SKEW = "skew"; +const std::string APP_CONFIG_FONT_DISTANCE = "distance"; +const std::string APP_CONFIG_FONT_ANGLE = "angle"; +const std::string APP_CONFIG_FONT_COLLECTION = "collection"; +const std::string APP_CONFIG_FONT_CHAR_GAP = "char_gap"; +const std::string APP_CONFIG_FONT_LINE_GAP = "line_gap"; + +const std::string APP_CONFIG_ACTIVE_FONT = "active_font"; + +std::string create_section_name(unsigned index) +{ + return AppConfig::SECTION_EMBOSS_STYLE + ':' + std::to_string(index); +} + +// check only existence of flag +bool read(const Section §ion, const std::string &key, bool &value) +{ + auto item = section.find(key); + if (item == section.end()) + return false; + + value = true; + return true; +} + +bool read(const Section §ion, const std::string &key, float &value) +{ + auto item = section.find(key); + if (item == section.end()) + return false; + const std::string &data = item->second; + if (data.empty()) + return false; + float value_; + fast_float::from_chars(data.c_str(), data.c_str() + data.length(), value_); + // read only non zero value + if (fabs(value_) <= std::numeric_limits::epsilon()) + return false; + + value = value_; + return true; +} + +bool read(const Section §ion, const std::string &key, std::optional &value) +{ + auto item = section.find(key); + if (item == section.end()) + return false; + const std::string &data = item->second; + if (data.empty()) + return false; + int value_ = std::atoi(data.c_str()); + if (value_ == 0) + return false; + + value = value_; + return true; +} + +bool read(const Section §ion, const std::string &key, std::optional &value) +{ + auto item = section.find(key); + if (item == section.end()) + return false; + const std::string &data = item->second; + if (data.empty()) + return false; + int value_ = std::atoi(data.c_str()); + if (value_ <= 0) + return false; + + value = static_cast(value_); + return true; +} + +bool read(const Section §ion, const std::string &key, std::optional &value) +{ + auto item = section.find(key); + if (item == section.end()) + return false; + const std::string &data = item->second; + if (data.empty()) + return false; + float value_; + fast_float::from_chars(data.c_str(), data.c_str() + data.length(), value_); + // read only non zero value + if (fabs(value_) <= std::numeric_limits::epsilon()) + return false; + + value = value_; + return true; +} + +std::optional load_style(const Section &app_cfg_section) +{ + auto path_it = app_cfg_section.find(APP_CONFIG_FONT_DESCRIPTOR); + if (path_it == app_cfg_section.end()) + return {}; + const std::string &path = path_it->second; + + auto name_it = app_cfg_section.find(APP_CONFIG_FONT_NAME); + const std::string default_name = "font_name"; + const std::string &name = (name_it == app_cfg_section.end()) ? default_name : name_it->second; + + FontProp fp; + read(app_cfg_section, APP_CONFIG_FONT_LINE_HEIGHT, fp.size_in_mm); + read(app_cfg_section, APP_CONFIG_FONT_DEPTH, fp.emboss); + read(app_cfg_section, APP_CONFIG_FONT_USE_SURFACE, fp.use_surface); + read(app_cfg_section, APP_CONFIG_FONT_BOLDNESS, fp.boldness); + read(app_cfg_section, APP_CONFIG_FONT_SKEW, fp.skew); + read(app_cfg_section, APP_CONFIG_FONT_DISTANCE, fp.distance); + read(app_cfg_section, APP_CONFIG_FONT_ANGLE, fp.angle); + read(app_cfg_section, APP_CONFIG_FONT_COLLECTION, fp.collection_number); + read(app_cfg_section, APP_CONFIG_FONT_CHAR_GAP, fp.char_gap); + read(app_cfg_section, APP_CONFIG_FONT_LINE_GAP, fp.line_gap); + + EmbossStyle::Type type = WxFontUtils::get_actual_type(); + return EmbossStyle{name, path, type, fp}; +} + +void store_style(AppConfig &cfg, const EmbossStyle &fi, unsigned index) +{ + Section data; + data[APP_CONFIG_FONT_NAME] = fi.name; + data[APP_CONFIG_FONT_DESCRIPTOR] = fi.path; + const FontProp &fp = fi.prop; + data[APP_CONFIG_FONT_LINE_HEIGHT] = std::to_string(fp.size_in_mm); + data[APP_CONFIG_FONT_DEPTH] = std::to_string(fp.emboss); + if (fp.use_surface) + data[APP_CONFIG_FONT_USE_SURFACE] = "true"; + if (fp.boldness.has_value()) + data[APP_CONFIG_FONT_BOLDNESS] = std::to_string(*fp.boldness); + if (fp.skew.has_value()) + data[APP_CONFIG_FONT_SKEW] = std::to_string(*fp.skew); + if (fp.distance.has_value()) + data[APP_CONFIG_FONT_DISTANCE] = std::to_string(*fp.distance); + if (fp.angle.has_value()) + data[APP_CONFIG_FONT_ANGLE] = std::to_string(*fp.angle); + if (fp.collection_number.has_value()) + data[APP_CONFIG_FONT_COLLECTION] = std::to_string(*fp.collection_number); + if (fp.char_gap.has_value()) + data[APP_CONFIG_FONT_CHAR_GAP] = std::to_string(*fp.char_gap); + if (fp.line_gap.has_value()) + data[APP_CONFIG_FONT_LINE_GAP] = std::to_string(*fp.line_gap); + cfg.set_section(create_section_name(index), std::move(data)); +} + +void store_style_index(AppConfig &cfg, unsigned index) +{ + // store actual font index + // active font first index is +1 to correspond with section name + Section data; + data[APP_CONFIG_ACTIVE_FONT] = std::to_string(index); + cfg.set_section(AppConfig::SECTION_EMBOSS_STYLE, std::move(data)); +} + +std::optional load_style_index(const AppConfig &cfg) +{ + if (!cfg.has_section(AppConfig::SECTION_EMBOSS_STYLE)) + return {}; + + auto section = cfg.get_section(AppConfig::SECTION_EMBOSS_STYLE); + auto it = section.find(APP_CONFIG_ACTIVE_FONT); + if (it == section.end()) + return {}; + + size_t active_font = static_cast(std::atoi(it->second.c_str())); + // order in config starts with number 1 + return active_font - 1; +} + +EmbossStyles load_styles(const AppConfig &cfg) +{ + EmbossStyles result; + // human readable index inside of config starts from 1 !! + unsigned index = 1; + std::string section_name = create_section_name(index); + while (cfg.has_section(section_name)) { + std::optional style_opt = load_style(cfg.get_section(section_name)); + if (style_opt.has_value()) + result.emplace_back(*style_opt); + section_name = create_section_name(++index); + } + return result; +} + +void store_styles(AppConfig &cfg, const EmbossStyles &styles) +{ + // store styles + unsigned index = 1; + for (const EmbossStyle &style : styles) { + // skip file paths + fonts from other OS(loaded from .3mf) + assert(style.type == WxFontUtils::get_actual_type()); + // if (style_opt.type != WxFontUtils::get_actual_type()) continue; + store_style(cfg, style, index); + ++index; + } + + // remove rest of font sections (after deletation) + std::string section_name = create_section_name(index); + while (cfg.has_section(section_name)) { + cfg.clear_section(section_name); + section_name = create_section_name(index); + ++index; + } +} + +} // namespace diff --git a/src/slic3r/Utils/EmbossStyleManager.hpp b/src/slic3r/Utils/EmbossStyleManager.hpp index dd6b9ca129..5bab7adce5 100644 --- a/src/slic3r/Utils/EmbossStyleManager.hpp +++ b/src/slic3r/Utils/EmbossStyleManager.hpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include namespace Slic3r::GUI::Emboss { @@ -176,7 +178,9 @@ public: { void* texture_id = 0; // GLuint BoundingBox bounding_box; - ImVec2 tex_size, uv0, uv1; + ImVec2 tex_size; + ImVec2 uv0; + ImVec2 uv1; Point offset = Point(0, 0); StyleImage() = default; }; @@ -187,9 +191,28 @@ public: /// struct Item { - // define font, style and other property of text + // parent Text style EmbossStyle style; + // Define how to emboss shape + EmbossProjection projection; + + // 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] + + // Angle of rotation around emboss direction (Z axis) + // It is calculate on the fly from volume world transformation + // only StyleManager keep actual value for comparision with style + // When not set value is zero and is not stored + std::optional angle; // [in radians] form -Pi to Pi + + bool operator==(const Item &other) const + { + return style == other.style && projection == other.projection && distance == other.distance && angle == other.angle; + } + // cache for view font name with maximal width in imgui std::string truncated_name; diff --git a/src/slic3r/Utils/EmbossStylesSerializable.cpp b/src/slic3r/Utils/EmbossStylesSerializable.cpp deleted file mode 100644 index 111bb597b1..0000000000 --- a/src/slic3r/Utils/EmbossStylesSerializable.cpp +++ /dev/null @@ -1,201 +0,0 @@ -#include "EmbossStylesSerializable.hpp" - -#include -#include "WxFontUtils.hpp" - -using namespace Slic3r; -using namespace Slic3r::GUI; - -const std::string EmbossStylesSerializable::APP_CONFIG_FONT_NAME = "name"; -const std::string EmbossStylesSerializable::APP_CONFIG_FONT_DESCRIPTOR = "descriptor"; -const std::string EmbossStylesSerializable::APP_CONFIG_FONT_LINE_HEIGHT = "line_height"; -const std::string EmbossStylesSerializable::APP_CONFIG_FONT_DEPTH = "depth"; -const std::string EmbossStylesSerializable::APP_CONFIG_FONT_USE_SURFACE = "use_surface"; -const std::string EmbossStylesSerializable::APP_CONFIG_FONT_BOLDNESS = "boldness"; -const std::string EmbossStylesSerializable::APP_CONFIG_FONT_SKEW = "skew"; -const std::string EmbossStylesSerializable::APP_CONFIG_FONT_DISTANCE = "distance"; -const std::string EmbossStylesSerializable::APP_CONFIG_FONT_ANGLE = "angle"; -const std::string EmbossStylesSerializable::APP_CONFIG_FONT_COLLECTION = "collection"; -const std::string EmbossStylesSerializable::APP_CONFIG_FONT_CHAR_GAP = "char_gap"; -const std::string EmbossStylesSerializable::APP_CONFIG_FONT_LINE_GAP = "line_gap"; - -const std::string EmbossStylesSerializable::APP_CONFIG_ACTIVE_FONT = "active_font"; - -std::string EmbossStylesSerializable::create_section_name(unsigned index) -{ - return AppConfig::SECTION_EMBOSS_STYLE + ':' + std::to_string(index); -} - -// check only existence of flag -bool EmbossStylesSerializable::read(const std::map& section, const std::string& key, bool& value){ - auto item = section.find(key); - if (item == section.end()) return false; - - value = true; - return true; -} - -#include "fast_float/fast_float.h" -bool EmbossStylesSerializable::read(const std::map& section, const std::string& key, float& value){ - auto item = section.find(key); - if (item == section.end()) return false; - const std::string &data = item->second; - if (data.empty()) return false; - float value_; - fast_float::from_chars(data.c_str(), data.c_str() + data.length(), value_); - // read only non zero value - if (fabs(value_) <= std::numeric_limits::epsilon()) return false; - - value = value_; - return true; -} - -bool EmbossStylesSerializable::read(const std::map& section, const std::string& key, std::optional& value){ - auto item = section.find(key); - if (item == section.end()) return false; - const std::string &data = item->second; - if (data.empty()) return false; - int value_ = std::atoi(data.c_str()); - if (value_ == 0) return false; - - value = value_; - return true; -} - -bool EmbossStylesSerializable::read(const std::map& section, const std::string& key, std::optional& value){ - auto item = section.find(key); - if (item == section.end()) return false; - const std::string &data = item->second; - if (data.empty()) return false; - int value_ = std::atoi(data.c_str()); - if (value_ <= 0) return false; - - value = static_cast(value_); - return true; -} - -bool EmbossStylesSerializable::read(const std::map& section, const std::string& key, std::optional& value){ - auto item = section.find(key); - if (item == section.end()) return false; - const std::string &data = item->second; - if (data.empty()) return false; - float value_; - fast_float::from_chars(data.c_str(), data.c_str() + data.length(), value_); - // read only non zero value - if (fabs(value_) <= std::numeric_limits::epsilon()) return false; - - value = value_; - return true; -} - -std::optional EmbossStylesSerializable::load_style( - const std::map &app_cfg_section) -{ - auto path_it = app_cfg_section.find(APP_CONFIG_FONT_DESCRIPTOR); - if (path_it == app_cfg_section.end()) return {}; - const std::string &path = path_it->second; - - auto name_it = app_cfg_section.find(APP_CONFIG_FONT_NAME); - const std::string default_name = "font_name"; - const std::string &name = - (name_it == app_cfg_section.end()) ? - default_name : name_it->second; - - FontProp fp; - read(app_cfg_section, APP_CONFIG_FONT_LINE_HEIGHT, fp.size_in_mm); - read(app_cfg_section, APP_CONFIG_FONT_DEPTH, fp.emboss); - read(app_cfg_section, APP_CONFIG_FONT_USE_SURFACE, fp.use_surface); - read(app_cfg_section, APP_CONFIG_FONT_BOLDNESS, fp.boldness); - read(app_cfg_section, APP_CONFIG_FONT_SKEW, fp.skew); - read(app_cfg_section, APP_CONFIG_FONT_DISTANCE, fp.distance); - read(app_cfg_section, APP_CONFIG_FONT_ANGLE, fp.angle); - read(app_cfg_section, APP_CONFIG_FONT_COLLECTION, fp.collection_number); - read(app_cfg_section, APP_CONFIG_FONT_CHAR_GAP, fp.char_gap); - read(app_cfg_section, APP_CONFIG_FONT_LINE_GAP, fp.line_gap); - - EmbossStyle::Type type = WxFontUtils::get_actual_type(); - return EmbossStyle{ name, path, type, fp }; -} - -void EmbossStylesSerializable::store_style(AppConfig & cfg, - const EmbossStyle &fi, - unsigned index) -{ - std::map data; - data[APP_CONFIG_FONT_NAME] = fi.name; - data[APP_CONFIG_FONT_DESCRIPTOR] = fi.path; - const FontProp &fp = fi.prop; - data[APP_CONFIG_FONT_LINE_HEIGHT] = std::to_string(fp.size_in_mm); - data[APP_CONFIG_FONT_DEPTH] = std::to_string(fp.emboss); - if (fp.use_surface) - data[APP_CONFIG_FONT_USE_SURFACE] = "true"; - if (fp.boldness.has_value()) - data[APP_CONFIG_FONT_BOLDNESS] = std::to_string(*fp.boldness); - if (fp.skew.has_value()) - data[APP_CONFIG_FONT_SKEW] = std::to_string(*fp.skew); - if (fp.distance.has_value()) - data[APP_CONFIG_FONT_DISTANCE] = std::to_string(*fp.distance); - if (fp.angle.has_value()) - data[APP_CONFIG_FONT_ANGLE] = std::to_string(*fp.angle); - if (fp.collection_number.has_value()) - data[APP_CONFIG_FONT_COLLECTION] = std::to_string(*fp.collection_number); - if (fp.char_gap.has_value()) - data[APP_CONFIG_FONT_CHAR_GAP] = std::to_string(*fp.char_gap); - if (fp.line_gap.has_value()) - data[APP_CONFIG_FONT_LINE_GAP] = std::to_string(*fp.line_gap); - cfg.set_section(create_section_name(index), std::move(data)); -} - -void EmbossStylesSerializable::store_style_index(AppConfig &cfg, unsigned index) { - // store actual font index - // active font first index is +1 to correspond with section name - std::map data; - data[APP_CONFIG_ACTIVE_FONT] = std::to_string(index); - cfg.set_section(AppConfig::SECTION_EMBOSS_STYLE, std::move(data)); -} - -std::optional EmbossStylesSerializable::load_style_index(const AppConfig &cfg) -{ - if (!cfg.has_section(AppConfig::SECTION_EMBOSS_STYLE)) return {}; - - auto section = cfg.get_section(AppConfig::SECTION_EMBOSS_STYLE); - auto it = section.find(APP_CONFIG_ACTIVE_FONT); - if (it == section.end()) return {}; - - size_t active_font = static_cast(std::atoi(it->second.c_str())); - // order in config starts with number 1 - return active_font - 1; -} - -EmbossStyles EmbossStylesSerializable::load_styles(const AppConfig &cfg) -{ - EmbossStyles result; - // human readable index inside of config starts from 1 !! - unsigned index = 1; - std::string section_name = create_section_name(index); - while (cfg.has_section(section_name)) { - std::optional style_opt = load_style(cfg.get_section(section_name)); - if (style_opt.has_value()) result.emplace_back(*style_opt); - section_name = create_section_name(++index); - } - return result; -} - -void EmbossStylesSerializable::store_styles(AppConfig &cfg, const EmbossStyles& styles) -{ - // store styles - unsigned index = 1; - for (const EmbossStyle &style : styles) { - // skip file paths + fonts from other OS(loaded from .3mf) - assert(style.type == WxFontUtils::get_actual_type()); - // if (style_opt.type != WxFontUtils::get_actual_type()) continue; - store_style(cfg, style, index++); - } - - // remove rest of font sections (after deletation) - std::string section_name = create_section_name(index); - while (cfg.has_section(section_name)) { - cfg.clear_section(section_name); - section_name = create_section_name(++index); - } -} \ No newline at end of file diff --git a/src/slic3r/Utils/EmbossStylesSerializable.hpp b/src/slic3r/Utils/EmbossStylesSerializable.hpp deleted file mode 100644 index da87af8203..0000000000 --- a/src/slic3r/Utils/EmbossStylesSerializable.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef slic3r_EmbossStylesSerializable_hpp_ -#define slic3r_EmbossStylesSerializable_hpp_ - -#include -#include -#include -#include // EmbossStyles+EmbossStyle - -namespace Slic3r { -class AppConfig; -} - -namespace Slic3r::GUI { - -/// -/// For store/load font list to/from AppConfig -/// -class EmbossStylesSerializable -{ - static const std::string APP_CONFIG_FONT_NAME; - static const std::string APP_CONFIG_FONT_DESCRIPTOR; - static const std::string APP_CONFIG_FONT_LINE_HEIGHT; - static const std::string APP_CONFIG_FONT_DEPTH; - static const std::string APP_CONFIG_FONT_USE_SURFACE; - static const std::string APP_CONFIG_FONT_BOLDNESS; - static const std::string APP_CONFIG_FONT_SKEW; - static const std::string APP_CONFIG_FONT_DISTANCE; - static const std::string APP_CONFIG_FONT_ANGLE; - static const std::string APP_CONFIG_FONT_COLLECTION; - static const std::string APP_CONFIG_FONT_CHAR_GAP; - static const std::string APP_CONFIG_FONT_LINE_GAP; - - static const std::string APP_CONFIG_ACTIVE_FONT; -public: - EmbossStylesSerializable() = delete; - - static void store_style_index(AppConfig &cfg, unsigned index); - static std::optional load_style_index(const AppConfig &cfg); - - static EmbossStyles load_styles(const AppConfig &cfg); - static void store_styles(AppConfig &cfg, const EmbossStyles& styles); - -private: - static std::string create_section_name(unsigned index); - static std::optional load_style(const std::map &app_cfg_section); - static void store_style(AppConfig &cfg, const EmbossStyle &style, unsigned index); - - // TODO: move to app config like read from section - static bool read(const std::map& section, const std::string& key, bool& value); - static bool read(const std::map& section, const std::string& key, float& value); - static bool read(const std::map& section, const std::string& key, std::optional& value); - static bool read(const std::map& section, const std::string& key, std::optional& value); - static bool read(const std::map& section, const std::string& key, std::optional& value); -}; -} // namespace Slic3r - -#endif // #define slic3r_EmbossStylesSerializable_hpp_ - diff --git a/tests/libslic3r/test_emboss.cpp b/tests/libslic3r/test_emboss.cpp index f087dbf3a2..4c22d588de 100644 --- a/tests/libslic3r/test_emboss.cpp +++ b/tests/libslic3r/test_emboss.cpp @@ -511,8 +511,7 @@ TEST_CASE("UndoRedo TextConfiguration serialization", "[Emboss]") std::stringstream ss; // any stream can be used { - cereal::BinaryOutputArchive oarchive(ss); // Create an output archive - + cereal::BinaryOutputArchive oarchive(ss); // Create an output archive oarchive(tc); } // archive goes out of scope, ensuring all contents are flushed @@ -532,9 +531,8 @@ TEST_CASE("UndoRedo EmbossShape serialization", "[Emboss]") EmbossShape emboss; emboss.shapes = {{{0, 0}, {10, 0}, {10, 10}, {0, 10}}, {{5, 5}, {6, 5}, {6, 6}, {5, 6}}}; emboss.scale = 2.; - emboss.depth = 5.; - emboss.use_surface = true; - emboss.distance = 3.f; + emboss.projection.depth = 5.; + emboss.projection.use_surface = true; 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.\ @@ -543,7 +541,6 @@ TEST_CASE("UndoRedo EmbossShape serialization", "[Emboss]") 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 @@ -554,9 +551,8 @@ TEST_CASE("UndoRedo EmbossShape serialization", "[Emboss]") } CHECK(emboss.shapes == emboss_loaded.shapes); CHECK(emboss.scale == emboss_loaded.scale); - CHECK(emboss.depth == emboss_loaded.depth); - CHECK(emboss.use_surface == emboss_loaded.use_surface); - CHECK(emboss.distance == emboss_loaded.distance); + CHECK(emboss.projection.depth == emboss_loaded.projection.depth); + CHECK(emboss.projection.use_surface == emboss_loaded.projection.use_surface); }