Reorganize data structures

This commit is contained in:
Filip Sykala - NTB T15p 2023-03-16 18:21:48 +01:00
parent 61fa3e8844
commit 574df48f85
10 changed files with 349 additions and 377 deletions

View File

@ -2,6 +2,7 @@
#define slic3r_EmbossShape_hpp_
#include <string>
#include <optional>
#include <cereal/cereal.hpp>
#include <cereal/types/string.hpp>
#include <cereal/types/optional.hpp>
@ -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> align;
// compare TextStyle
bool operator==(const EmbossProjection &other) const {
return depth == other.depth && use_surface == other.use_surface;
}
// undo / redo stack recovery
template<class Archive> void serialize(Archive &ar) { ar(depth, use_surface); }
};
/// <summary>
/// Contain plane shape information to be able emboss it and edit it
/// </summary>
@ -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<float> 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<class Archive> 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<class Archive> 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);
}
};

View File

@ -26,15 +26,6 @@ struct FontProp
// When not set value is zero and is not stored
std::optional<int> 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<float> 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<float> 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<float> angle; // [in radians] form -Pi to Pi
// Parameter for True Type Font collections
// Select index of font in collection
std::optional<unsigned int> 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> 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<float> distance;
[[deprecated("it is calculated on the fly")]]
std::optional<float> 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<class Archive> 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<class Archive> 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<class Archive> void serialize(Archive &ar){
ar(name, path, type, prop);
}
template<class Archive> 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<Transform3d> fix_3mf_tr;
// undo / redo stack recovery
template<class Archive> void save(Archive &ar) const{
ar(text, style);
cereal::save(ar, fix_3mf_tr);
}
template<class Archive> void load(Archive &ar){
ar(text, style);
cereal::load(ar, fix_3mf_tr);
}
template<class Archive> void serialize(Archive &ar) { ar(style, text); }
};
} // namespace Slic3r

View File

@ -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

View File

@ -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<double>();
// 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<typename Fnc> 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<ProjectZ>(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<typename Fnc> TriangleMesh cut_surface(DataBase &base, const SurfaceVol
return {};
// !! Projection needs to transform cut
OrthoProject3d projection = create_emboss_projection(input2.is_outside, static_cast<float>(emboss_shape.depth), emboss_tr, cut);
OrthoProject3d projection = create_emboss_projection(input2.is_outside, static_cast<float>(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<GUI::Job> 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;

View File

@ -168,7 +168,6 @@ SurfaceVolumeData::ModelSources create_volume_sources(const ModelVolume &volume)
/// </summary>
struct CreateVolumeParams
{
GLCanvas3D &canvas;
// Direction of ray into scene

View File

@ -1,15 +1,15 @@
#include "EmbossStyleManager.hpp"
#include <optional>
#include <GL/glew.h> // Imgui texture
#include <imgui/imgui_internal.h> // ImTextCharFromUtf8
#include "WxFontUtils.hpp"
#include "libslic3r/Utils.hpp" // ScopeGuard
#include <libslic3r/AppConfig.hpp>
#include <libslic3r/Utils.hpp> // 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();
}
/// <summary>
/// For store/load emboss style to/from AppConfig
/// </summary>
namespace {
void store_style_index(AppConfig &cfg, unsigned index);
::std::optional<size_t> 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<size_t> active_index_opt = (app_config != nullptr) ?
EmbossStylesSerializable::load_style_index(*app_config) :
::load_style_index(*app_config) :
std::optional<size_t>{};
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<FontFile>
clear_imgui_font();
return true;
}
#include <libslic3r/AppConfig.hpp>
#include "WxFontUtils.hpp"
#include "fast_float/fast_float.h"
// StylesSerializable
namespace {
using namespace Slic3r;
using namespace Slic3r::GUI;
using Section = std::map<std::string,std::string>;
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 &section, 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 &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<float>::epsilon())
return false;
value = value_;
return true;
}
bool read(const Section &section, const std::string &key, std::optional<int> &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 &section, const std::string &key, std::optional<unsigned int> &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<unsigned int>(value_);
return true;
}
bool read(const Section &section, const std::string &key, std::optional<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<float>::epsilon())
return false;
value = value_;
return true;
}
std::optional<EmbossStyle> 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<size_t> 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<size_t>(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<EmbossStyle> 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

View File

@ -10,6 +10,8 @@
#include <GL/glew.h>
#include <libslic3r/BoundingBox.hpp>
#include <libslic3r/Emboss.hpp>
#include <libslic3r/TextConfiguration.hpp>
#include <libslic3r/EmbossShape.hpp>
#include <libslic3r/AppConfig.hpp>
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:
/// </summary>
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<float> 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<float> 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;

View File

@ -1,201 +0,0 @@
#include "EmbossStylesSerializable.hpp"
#include <libslic3r/AppConfig.hpp>
#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<std::string, std::string>& 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<std::string, std::string>& 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<float>::epsilon()) return false;
value = value_;
return true;
}
bool EmbossStylesSerializable::read(const std::map<std::string, std::string>& section, const std::string& key, std::optional<int>& 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<std::string, std::string>& section, const std::string& key, std::optional<unsigned int>& 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<unsigned int>(value_);
return true;
}
bool EmbossStylesSerializable::read(const std::map<std::string, std::string>& section, const std::string& key, std::optional<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<float>::epsilon()) return false;
value = value_;
return true;
}
std::optional<EmbossStyle> EmbossStylesSerializable::load_style(
const std::map<std::string, std::string> &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<std::string, std::string> 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<std::string, std::string> data;
data[APP_CONFIG_ACTIVE_FONT] = std::to_string(index);
cfg.set_section(AppConfig::SECTION_EMBOSS_STYLE, std::move(data));
}
std::optional<size_t> 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<size_t>(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<EmbossStyle> 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);
}
}

View File

@ -1,58 +0,0 @@
#ifndef slic3r_EmbossStylesSerializable_hpp_
#define slic3r_EmbossStylesSerializable_hpp_
#include <string>
#include <map>
#include <optional>
#include <libslic3r/TextConfiguration.hpp> // EmbossStyles+EmbossStyle
namespace Slic3r {
class AppConfig;
}
namespace Slic3r::GUI {
/// <summary>
/// For store/load font list to/from AppConfig
/// </summary>
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<size_t> 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<EmbossStyle> load_style(const std::map<std::string, std::string> &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<std::string, std::string>& section, const std::string& key, bool& value);
static bool read(const std::map<std::string, std::string>& section, const std::string& key, float& value);
static bool read(const std::map<std::string, std::string>& section, const std::string& key, std::optional<int>& value);
static bool read(const std::map<std::string, std::string>& section, const std::string& key, std::optional<unsigned int>& value);
static bool read(const std::map<std::string, std::string>& section, const std::string& key, std::optional<float>& value);
};
} // namespace Slic3r
#endif // #define slic3r_EmbossStylesSerializable_hpp_

View File

@ -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);
}