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_ #define slic3r_EmbossShape_hpp_
#include <string> #include <string>
#include <optional>
#include <cereal/cereal.hpp> #include <cereal/cereal.hpp>
#include <cereal/types/string.hpp> #include <cereal/types/string.hpp>
#include <cereal/types/optional.hpp> #include <cereal/types/optional.hpp>
@ -12,6 +13,39 @@
namespace Slic3r { 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> /// <summary>
/// Contain plane shape information to be able emboss it and edit it /// Contain plane shape information to be able emboss it and edit it
/// </summary> /// </summary>
@ -22,19 +56,9 @@ struct EmbossShape
// scale of shape, multiplier to get 3d point in mm from integer shape // scale of shape, multiplier to get 3d point in mm from integer shape
double scale = 1.; 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 // Define how to emboss shape
bool use_surface = false; EmbossProjection projection;
// 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]
// !!! Volume stored in .3mf has transformed vertices. // !!! Volume stored in .3mf has transformed vertices.
// (baked transformation into vertices position) // (baked transformation into vertices position)
@ -50,14 +74,12 @@ struct EmbossShape
// undo / redo stack recovery // undo / redo stack recovery
template<class Archive> void save(Archive &ar) const template<class Archive> void save(Archive &ar) const
{ {
ar(shapes, scale, depth, use_surface, svg_file_path); ar(shapes, scale, projection, svg_file_path);
cereal::save(ar, distance);
cereal::save(ar, fix_3mf_tr); cereal::save(ar, fix_3mf_tr);
} }
template<class Archive> void load(Archive &ar) template<class Archive> void load(Archive &ar)
{ {
ar(shapes, scale, depth, use_surface, svg_file_path); ar(shapes, scale, projection, svg_file_path);
cereal::load(ar, distance);
cereal::load(ar, fix_3mf_tr); cereal::load(ar, fix_3mf_tr);
} }
}; };

View File

@ -26,15 +26,6 @@ struct FontProp
// When not set value is zero and is not stored // When not set value is zero and is not stored
std::optional<int> line_gap; // [in font point] 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 // positive value mean wider character shape
// negative value mean tiner character shape // negative value mean tiner character shape
// When not set value is zero and is not stored // 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 // When not set value is zero and is not stored
std::optional<float> skew; // [ration x:y] 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 // Parameter for True Type Font collections
// Select index of font in collection // Select index of font in collection
std::optional<unsigned int> collection_number; std::optional<unsigned int> collection_number;
//enum class Align { [[deprecated("Back compatibility only, now it is stored EmbossProjection like depth")]]
// left, float emboss;
// right,
// center, [[deprecated("Back compatibility only, now it is stored EmbossProjection")]]
// top_left, bool use_surface;
// top_right,
// top_center, [[deprecated("it is calculated on the fly")]]
// bottom_left, std::optional<float> distance;
// bottom_right,
// bottom_center [[deprecated("it is calculated on the fly")]]
//}; std::optional<float> angle;
//// change pivot of text
//// When not set, center is used and is not stored
//std::optional<Align> align;
////// //////
// Duplicit data to wxFontDescriptor // Duplicit data to wxFontDescriptor
@ -104,45 +81,29 @@ struct FontProp
return return
char_gap == other.char_gap && char_gap == other.char_gap &&
line_gap == other.line_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(size_in_mm, other.size_in_mm) &&
is_approx(boldness, other.boldness) && is_approx(boldness, other.boldness) &&
is_approx(skew, other.skew) && is_approx(skew, other.skew);
is_approx(distance, other.distance) &&
is_approx(angle, other.angle);
} }
// undo / redo stack recovery // undo / redo stack recovery
template<class Archive> void save(Archive &ar) const 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, char_gap);
cereal::save(ar, line_gap); cereal::save(ar, line_gap);
cereal::save(ar, boldness); cereal::save(ar, boldness);
cereal::save(ar, skew); cereal::save(ar, skew);
cereal::save(ar, distance);
cereal::save(ar, angle);
cereal::save(ar, collection_number); 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) 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, char_gap);
cereal::load(ar, line_gap); cereal::load(ar, line_gap);
cereal::load(ar, boldness); cereal::load(ar, boldness);
cereal::load(ar, skew); cereal::load(ar, skew);
cereal::load(ar, distance);
cereal::load(ar, angle);
cereal::load(ar, collection_number); 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 // undo / redo stack recovery
template<class Archive> void serialize(Archive &ar){ template<class Archive> void serialize(Archive &ar){ ar(name, path, type, prop); }
ar(name, path, type, prop);
}
}; };
// Emboss style name inside vector is unique // Emboss style name inside vector is unique
@ -219,21 +178,11 @@ struct TextConfiguration
// Embossed text value // Embossed text value
std::string text = "None"; std::string text = "None";
// !!! Volume stored in .3mf has transformed vertices. [[deprecated("only for back compatibility, now it is stored in EmbossShape")]]
// (baked transformation into vertices position)
// Only place for fill this is when load from .3mf
// This is correct volume transformation
std::optional<Transform3d> fix_3mf_tr; std::optional<Transform3d> fix_3mf_tr;
// undo / redo stack recovery // undo / redo stack recovery
template<class Archive> void save(Archive &ar) const{ template<class Archive> void serialize(Archive &ar) { ar(style, text); }
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);
}
}; };
} // namespace Slic3r } // namespace Slic3r

View File

@ -258,8 +258,6 @@ set(SLIC3R_GUI_SOURCES
Utils/Duet.hpp Utils/Duet.hpp
Utils/EmbossStyleManager.cpp Utils/EmbossStyleManager.cpp
Utils/EmbossStyleManager.hpp Utils/EmbossStyleManager.hpp
Utils/EmbossStylesSerializable.cpp
Utils/EmbossStylesSerializable.hpp
Utils/FlashAir.cpp Utils/FlashAir.cpp
Utils/FlashAir.hpp Utils/FlashAir.hpp
Utils/FontConfigHelp.cpp Utils/FontConfigHelp.cpp

View File

@ -291,12 +291,9 @@ void CreateObjectJob::process(Ctl &ctl)
if (!check(m_input)) if (!check(m_input))
throw JobException("Bad input data for EmbossCreateObjectJob."); 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 // can't create new object with using surface
if (m_input.base->shape.use_surface) if (m_input.base->shape.projection.use_surface)
m_input.base->shape.use_surface = false; m_input.base->shape.projection.use_surface = false;
auto was_canceled = ::was_canceled(ctl, *m_input.base); auto was_canceled = ::was_canceled(ctl, *m_input.base);
m_result = create_mesh(*m_input.base, was_canceled, ctl); 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>(); bed_coor = bed.centroid().cast<double>();
// TODO: need TextConfiguration refactor to work !!! // 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); Vec3d offset(bed_coor.x(), bed_coor.y(), z);
offset -= m_result.center(); offset -= m_result.center();
@ -658,6 +655,8 @@ bool check(const DataCreateVolume &input, bool is_main_thread)
assert(input.volume_type != ModelVolumeType::INVALID); assert(input.volume_type != ModelVolumeType::INVALID);
res &= input.volume_type != ModelVolumeType::INVALID; res &= input.volume_type != ModelVolumeType::INVALID;
res &= check(input.gizmo); res &= check(input.gizmo);
assert(!input.base->shape.projection.use_surface);
res &= !input.base->shape.projection.use_surface;
return res; return res;
} }
bool check(const DataCreateObject &input) bool check(const DataCreateObject &input)
@ -673,6 +672,8 @@ bool check(const DataCreateObject &input)
assert(input.bed_shape.size() >= 3); // at least triangle assert(input.bed_shape.size() >= 3); // at least triangle
res &= input.bed_shape.size() >= 3; res &= input.bed_shape.size() >= 3;
res &= check(input.gizmo); res &= check(input.gizmo);
assert(!input.base->shape.projection.use_surface);
res &= !input.base->shape.projection.use_surface;
return res; return res;
} }
bool check(const DataUpdate &input, bool is_main_thread, bool use_surface) 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; res &= input.base->cancel != nullptr;
if (is_main_thread) if (is_main_thread)
assert(!input.base->cancel->load()); assert(!input.base->cancel->load());
assert(!input.base->shape.projection.use_surface);
res &= !input.base->shape.projection.use_surface;
return res; return res;
} }
bool check(const CreateSurfaceVolumeData &input, bool is_main_thread) 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()); assert(!input.sources.empty());
res &= !input.sources.empty(); res &= !input.sources.empty();
res &= check(input.gizmo); res &= check(input.gizmo);
assert(input.base->shape.projection.use_surface);
res &= input.base->shape.projection.use_surface;
return res; return res;
} }
bool check(const UpdateSurfaceVolumeData &input, bool is_main_thread) 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); res &= check(*input.base, is_main_thread, use_surface);
assert(!input.sources.empty()); assert(!input.sources.empty());
res &= !input.sources.empty(); res &= !input.sources.empty();
assert(input.base->shape.projection.use_surface);
res &= input.base->shape.projection.use_surface;
return res; return res;
} }
@ -716,7 +723,7 @@ template<typename Fnc> TriangleMesh try_create_mesh(DataBase &base, const Fnc &w
const EmbossShape &shape = base.create_shape(); const EmbossShape &shape = base.create_shape();
if (shape.shapes.empty()) if (shape.shapes.empty())
return {}; return {};
double depth = shape.depth / shape.scale; double depth = shape.projection.depth / shape.scale;
auto projectZ = std::make_unique<ProjectZ>(depth); auto projectZ = std::make_unique<ProjectZ>(depth);
ProjectScale project(std::move(projectZ), shape.scale); ProjectScale project(std::move(projectZ), shape.scale);
if (was_canceled()) if (was_canceled())
@ -887,7 +894,7 @@ void create_volume(TriangleMesh &&mesh,
if (trmat.has_value()) { if (trmat.has_value()) {
volume->set_transformation(*trmat); volume->set_transformation(*trmat);
} else { } else {
assert(!data.shape.use_surface); assert(!data.shape.projection.use_surface);
// Create transformation for volume near from object(defined by glVolume) // Create transformation for volume near from object(defined by glVolume)
// Transformation is inspired add generic volumes in ObjectList::load_generic_subobject // Transformation is inspired add generic volumes in ObjectList::load_generic_subobject
Vec3d volume_size = volume->mesh().bounding_box().size(); Vec3d volume_size = volume->mesh().bounding_box().size();
@ -1064,7 +1071,7 @@ template<typename Fnc> TriangleMesh cut_surface(DataBase &base, const SurfaceVol
return {}; return {};
// !! Projection needs to transform cut // !! 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); indexed_triangle_set new_its = cut2model(cut, projection);
assert(!new_its.empty()); assert(!new_its.empty());
if (was_canceled()) if (was_canceled())
@ -1132,7 +1139,7 @@ bool start_create_volume_job(Worker &worker,
ModelVolumeType volume_type, ModelVolumeType volume_type,
GLGizmosManager::EType gizmo) GLGizmosManager::EType gizmo)
{ {
bool &use_surface = data->shape.use_surface; bool &use_surface = data->shape.projection.use_surface;
std::unique_ptr<GUI::Job> job; std::unique_ptr<GUI::Job> job;
if (use_surface) { if (use_surface) {
// Model to cut surface from. // 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 // soo create transfomation on border of object
// there is no point on surface so no use of surface will be applied // there is no point on surface so no use of surface will be applied
if (data_->shape.use_surface) if (data_->shape.projection.use_surface)
data_->shape.use_surface = false; data_->shape.projection.use_surface = false;
if (object == nullptr) if (object == nullptr)
return false; return false;

View File

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

View File

@ -1,15 +1,15 @@
#include "EmbossStyleManager.hpp" #include "EmbossStyleManager.hpp"
#include <optional>
#include <GL/glew.h> // Imgui texture #include <GL/glew.h> // Imgui texture
#include <imgui/imgui_internal.h> // ImTextCharFromUtf8 #include <imgui/imgui_internal.h> // ImTextCharFromUtf8
#include "WxFontUtils.hpp" #include <libslic3r/AppConfig.hpp>
#include "libslic3r/Utils.hpp" // ScopeGuard #include <libslic3r/Utils.hpp> // ScopeGuard
#include "WxFontUtils.hpp"
#include "slic3r/GUI/3DScene.hpp" // ::glsafe #include "slic3r/GUI/3DScene.hpp" // ::glsafe
#include "slic3r/GUI/Jobs/CreateFontStyleImagesJob.hpp" #include "slic3r/GUI/Jobs/CreateFontStyleImagesJob.hpp"
#include "slic3r/GUI/ImGuiWrapper.hpp" // check of font ranges #include "slic3r/GUI/ImGuiWrapper.hpp" // check of font ranges
#include "slic3r/Utils/EmbossStylesSerializable.hpp"
using namespace Slic3r; using namespace Slic3r;
using namespace Slic3r::Emboss; using namespace Slic3r::Emboss;
using namespace Slic3r::GUI::Emboss; using namespace Slic3r::GUI::Emboss;
@ -28,11 +28,22 @@ StyleManager::~StyleManager() {
free_style_images(); 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) void StyleManager::init(AppConfig *app_config)
{ {
m_app_config = app_config; m_app_config = app_config;
EmbossStyles styles = (app_config != nullptr) ? EmbossStyles styles = (app_config != nullptr) ?
EmbossStylesSerializable::load_styles(*app_config) : ::load_styles(*app_config) :
EmbossStyles{}; EmbossStyles{};
if (styles.empty()) if (styles.empty())
styles = m_create_default_styles(); 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) ? 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>{}; std::optional<size_t>{};
size_t active_index = 0; 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() ? size_t style_index = exist_stored_style() ?
m_style_cache.style_index : m_style_cache.style_index :
m_last_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; EmbossStyles styles;
styles.reserve(m_style_items.size()); styles.reserve(m_style_items.size());
for (const Item &item : m_style_items) styles.push_back(item.style); 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; return true;
} }
@ -542,3 +553,229 @@ bool StyleManager::set_wx_font(const wxFont &wx_font, std::unique_ptr<FontFile>
clear_imgui_font(); clear_imgui_font();
return true; 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 <GL/glew.h>
#include <libslic3r/BoundingBox.hpp> #include <libslic3r/BoundingBox.hpp>
#include <libslic3r/Emboss.hpp> #include <libslic3r/Emboss.hpp>
#include <libslic3r/TextConfiguration.hpp>
#include <libslic3r/EmbossShape.hpp>
#include <libslic3r/AppConfig.hpp> #include <libslic3r/AppConfig.hpp>
namespace Slic3r::GUI::Emboss { namespace Slic3r::GUI::Emboss {
@ -176,7 +178,9 @@ public:
{ {
void* texture_id = 0; // GLuint void* texture_id = 0; // GLuint
BoundingBox bounding_box; BoundingBox bounding_box;
ImVec2 tex_size, uv0, uv1; ImVec2 tex_size;
ImVec2 uv0;
ImVec2 uv1;
Point offset = Point(0, 0); Point offset = Point(0, 0);
StyleImage() = default; StyleImage() = default;
}; };
@ -187,9 +191,28 @@ public:
/// </summary> /// </summary>
struct Item struct Item
{ {
// define font, style and other property of text // parent Text style
EmbossStyle 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 // cache for view font name with maximal width in imgui
std::string truncated_name; 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 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); oarchive(tc);
} // archive goes out of scope, ensuring all contents are flushed } // archive goes out of scope, ensuring all contents are flushed
@ -532,9 +531,8 @@ TEST_CASE("UndoRedo EmbossShape serialization", "[Emboss]")
EmbossShape emboss; EmbossShape emboss;
emboss.shapes = {{{0, 0}, {10, 0}, {10, 10}, {0, 10}}, {{5, 5}, {6, 5}, {6, 6}, {5, 6}}}; emboss.shapes = {{{0, 0}, {10, 0}, {10, 10}, {0, 10}}, {{5, 5}, {6, 5}, {6, 6}, {5, 6}}};
emboss.scale = 2.; emboss.scale = 2.;
emboss.depth = 5.; emboss.projection.depth = 5.;
emboss.use_surface = true; emboss.projection.use_surface = true;
emboss.distance = 3.f;
emboss.fix_3mf_tr = Transform3d::Identity(); emboss.fix_3mf_tr = Transform3d::Identity();
emboss.svg_file_path = "Everything starts somewhere, though many physicists disagree.\ 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.\ 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 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(emboss); oarchive(emboss);
} // archive goes out of scope, ensuring all contents are flushed } // 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.shapes == emboss_loaded.shapes);
CHECK(emboss.scale == emboss_loaded.scale); CHECK(emboss.scale == emboss_loaded.scale);
CHECK(emboss.depth == emboss_loaded.depth); CHECK(emboss.projection.depth == emboss_loaded.projection.depth);
CHECK(emboss.use_surface == emboss_loaded.use_surface); CHECK(emboss.projection.use_surface == emboss_loaded.projection.use_surface);
CHECK(emboss.distance == emboss_loaded.distance);
} }