diff --git a/src/libslic3r/CutSurface.cpp b/src/libslic3r/CutSurface.cpp
index a8db9e4183..7b95fe8c16 100644
--- a/src/libslic3r/CutSurface.cpp
+++ b/src/libslic3r/CutSurface.cpp
@@ -449,16 +449,21 @@ ProjectionDistances choose_best_distance(
///
/// For each point selected closest distance
/// All patches
-/// All patches
+/// Shape to cut
+/// Bound of shapes
+///
+///
+///
+///
/// Mask of used patch
std::vector select_patches(const ProjectionDistances &best_distances,
const SurfacePatches &patches,
-
- const ExPolygons &shapes,
- const ExPolygonsIndices &s2i,
- const VCutAOIs &cutAOIs,
- const CutMeshes &meshes,
- const Project &projection);
+ const ExPolygons &shapes,
+ const BoundingBox &shapes_bb,
+ const ExPolygonsIndices &s2i,
+ const VCutAOIs &cutAOIs,
+ const CutMeshes &meshes,
+ const Project &projection);
///
/// Merge two surface cuts together
@@ -601,8 +606,7 @@ SurfaceCut Slic3r::cut_surface(const ExPolygons &shapes,
// Use only outline points
// for each point select best projection
priv::ProjectionDistances best_projection = priv::choose_best_distance(distances, shapes, start, s2i, patches);
- std::vector use_patch = priv::select_patches(best_projection, patches,
- shapes, s2i,model_cuts, cgal_models, projection);
+ std::vector use_patch = priv::select_patches(best_projection, patches, shapes, shapes_bb, s2i, model_cuts, cgal_models, projection);
SurfaceCut result = merge_patches(patches, use_patch);
//*/
@@ -3194,15 +3198,17 @@ bool priv::is_over_whole_expoly(const CutAOI &cutAOI,
std::vector priv::select_patches(const ProjectionDistances &best_distances,
const SurfacePatches &patches,
-
- const ExPolygons &shapes,
- const ExPolygonsIndices &s2i,
- const VCutAOIs &cutAOIs,
- const CutMeshes &meshes,
- const Project &projection)
+ const ExPolygons &shapes,
+ const BoundingBox &shapes_bb,
+ const ExPolygonsIndices &s2i,
+ const VCutAOIs &cutAOIs,
+ const CutMeshes &meshes,
+ const Project &projection)
{
// extension to cover numerical mistake made by back projection patch from 3d to 2d
- const float extend_delta = 5.f / Emboss::SHAPE_SCALE; // [Font points scaled by Emboss::SHAPE_SCALE]
+ // Calculated as one percent of average size(width and height)
+ Point s = shapes_bb.size();
+ const float extend_delta = (s.x() + s.y())/ float(2 * 100);
// vector of patches for shape
std::vector> used_shapes_patches(shapes.size());
diff --git a/src/libslic3r/Emboss.cpp b/src/libslic3r/Emboss.cpp
index 65aa5a333b..ed8ad12a8c 100644
--- a/src/libslic3r/Emboss.cpp
+++ b/src/libslic3r/Emboss.cpp
@@ -19,6 +19,10 @@
#include "libslic3r/Line.hpp"
#include "libslic3r/BoundingBox.hpp"
+// every glyph's shape point is divided by SHAPE_SCALE - increase precission of fixed point value
+// stored in fonts (to be able represents curve by sequence of lines)
+static constexpr double SHAPE_SCALE = 0.001; // SCALING_FACTOR promile is fine enough
+
using namespace Slic3r;
using namespace Emboss;
using fontinfo_opt = std::optional;
@@ -1358,12 +1362,12 @@ std::string Emboss::create_range_text(const std::string &text,
return boost::nowide::narrow(ws);
}
-double Emboss::get_shape_scale(const FontProp &fp, const FontFile &ff)
+double Emboss::get_text_shape_scale(const FontProp &fp, const FontFile &ff)
{
- const auto &cn = fp.collection_number;
+ const std::optional &cn = fp.collection_number;
unsigned int font_index = (cn.has_value()) ? *cn : 0;
- int unit_per_em = ff.infos[font_index].unit_per_em;
- double scale = fp.size_in_mm / unit_per_em;
+ int unit_per_em = ff.infos[font_index].unit_per_em;
+ double scale = fp.size_in_mm / unit_per_em;
// Shape is scaled for store point coordinate as integer
return scale * SHAPE_SCALE;
}
@@ -1523,10 +1527,7 @@ indexed_triangle_set Emboss::polygons2model(const ExPolygons &shape2d,
std::pair Emboss::ProjectZ::create_front_back(const Point &p) const
{
- Vec3d front(
- p.x() * SHAPE_SCALE,
- p.y() * SHAPE_SCALE,
- 0.);
+ Vec3d front(p.x(), p.y(), 0.);
return std::make_pair(front, project(front));
}
@@ -1538,8 +1539,7 @@ Vec3d Emboss::ProjectZ::project(const Vec3d &point) const
}
std::optional Emboss::ProjectZ::unproject(const Vec3d &p, double *depth) const {
- if (depth != nullptr) *depth /= SHAPE_SCALE;
- return Vec2d(p.x() / SHAPE_SCALE, p.y() / SHAPE_SCALE);
+ return Vec2d(p.x(), p.y());
}
diff --git a/src/libslic3r/Emboss.hpp b/src/libslic3r/Emboss.hpp
index fc0f0a0a3c..2e0eae7322 100644
--- a/src/libslic3r/Emboss.hpp
+++ b/src/libslic3r/Emboss.hpp
@@ -18,10 +18,6 @@ namespace Slic3r {
///
namespace Emboss
{
- // every glyph's shape point is divided by SHAPE_SCALE - increase precission of fixed point value
- // stored in fonts (to be able represents curve by sequence of lines)
- static constexpr double SHAPE_SCALE = 0.001; // SCALING_FACTOR promile is fine enough
-
///
/// Collect fonts registred inside OS
///
@@ -220,7 +216,7 @@ namespace Emboss
/// Property of font
/// Font data
/// Conversion to mm
- double get_shape_scale(const FontProp &fp, const FontFile &ff);
+ double get_text_shape_scale(const FontProp &fp, const FontFile &ff);
///
/// Project spatial point
diff --git a/src/libslic3r/EmbossShape.hpp b/src/libslic3r/EmbossShape.hpp
index bbb37d39a7..97a0f8a943 100644
--- a/src/libslic3r/EmbossShape.hpp
+++ b/src/libslic3r/EmbossShape.hpp
@@ -18,13 +18,14 @@ namespace Slic3r {
struct EmbossShape
{
// shape defined by integer point consist only by lines not curves
- ExPolygons shape;
+ ExPolygons shapes;
// scale of shape, multiplier to get 3d point in mm from integer shape
- double shape_scale;
+ double scale;
- // Emboss depth
- double depth; // [in world mm]
+ // Emboss depth, Size in local Z direction
+ double depth; // [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;
@@ -32,6 +33,7 @@ struct EmbossShape
// 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]
// !!! Volume stored in .3mf has transformed vertices.
@@ -42,18 +44,19 @@ struct EmbossShape
std::optional fix_3mf_tr;
// file(.svg) path to source of shape
+ // When empty can't reload from disk
std::string svg_file_path;
// undo / redo stack recovery
template void save(Archive &ar) const
{
- ar(shape, shape_scale, depth, use_surface, svg_file_path);
+ ar(shapes, scale, depth, use_surface, svg_file_path);
cereal::save(ar, distance);
cereal::save(ar, fix_3mf_tr);
}
template void load(Archive &ar)
{
- ar(shape, shape_scale, depth, use_surface, svg_file_path);
+ ar(shapes, scale, depth, use_surface, svg_file_path);
cereal::load(ar, distance);
cereal::load(ar, fix_3mf_tr);
}
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index ae0e54b456..5aa9943900 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -1833,12 +1833,7 @@ void ObjectList::load_shape_object_from_gallery(const wxArrayString& input_files
wxGetApp().mainframe->update_title();
}
-void ObjectList::load_mesh_object(
- const TriangleMesh & mesh,
- const std::string & name,
- bool center,
- const TextConfiguration *text_config /* = nullptr*/,
- const Transform3d * transformation /* = nullptr*/)
+void ObjectList::load_mesh_object(const TriangleMesh &mesh, const std::string &name, bool center)
{
PlaterAfterLoadAutoArrange plater_after_load_auto_arrange;
// Add mesh to model as a new object
@@ -1848,7 +1843,6 @@ void ObjectList::load_mesh_object(
check_model_ids_validity(model);
#endif /* _DEBUG */
- std::vector object_idxs;
ModelObject* new_object = model.add_object();
new_object->name = name;
new_object->add_instance(); // each object should have at list one instance
@@ -1856,31 +1850,24 @@ void ObjectList::load_mesh_object(
ModelVolume* new_volume = new_object->add_volume(mesh);
new_object->sort_volumes(wxGetApp().app_config->get_bool("order_volumes"));
new_volume->name = name;
- if (text_config)
- new_volume->text_configuration = *text_config;
+
// set a default extruder value, since user can't add it manually
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
new_object->invalidate_bounding_box();
- if (transformation) {
- assert(!center);
- Slic3r::Geometry::Transformation tr(*transformation);
- new_object->instances[0]->set_transformation(tr);
- } else {
- auto bb = mesh.bounding_box();
- new_object->translate(-bb.center());
- new_object->instances[0]->set_offset(
- center ? to_3d(wxGetApp().plater()->build_volume().bounding_volume2d().center(), -new_object->origin_translation.z()) :
- bb.center());
- }
+
+ auto bb = mesh.bounding_box();
+ new_object->translate(-bb.center());
+ new_object->instances[0]->set_offset(
+ center ? to_3d(wxGetApp().plater()->build_volume().bounding_volume2d().center(), -new_object->origin_translation.z()) :
+ bb.center());
new_object->ensure_on_bed();
- object_idxs.push_back(model.objects.size() - 1);
#ifdef _DEBUG
check_model_ids_validity(model);
#endif /* _DEBUG */
-
- paste_objects_into_list(object_idxs);
+
+ paste_objects_into_list({model.objects.size() - 1});
#ifdef _DEBUG
check_model_ids_validity(model);
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index d2965c77e3..9f2a10e2b6 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -27,7 +27,6 @@ class ModelConfig;
class ModelObject;
class ModelVolume;
class TriangleMesh;
-struct TextConfiguration;
enum class ModelVolumeType : int;
// FIXME: broken build on mac os because of this is missing:
@@ -258,8 +257,7 @@ public:
void load_shape_object(const std::string &type_name);
void load_shape_object_from_gallery();
void load_shape_object_from_gallery(const wxArrayString& input_files);
- void load_mesh_object(const TriangleMesh &mesh, const std::string &name, bool center = true,
- const TextConfiguration* text_config = nullptr, const Transform3d* transformation = nullptr);
+ void load_mesh_object(const TriangleMesh &mesh, const std::string &name, bool center = true);
bool del_object(const int obj_idx);
bool del_subobject_item(wxDataViewItem& item);
void del_settings_from_config(const wxDataViewItem& parent_item);
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
index 034a563d2e..457471af54 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
@@ -107,6 +107,67 @@ GLGizmoEmboss::GLGizmoEmboss(GLCanvas3D &parent)
// Private namespace with helper function for create volume
namespace priv {
+///
+/// Data for emboss job to create shape
+///
+struct TextDataBase : public DataBase
+{
+ TextDataBase(DataBase &&parent, const FontFileWithCache& font_file, TextConfiguration &&text_configuration)
+ : DataBase(std::move(parent)), font_file(font_file) /* copy */, text_configuration(std::move(text_configuration))
+ {
+ assert(this->font_file.has_value());
+
+ // partialy fill shape from text configuration
+ const FontProp &fp = this->text_configuration.style.prop;
+ shape.depth = fp.emboss;
+ shape.use_surface = fp.use_surface;
+ shape.distance = fp.distance;
+
+ const FontFile &ff = *this->font_file.font_file;
+ shape.scale = get_text_shape_scale(fp, ff);
+ }
+ ///
+ /// Create shape from text and font
+ ///
+ /// Text shape defined by configuration and font file
+ EmbossShape &create_shape() override {
+ if (!shape.shapes.empty())
+ return shape;
+
+ // create shape by configuration
+ const char *text = text_configuration.text.c_str();
+ const FontProp &fp = text_configuration.style.prop;
+ auto was_canceled = [&c = cancel]() -> bool { return c->load(); };
+ shape.shapes = text2shapes(font_file, text, fp, was_canceled);
+
+ // TEST
+ const FontProp &prop = text_configuration.style.prop;
+ const std::optional &cn = prop.collection_number;
+ unsigned int font_index = (cn.has_value()) ? *cn : 0;
+ const FontFileWithCache &font = font_file;
+ assert(font_index < font.font_file->infos.size());
+ int unit_per_em = font.font_file->infos[font_index].unit_per_em;
+ float scale = prop.size_in_mm / unit_per_em;
+ float depth = prop.emboss / scale;
+
+ return shape;
+ }
+
+ void write(ModelVolume &volume) const override
+ {
+ volume.text_configuration = text_configuration; // copy
+
+ // discard information about rotation, should not be stored in volume
+ volume.text_configuration->style.prop.angle.reset();
+
+ DataBase::write(volume);
+ }
+
+ // Keep pointer on Data of font (glyph shapes)
+ FontFileWithCache font_file;
+ // font item is not used for create object
+ TextConfiguration text_configuration;
+};
///
/// Check if volume type is possible use for new text volume
@@ -122,7 +183,8 @@ static bool is_valid(ModelVolumeType volume_type);
/// Keep actual selected style
/// Cancel for previous job
/// Base data for emboss text
-static DataBase create_emboss_data_base(const std::string &text, StyleManager &style_manager, std::shared_ptr> &cancel);
+static std::unique_ptr create_emboss_data_base(
+ const std::string &text, StyleManager &style_manager, std::shared_ptr> &cancel);
///
/// Start job for add new volume to object with given transformation
@@ -133,7 +195,7 @@ static DataBase create_emboss_data_base(const std::string &text, StyleManager &s
/// Type of volume
static void start_create_volume_job(const ModelObject *object,
const Transform3d volume_trmat,
- DataBase &emboss_data,
+ std::unique_ptr emboss_data,
ModelVolumeType volume_type);
///
@@ -146,7 +208,7 @@ static void start_create_volume_job(const ModelObject *object,
/// Ability to ray cast to model
/// Contain already used scene RayCasters
/// True when start creation, False when there is no hit surface by screen coor
-static bool start_create_volume_on_surface_job(DataBase &emboss_data,
+static bool start_create_volume_on_surface_job(std::unique_ptr emboss_data,
ModelVolumeType volume_type,
const Vec2d &screen_coor,
const GLVolume *gl_volume,
@@ -174,7 +236,7 @@ static void find_closest_volume(const Selection &selection,
///
/// Define params of text
/// Screen coordinat, where to create new object laying on bed
-static void start_create_object_job(DataBase &emboss_data, const Vec2d &coor);
+static void start_create_object_job(std::unique_ptr emboss_data, const Vec2d &coor);
// Loaded icons enum
// Have to match order of files in function GLGizmoEmboss::init_icons()
@@ -209,17 +271,17 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mous
set_default_text();
GLVolume *gl_volume = get_first_hovered_gl_volume(m_parent);
- DataBase emboss_data = priv::create_emboss_data_base(m_text, m_style_manager, m_job_cancel);
+ std::unique_ptr emboss_data = priv::create_emboss_data_base(m_text, m_style_manager, m_job_cancel);
if (gl_volume != nullptr) {
// Try to cast ray into scene and find object for add volume
- if (!priv::start_create_volume_on_surface_job(emboss_data, volume_type, mouse_pos, gl_volume, m_raycast_manager, m_parent)) {
+ if (!priv::start_create_volume_on_surface_job(std::move(emboss_data), volume_type, mouse_pos, gl_volume, m_raycast_manager, m_parent)) {
// When model is broken. It could appear that hit miss the object.
// So add part near by in simmilar manner as right panel do
create_volume(volume_type);
}
} else {
// object is not under mouse position soo create object on plater
- priv::start_create_object_job(emboss_data, mouse_pos);
+ priv::start_create_object_job(std::move(emboss_data), mouse_pos);
}
}
@@ -236,13 +298,13 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type)
Size s = m_parent.get_canvas_size();
Vec2d screen_center(s.get_width() / 2., s.get_height() / 2.);
- DataBase emboss_data = priv::create_emboss_data_base(m_text, m_style_manager, m_job_cancel);
+ std::unique_ptr emboss_data = priv::create_emboss_data_base(m_text, m_style_manager, m_job_cancel);
const ModelObjectPtrs &objects = selection.get_model()->objects;
// No selected object so create new object
if (selection.is_empty() || object_idx < 0 || static_cast(object_idx) >= objects.size()) {
// create Object on center of screen
// when ray throw center of screen not hit bed it create object on center of bed
- priv::start_create_object_job(emboss_data, screen_center);
+ priv::start_create_object_job(std::move(emboss_data), screen_center);
return;
}
@@ -252,15 +314,18 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type)
const Camera &camera = wxGetApp().plater()->get_camera();
priv::find_closest_volume(selection, screen_center, camera, objects, &coor, &vol);
if (vol == nullptr) {
- priv::start_create_object_job(emboss_data, screen_center);
- } else if (!priv::start_create_volume_on_surface_job(emboss_data, volume_type, coor, vol, m_raycast_manager, m_parent)) {
+ priv::start_create_object_job(std::move(emboss_data), screen_center);
+ } else if (!priv::start_create_volume_on_surface_job(std::move(emboss_data), volume_type, coor, vol, m_raycast_manager, m_parent)) {
// in centroid of convex hull is not hit with object
// soo create transfomation on border of object
+ // unique pointer is already destoyed need to create again
+ std::unique_ptr emboss_data = priv::create_emboss_data_base(m_text, m_style_manager, m_job_cancel);
+ // TODO: do it better way
+ FontProp &fp = static_cast(emboss_data.get())->text_configuration.style.prop;
// there is no point on surface so no use of surface will be applied
- FontProp &prop = emboss_data.text_configuration.style.prop;
- if (prop.use_surface)
- prop.use_surface = false;
+ if (fp.use_surface)
+ fp.use_surface = false;
// Transformation is inspired add generic volumes in ObjectList::load_generic_subobject
const ModelObject *obj = objects[vol->object_idx()];
@@ -268,11 +333,11 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type)
// Translate the new modifier to be pickable: move to the left front corner of the instance's bounding box, lift to print bed.
Transform3d tr = vol->get_instance_transformation().get_matrix_no_offset().inverse();
Vec3d offset_tr(0, // center of instance - Can't suggest width of text before it will be created
- - instance_bb.size().y() / 2 - prop.size_in_mm / 2, // under
- prop.emboss / 2 - instance_bb.size().z() / 2 // lay on bed
+ - instance_bb.size().y() / 2 - fp.size_in_mm / 2, // under
+ fp.emboss / 2 - instance_bb.size().z() / 2 // lay on bed
);
Transform3d volume_trmat = tr * Eigen::Translation3d(offset_tr);
- priv::start_create_volume_job(obj, volume_trmat, emboss_data, volume_type);
+ priv::start_create_volume_job(obj, volume_trmat, std::move(emboss_data), volume_type);
}
}
@@ -1064,8 +1129,10 @@ bool GLGizmoEmboss::process()
std::unique_ptr job = nullptr;
- // check cutting from source mesh
- bool &use_surface = data.text_configuration.style.prop.use_surface;
+ // check cutting from source mesh
+ // TODO: do it better way
+ FontProp &fp = static_cast(data.base.get())->text_configuration.style.prop;
+ bool &use_surface = fp.use_surface;
bool is_object = m_volume->get_object()->volumes.size() == 1;
if (use_surface && is_object)
use_surface = false;
@@ -3271,15 +3338,16 @@ bool GLGizmoEmboss::is_text_object(const ModelVolume *text) {
bool priv::is_valid(ModelVolumeType volume_type)
{
- if (volume_type == ModelVolumeType::MODEL_PART || volume_type == ModelVolumeType::NEGATIVE_VOLUME ||
+ if (volume_type == ModelVolumeType::MODEL_PART ||
+ volume_type == ModelVolumeType::NEGATIVE_VOLUME ||
volume_type == ModelVolumeType::PARAMETER_MODIFIER)
return true;
- BOOST_LOG_TRIVIAL(error) << "Can't create embossed volume with this type: " << (int) volume_type;
+ BOOST_LOG_TRIVIAL(error) << "Can't create embossed text with this type: " << (int) volume_type;
return false;
}
-DataBase priv::create_emboss_data_base(const std::string &text, StyleManager &style_manager, std::shared_ptr>& cancel)
+std::unique_ptr priv::create_emboss_data_base(const std::string &text, StyleManager &style_manager, std::shared_ptr>& cancel)
{
// create volume_name
std::string volume_name = text; // copy
@@ -3297,7 +3365,6 @@ DataBase priv::create_emboss_data_base(const std::string &text, StyleManager &st
// volume must store valid path
assert(style_manager.get_wx_font().IsOk());
assert(es.path.compare(WxFontUtils::store_wxFont(style_manager.get_wx_font())) == 0);
- TextConfiguration tc{es, text};
// Cancel previous Job, when it is in process
// worker.cancel(); --> Use less in this case I want cancel only previous EmbossJob no other jobs
@@ -3306,10 +3373,14 @@ DataBase priv::create_emboss_data_base(const std::string &text, StyleManager &st
cancel->store(true);
// create new shared ptr to cancel new job
cancel = std::make_shared>(false);
- return Slic3r::GUI::Emboss::DataBase{style_manager.get_font_file_with_cache(), tc, volume_name, cancel};
+
+ DataBase base(volume_name, cancel);
+ FontFileWithCache &font = style_manager.get_font_file_with_cache();
+ TextConfiguration tc{es, text};
+ return std::make_unique(std::move(base), font, std::move(tc));
}
-void priv::start_create_object_job(DataBase &emboss_data, const Vec2d &coor)
+void priv::start_create_object_job(std::unique_ptr emboss_data, const Vec2d &coor)
{
// start creation of new object
Plater *plater = wxGetApp().plater();
@@ -3317,12 +3388,13 @@ void priv::start_create_object_job(DataBase &emboss_data, const Vec2d &coor)
const Pointfs &bed_shape = plater->build_volume().bed_shape();
// can't create new object with distance from surface
- FontProp &prop = emboss_data.text_configuration.style.prop;
- if (prop.distance.has_value()) prop.distance.reset();
+ // TODO: do it better way
+ FontProp &fp = static_cast(emboss_data.get())->text_configuration.style.prop;
+ if (fp.distance.has_value()) fp.distance.reset();
// can't create new object with using surface
- if (prop.use_surface)
- prop.use_surface = false;
+ if (fp.use_surface)
+ fp.use_surface = false;
// Transform3d volume_tr = priv::create_transformation_on_bed(mouse_pos, camera, bed_shape, prop.emboss / 2);
DataCreateObject data{std::move(emboss_data), coor, camera, bed_shape};
@@ -3333,10 +3405,13 @@ void priv::start_create_object_job(DataBase &emboss_data, const Vec2d &coor)
void priv::start_create_volume_job(const ModelObject *object,
const Transform3d volume_trmat,
- DataBase &emboss_data,
+ std::unique_ptr emboss_data,
ModelVolumeType volume_type)
{
- bool &use_surface = emboss_data.text_configuration.style.prop.use_surface;
+ // TODO: do it better way
+ FontProp &fp = static_cast(emboss_data.get())->text_configuration.style.prop;
+ bool &use_surface = fp.use_surface;
+
std::unique_ptr job;
if (use_surface) {
// Model to cut surface from.
@@ -3348,7 +3423,7 @@ void priv::start_create_volume_job(const ModelObject *object,
// check that there is not unexpected volume type
assert(is_outside || volume_type == ModelVolumeType::NEGATIVE_VOLUME || volume_type == ModelVolumeType::PARAMETER_MODIFIER);
SurfaceVolumeData sfvd{volume_trmat, is_outside, std::move(sources)};
- CreateSurfaceVolumeData surface_data{std::move(emboss_data), std::move(sfvd), volume_type, object->id()};
+ CreateSurfaceVolumeData surface_data{std::move(sfvd), std::move(emboss_data), volume_type, object->id()};
job = std::make_unique(std::move(surface_data));
}
}
@@ -3363,8 +3438,12 @@ void priv::start_create_volume_job(const ModelObject *object,
queue_job(worker, std::move(job));
}
-bool priv::start_create_volume_on_surface_job(
- DataBase &emboss_data, ModelVolumeType volume_type, const Vec2d &screen_coor, const GLVolume *gl_volume, RaycastManager &raycaster, GLCanvas3D& canvas)
+bool priv::start_create_volume_on_surface_job(std::unique_ptr emboss_data,
+ ModelVolumeType volume_type,
+ const Vec2d &screen_coor,
+ const GLVolume *gl_volume,
+ RaycastManager &raycaster,
+ GLCanvas3D &canvas)
{
assert(gl_volume != nullptr);
if (gl_volume == nullptr) return false;
@@ -3395,11 +3474,14 @@ bool priv::start_create_volume_on_surface_job(
// Create result volume transformation
Transform3d surface_trmat = create_transformation_onto_surface(hit->position, hit->normal, Slic3r::GUI::up_limit);
- const FontProp &font_prop = emboss_data.text_configuration.style.prop;
- apply_transformation(font_prop, surface_trmat);
+
+ // TODO: find better way !!!
+ const FontProp &fp = static_cast(emboss_data.get())->text_configuration.style.prop;
+
+ apply_transformation(fp, surface_trmat);
// new transformation in world coor is surface_trmat
Transform3d volume_trmat = instance.inverse() * surface_trmat;
- start_create_volume_job(obj, volume_trmat, emboss_data, volume_type);
+ start_create_volume_job(obj, volume_trmat, std::move(emboss_data), volume_type);
return true;
}
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp
index 4d788ba54b..30a3540f3d 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp
@@ -41,9 +41,6 @@ static const struct Limits
// distance text object from surface
MinMax angle{-180.f, 180.f}; // in degrees
} limits;
-
-static std::string choose_svg_file();
-static std::string get_file_name(const std::string &file_path);
} // namespace priv
GLGizmoSVG::GLGizmoSVG(GLCanvas3D &parent)
@@ -56,6 +53,34 @@ GLGizmoSVG::GLGizmoSVG(GLCanvas3D &parent)
m_rotate_gizmo.set_force_local_coordinate(true);
}
+// Private functions to create emboss volume
+namespace priv {
+
+///
+/// Check if volume type is possible use for new text volume
+///
+/// Type
+/// True when allowed otherwise false
+static bool is_valid(ModelVolumeType volume_type);
+
+///
+/// Open file dialog with svg files
+///
+/// File path to svg
+static std::string choose_svg_file();
+
+///
+/// Separate file name from file path.
+/// String after last delimiter and before last point
+///
+/// path return by file dialog
+/// File name without directory path
+static std::string get_file_name(const std::string &file_path);
+
+
+} // namespace priv
+
+
void GLGizmoSVG::create_volume(ModelVolumeType volume_type, const Vec2d &mouse_pos){
std::string path = priv::choose_svg_file();
if (path.empty()) return;
@@ -594,30 +619,70 @@ void GLGizmoSVG::draw_model_type()
}
+/////////////
+// priv namespace implementation
+///////////////
+
+bool priv::is_valid(ModelVolumeType volume_type)
+{
+ if (volume_type == ModelVolumeType::MODEL_PART ||
+ volume_type == ModelVolumeType::NEGATIVE_VOLUME ||
+ volume_type == ModelVolumeType::PARAMETER_MODIFIER )
+ return true;
+
+ BOOST_LOG_TRIVIAL(error) << "Can't create embossed SVG with this type: " << (int) volume_type;
+ return false;
+}
+
std::string priv::get_file_name(const std::string &file_path)
{
+ if (file_path.empty())
+ return file_path;
+
size_t pos_last_delimiter = file_path.find_last_of("/\\");
- size_t pos_point = file_path.find_last_of('.');
- size_t offset = pos_last_delimiter + 1;
- size_t count = pos_point - pos_last_delimiter - 1;
+ if (pos_last_delimiter == std::string::npos) {
+ // should not happend that in path is not delimiter
+ assert(false);
+ pos_last_delimiter = 0;
+ }
+
+ size_t pos_point = file_path.find_last_of('.');
+ if (pos_point == std::string::npos ||
+ pos_point < pos_last_delimiter // last point is inside of directory path
+ ) {
+ // there is no extension
+ assert(false);
+ pos_point = file_path.size();
+ }
+
+ size_t offset = pos_last_delimiter + 1; // result should not contain last delimiter ( +1 )
+ size_t count = pos_point - pos_last_delimiter - 1; // result should not contain extension point ( -1 )
return file_path.substr(offset, count);
}
std::string priv::choose_svg_file()
{
- wxArrayString input_files;
+ wxWindow* parent = nullptr;
+ wxString message = _L("Choose SVG file for emboss:");
wxString defaultDir = wxEmptyString;
wxString selectedFile = wxEmptyString;
-
- wxFileDialog dialog(nullptr, _L("Choose SVG file:"), defaultDir,
- selectedFile, file_wildcards(FT_SVG),
- wxFD_OPEN | wxFD_FILE_MUST_EXIST);
-
- if (dialog.ShowModal() == wxID_OK) dialog.GetPaths(input_files);
- if (input_files.IsEmpty())
+ wxString wildcard = file_wildcards(FT_SVG);
+ long style = wxFD_OPEN | wxFD_FILE_MUST_EXIST;
+ wxFileDialog dialog(parent, message, defaultDir, selectedFile, wildcard, style);
+ if (dialog.ShowModal() != wxID_OK) {
+ BOOST_LOG_TRIVIAL(warning) << "SVG file for emboss was NOT selected.";
return {};
+ }
+
+ wxArrayString input_files;
+ dialog.GetPaths(input_files);
+ if (input_files.IsEmpty()) {
+ BOOST_LOG_TRIVIAL(warning) << "SVG file dialog result is empty.";
+ return {};
+ }
+
if (input_files.size() != 1)
- return {};
+ BOOST_LOG_TRIVIAL(warning) << "SVG file dialog result contain multiple files but only first is used.";
auto &input_file = input_files.front();
std::string path = std::string(input_file.c_str());
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp
index 90552c0a5d..6cbf96799d 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp
@@ -37,7 +37,7 @@ static void call_after_if_active(std::function fn, GUI_App* app = &wxGet
});
}
-static std::set get_volume_ids(const Selection &selection)
+static std::set get_selected_volume_ids(const Selection &selection)
{
const Selection::IndicesList &volume_ids = selection.get_volume_idxs();
const ModelObjectPtrs &model_objects = selection.get_model()->objects;
@@ -64,20 +64,6 @@ static std::set get_volume_ids(const Selection &selection)
return result;
}
-// return ModelVolume from selection by object id
-static ModelVolume *get_volume(const ObjectID &id, const Selection &selection) {
- const Selection::IndicesList &volume_ids = selection.get_volume_idxs();
- const ModelObjectPtrs &model_objects = selection.get_model()->objects;
- for (auto volume_id : volume_ids) {
- const GLVolume *selected_volume = selection.get_volume(volume_id);
- const GLVolume::CompositeID &cid = selected_volume->composite_id;
- ModelObject *obj = model_objects[cid.object_id];
- ModelVolume *volume = obj->volumes[cid.volume_id];
- if (id == volume->id()) return volume;
- }
- return nullptr;
-}
-
static std::string create_volumes_name(const std::set& ids, const Selection &selection){
assert(!ids.empty());
std::string name;
@@ -88,7 +74,7 @@ static std::string create_volumes_name(const std::set& ids, const Sele
else
name += " + ";
- const ModelVolume *volume = get_volume(id, selection);
+ const ModelVolume *volume = get_selected_volume(id, selection);
assert(volume != nullptr);
name += volume->name;
}
@@ -181,7 +167,7 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi
{
create_gui_cfg();
const Selection &selection = m_parent.get_selection();
- auto act_volume_ids = get_volume_ids(selection);
+ auto act_volume_ids = get_selected_volume_ids(selection);
if (act_volume_ids.empty()) {
stop_worker_thread_request();
close();
@@ -472,7 +458,7 @@ void GLGizmoSimplify::process()
const Selection& selection = m_parent.get_selection();
State::Data its;
for (const auto &id : m_volume_ids) {
- const ModelVolume *volume = get_volume(id, selection);
+ const ModelVolume *volume = get_selected_volume(id, selection);
its[id] = std::make_unique(volume->mesh().its); // copy
}
@@ -549,7 +535,7 @@ void GLGizmoSimplify::apply_simplify() {
for (const auto &item: m_state.result) {
const ObjectID &id = item.first;
const indexed_triangle_set &its = *item.second;
- ModelVolume *volume = get_volume(id, selection);
+ ModelVolume *volume = get_selected_volume(id, selection);
assert(volume != nullptr);
ModelObject *obj = volume->get_object();
@@ -725,7 +711,7 @@ void GLGizmoSimplify::on_render()
const Selection & selection = m_parent.get_selection();
// Check that the GLVolume still belongs to the ModelObject we work on.
- if (m_volume_ids != get_volume_ids(selection)) return;
+ if (m_volume_ids != get_selected_volume_ids(selection)) return;
const ModelObjectPtrs &model_objects = selection.get_model()->objects;
const Selection::IndicesList &volume_idxs = selection.get_volume_idxs();
diff --git a/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp b/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp
index 8aa9e23cb9..e0e19ad52d 100644
--- a/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp
+++ b/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp
@@ -46,10 +46,7 @@ void CreateFontStyleImagesJob::process(Ctl &ctl)
for (ExPolygon &shape : shapes) shape.translate(-bounding_box.min);
// calculate conversion from FontPoint to screen pixels by size of font
- const auto &cn = item.prop.collection_number;
- unsigned int font_index = (cn.has_value()) ? *cn : 0;
- double unit_per_em = item.font.font_file->infos[font_index].unit_per_em;
- double scale = item.prop.size_in_mm / unit_per_em * SHAPE_SCALE * m_input.ppm;
+ double scale = get_text_shape_scale(item.prop, *item.font.font_file);
scales[index] = scale;
//double scale = font_prop.size_in_mm * SCALING_FACTOR;
diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp
index f5c315b30e..88f2624919 100644
--- a/src/slic3r/GUI/Jobs/EmbossJob.cpp
+++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp
@@ -40,8 +40,6 @@ bool check(const DataUpdate &input, bool is_main_thread = false, bool use_surfac
bool check(const CreateSurfaceVolumeData &input, bool is_main_thread = false);
bool check(const UpdateSurfaceVolumeData &input, bool is_main_thread = false);
-template static ExPolygons create_shape(DataBase &input, Fnc was_canceled);
-
//
/// Try to create mesh from text
///
@@ -68,6 +66,13 @@ static TriangleMesh create_default_mesh();
/// Transformation of volume
static void update_volume(TriangleMesh &&mesh, const DataUpdate &data, Transform3d *tr = nullptr);
+///
+/// Update name in right panel
+///
+/// Right panel data
+/// Volume with just changed name
+static void update_name_in_list(const ObjectList &object_list, const ModelVolume &volume);
+
///
/// Add new volume to object
///
@@ -109,7 +114,7 @@ static OrthoProject3d create_emboss_projection(bool is_outside, float emboss, Tr
///
/// Cut surface into triangle mesh
///
-/// (can't be const - cache of font)
+/// (can't be const - cache of font)
/// SurfaceVolume data
/// Check to interupt execution
/// Extruded object from cuted surace
@@ -122,50 +127,49 @@ static bool finalize(bool canceled, std::exception_ptr &eptr, const DataBase &in
class JobException : public std::runtime_error {
public: JobException(const char* message):runtime_error(message){}};
+auto was_canceled(Job::Ctl &ctl, DataBase &base){
+ return [&ctl, &cancel = base.cancel]() -> bool {
+ if (cancel->load())
+ return true;
+ return ctl.was_canceled();
+ };
+}
+
}// namespace priv
/////////////////
/// Create Volume
-CreateVolumeJob::CreateVolumeJob(DataCreateVolume &&input)
- : m_input(std::move(input))
-{
- assert(priv::check(m_input, true));
-}
+CreateVolumeJob::CreateVolumeJob(DataCreateVolume &&input): m_input(std::move(input)){ assert(priv::check(m_input, true)); }
void CreateVolumeJob::process(Ctl &ctl) {
- if (!priv::check(m_input)) throw std::runtime_error("Bad input data for EmbossCreateVolumeJob.");
- auto was_canceled = [&ctl]()->bool { return ctl.was_canceled(); };
- m_result = priv::create_mesh(m_input, was_canceled, ctl);
+ if (!priv::check(m_input))
+ throw std::runtime_error("Bad input data for EmbossCreateVolumeJob.");
+
+ m_result = priv::create_mesh(*m_input.base, priv::was_canceled(ctl, *m_input.base), ctl);
// center result
Vec3f c = m_result.bounding_box().center().cast();
if (!c.isApprox(Vec3f::Zero())) m_result.translate(-c);
}
-
void CreateVolumeJob::finalize(bool canceled, std::exception_ptr &eptr) {
- if (!priv::finalize(canceled, eptr, m_input))
+ if (!priv::finalize(canceled, eptr, *m_input.base))
return;
if (m_result.its.empty())
return priv::create_message(_u8L("Can't create empty volume."));
-
- priv::create_volume(std::move(m_result), m_input.object_id, m_input.volume_type, m_input.trmat, m_input);
+ priv::create_volume(std::move(m_result), m_input.object_id, m_input.volume_type, m_input.trmat, *m_input.base);
}
/////////////////
/// Create Object
-CreateObjectJob::CreateObjectJob(DataCreateObject &&input)
- : m_input(std::move(input))
-{
- assert(priv::check(m_input));
-}
+CreateObjectJob::CreateObjectJob(DataCreateObject &&input): m_input(std::move(input)){ assert(priv::check(m_input)); }
void CreateObjectJob::process(Ctl &ctl)
{
if (!priv::check(m_input))
throw std::runtime_error("Bad input data for EmbossCreateObjectJob.");
- auto was_canceled = [&ctl]()->bool { return ctl.was_canceled(); };
- m_result = priv::create_mesh(m_input, was_canceled, ctl);
+ auto was_canceled = priv::was_canceled(ctl, *m_input.base);
+ m_result = priv::create_mesh(*m_input.base, was_canceled, ctl);
if (was_canceled()) return;
// Create new object
@@ -184,7 +188,9 @@ void CreateObjectJob::process(Ctl &ctl)
// mouse pose is out of build plate so create object in center of plate
bed_coor = bed.centroid().cast();
- double z = m_input.text_configuration.style.prop.emboss / 2;
+ // TODO: need TextConfiguration refactor to work !!!
+ double z = m_input.base->shape.depth / 2;
+
Vec3d offset(bed_coor.x(), bed_coor.y(), z);
offset -= m_result.center();
Transform3d::TranslationType tt(offset.x(), offset.y(), offset.z());
@@ -193,29 +199,49 @@ void CreateObjectJob::process(Ctl &ctl)
void CreateObjectJob::finalize(bool canceled, std::exception_ptr &eptr)
{
- if (!priv::finalize(canceled, eptr, m_input))
+ if (!priv::finalize(canceled, eptr, *m_input.base))
return;
// only for sure
if (m_result.empty())
return priv::create_message(_u8L("Can't create empty object."));
- GUI_App &app = wxGetApp();
- Plater *plater = app.plater();
- ObjectList *obj_list = app.obj_list();
- GLCanvas3D *canvas = plater->canvas3D();
-
+ GUI_App &app = wxGetApp();
+ Plater *plater = app.plater();
plater->take_snapshot(_L("Add Emboss text object"));
- // Create new object and change selection
- bool center = false;
- obj_list->load_mesh_object(std::move(m_result), m_input.volume_name,
- center, &m_input.text_configuration,
- &m_transformation);
+ Model& model = plater->model();
+#ifdef _DEBUG
+ check_model_ids_validity(model);
+#endif /* _DEBUG */
+ {
+ // INFO: inspiration for create object is from ObjectList::load_mesh_object()
+ ModelObject *new_object = model.add_object();
+ new_object->name = m_input.base->volume_name;
+ new_object->add_instance(); // each object should have at list one instance
+
+ ModelVolume *new_volume = new_object->add_volume(std::move(m_result));
+ // set a default extruder value, since user can't add it manually
+ new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
+ // write emboss data into volume
+ m_input.base->write(*new_volume);
+
+ // set transformation
+ Slic3r::Geometry::Transformation tr(m_transformation);
+ new_object->instances.front()->set_transformation(tr);
+ new_object->ensure_on_bed();
+
+ // Actualize right panel and set inside of selection
+ app.obj_list()->paste_objects_into_list({model.objects.size() - 1});
+ }
+#ifdef _DEBUG
+ check_model_ids_validity(model);
+#endif /* _DEBUG */
// When add new object selection is empty.
// When cursor move and no one object is selected than
// Manager::reset_all() So Gizmo could be closed before end of creation object
+ GLCanvas3D *canvas = plater->canvas3D();
GLGizmosManager &manager = canvas->get_gizmos_manager();
if (manager.get_current_type() != GLGizmosManager::Emboss)
manager.open_gizmo(GLGizmosManager::Emboss);
@@ -226,22 +252,15 @@ void CreateObjectJob::finalize(bool canceled, std::exception_ptr &eptr)
/////////////////
/// Update Volume
-UpdateJob::UpdateJob(DataUpdate&& input)
- : m_input(std::move(input))
-{
- assert(priv::check(m_input, true));
-}
+UpdateJob::UpdateJob(DataUpdate&& input): m_input(std::move(input)){ assert(priv::check(m_input, true)); }
void UpdateJob::process(Ctl &ctl)
{
if (!priv::check(m_input))
throw std::runtime_error("Bad input data for EmbossUpdateJob.");
- auto was_canceled = [&ctl, &cancel = m_input.cancel]()->bool {
- if (cancel->load()) return true;
- return ctl.was_canceled();
- };
- m_result = priv::try_create_mesh(m_input, was_canceled);
+ auto was_canceled = priv::was_canceled(ctl, *m_input.base);
+ m_result = priv::try_create_mesh(*m_input.base, was_canceled);
if (was_canceled()) return;
if (m_result.its.empty())
throw priv::JobException(_u8L("Created text volume is empty. Change text or font.").c_str());
@@ -253,7 +272,7 @@ void UpdateJob::process(Ctl &ctl)
void UpdateJob::finalize(bool canceled, std::exception_ptr &eptr)
{
- if (!priv::finalize(canceled, eptr, m_input))
+ if (!priv::finalize(canceled, eptr, *m_input.base))
return;
priv::update_volume(std::move(m_result), m_input);
}
@@ -299,16 +318,14 @@ CreateSurfaceVolumeJob::CreateSurfaceVolumeJob(CreateSurfaceVolumeData &&input)
void CreateSurfaceVolumeJob::process(Ctl &ctl) {
if (!priv::check(m_input))
throw std::runtime_error("Bad input data for CreateSurfaceVolumeJob.");
- // check cancelation of process
- auto was_canceled = [&ctl]() -> bool { return ctl.was_canceled(); };
- m_result = priv::cut_surface(m_input, m_input, was_canceled);
+ m_result = priv::cut_surface(*m_input.base, m_input, priv::was_canceled(ctl, *m_input.base));
}
void CreateSurfaceVolumeJob::finalize(bool canceled, std::exception_ptr &eptr) {
- if (!priv::finalize(canceled, eptr, m_input))
+ if (!priv::finalize(canceled, eptr, *m_input.base))
return;
priv::create_volume(std::move(m_result), m_input.object_id,
- m_input.volume_type, m_input.text_tr, m_input);
+ m_input.volume_type, m_input.transform, *m_input.base);
}
/////////////////
@@ -323,23 +340,17 @@ void UpdateSurfaceVolumeJob::process(Ctl &ctl)
{
if (!priv::check(m_input))
throw std::runtime_error("Bad input data for UseSurfaceJob.");
-
- // check cancelation of process
- auto was_canceled = [&ctl, &cancel = m_input.cancel]()->bool {
- if (cancel->load()) return true;
- return ctl.was_canceled();
- };
- m_result = priv::cut_surface(m_input, m_input, was_canceled);
+ m_result = priv::cut_surface(*m_input.base, m_input, priv::was_canceled(ctl, *m_input.base));
}
void UpdateSurfaceVolumeJob::finalize(bool canceled, std::exception_ptr &eptr)
{
- if (!priv::finalize(canceled, eptr, m_input))
+ if (!priv::finalize(canceled, eptr, *m_input.base))
return;
// when start using surface it is wanted to move text origin on surface of model
// also when repeteadly move above surface result position should match
- Transform3d *tr = &m_input.text_tr;
+ Transform3d *tr = &m_input.transform;
priv::update_volume(std::move(m_result), m_input, tr);
}
@@ -348,23 +359,25 @@ void UpdateSurfaceVolumeJob::finalize(bool canceled, std::exception_ptr &eptr)
bool priv::check(const DataBase &input, bool check_fontfile, bool use_surface)
{
bool res = true;
- if (check_fontfile) {
- assert(input.font_file.has_value());
- res &= input.font_file.has_value();
- }
- assert(!input.text_configuration.fix_3mf_tr.has_value());
- res &= !input.text_configuration.fix_3mf_tr.has_value();
- assert(!input.text_configuration.text.empty());
- res &= !input.text_configuration.text.empty();
+ //if (check_fontfile) {
+ // assert(input.font_file.has_value());
+ // res &= input.font_file.has_value();
+ //}
+ //assert(!input.text_configuration.fix_3mf_tr.has_value());
+ //res &= !input.text_configuration.fix_3mf_tr.has_value();
+ //assert(!input.text_configuration.text.empty());
+ //res &= !input.text_configuration.text.empty();
assert(!input.volume_name.empty());
res &= !input.volume_name.empty();
- assert(input.text_configuration.style.prop.use_surface == use_surface);
- res &= input.text_configuration.style.prop.use_surface == use_surface;
+ //assert(input.text_configuration.style.prop.use_surface == use_surface);
+ //res &= input.text_configuration.style.prop.use_surface == use_surface;
return res;
}
bool priv::check(const DataCreateVolume &input, bool is_main_thread) {
bool check_fontfile = false;
- bool res = check((DataBase) input, check_fontfile);
+ assert(input.base != nullptr);
+ bool res = input.base != nullptr;
+ res &= check(*input.base, check_fontfile);
assert(input.volume_type != ModelVolumeType::INVALID);
res &= input.volume_type != ModelVolumeType::INVALID;
assert(input.object_id.id >= 0);
@@ -373,7 +386,9 @@ bool priv::check(const DataCreateVolume &input, bool is_main_thread) {
}
bool priv::check(const DataCreateObject &input) {
bool check_fontfile = false;
- bool res = check((DataBase) input, check_fontfile);
+ assert(input.base != nullptr);
+ bool res = input.base != nullptr;
+ res &= check(*input.base, check_fontfile);
assert(input.screen_coor.x() >= 0.);
res &= input.screen_coor.x() >= 0.;
assert(input.screen_coor.y() >= 0.);
@@ -384,66 +399,49 @@ bool priv::check(const DataCreateObject &input) {
}
bool priv::check(const DataUpdate &input, bool is_main_thread, bool use_surface){
bool check_fontfile = true;
- bool res = check((DataBase) input, check_fontfile, use_surface);
+ assert(input.base != nullptr);
+ bool res = input.base != nullptr;
+ res &= check(*input.base, check_fontfile, use_surface);
assert(input.volume_id.id >= 0);
res &= input.volume_id.id >= 0;
if (is_main_thread)
assert(get_volume(wxGetApp().model().objects, input.volume_id) != nullptr);
- assert(input.cancel != nullptr);
- res &= input.cancel != nullptr;
+ assert(input.base->cancel != nullptr);
+ res &= input.base->cancel != nullptr;
if (is_main_thread)
- assert(!input.cancel->load());
+ assert(!input.base->cancel->load());
return res;
}
bool priv::check(const CreateSurfaceVolumeData &input, bool is_main_thread)
{
bool use_surface = true;
- bool res = check((DataBase)input, is_main_thread, use_surface);
+ assert(input.base != nullptr);
+ bool res = input.base != nullptr;
+ res &= check(*input.base, is_main_thread, use_surface);
assert(!input.sources.empty());
res &= !input.sources.empty();
return res;
}
bool priv::check(const UpdateSurfaceVolumeData &input, bool is_main_thread){
bool use_surface = true;
- bool res = check((DataUpdate)input, is_main_thread, use_surface);
+ assert(input.base != nullptr);
+ bool res = input.base != nullptr;
+ res &= check(*input.base, is_main_thread, use_surface);
assert(!input.sources.empty());
res &= !input.sources.empty();
return res;
}
-template
-ExPolygons priv::create_shape(DataBase &input, Fnc was_canceled) {
- FontFileWithCache &font = input.font_file;
- const TextConfiguration &tc = input.text_configuration;
- const char *text = tc.text.c_str();
- const FontProp &prop = tc.style.prop;
-
- assert(font.has_value());
- if (!font.has_value())
- return {};
-
- return text2shapes(font, text, prop, was_canceled);
-}
-
template
-TriangleMesh priv::try_create_mesh(DataBase &input, Fnc was_canceled)
+TriangleMesh priv::try_create_mesh(DataBase &base, Fnc was_canceled)
{
- ExPolygons shapes = priv::create_shape(input, was_canceled);
- if (shapes.empty()) return {};
- if (was_canceled()) return {};
-
- const FontProp &prop = input.text_configuration.style.prop;
- const std::optional &cn = prop.collection_number;
- unsigned int font_index = (cn.has_value()) ? *cn : 0;
- const FontFileWithCache &font = input.font_file;
- assert(font_index < font.font_file->infos.size());
- int unit_per_em = font.font_file->infos[font_index].unit_per_em;
- float scale = prop.size_in_mm / unit_per_em;
- float depth = prop.emboss / scale;
+ const EmbossShape& shape = base.create_shape();
+ if (shape.shapes.empty()) return {};
+ float depth = shape.depth / shape.scale;
auto projectZ = std::make_unique(depth);
- ProjectScale project(std::move(projectZ), scale);
+ ProjectScale project(std::move(projectZ), shape.scale);
if (was_canceled()) return {};
- return TriangleMesh(polygons2model(shapes, project));
+ return TriangleMesh(polygons2model(shape.shapes, project));
}
template
@@ -451,11 +449,8 @@ TriangleMesh priv::create_mesh(DataBase &input, Fnc was_canceled, Job::Ctl& ctl)
{
// It is neccessary to create some shape
// Emboss text window is opened by creation new emboss text object
- TriangleMesh result;
- if (input.font_file.has_value()) {
- result = try_create_mesh(input, was_canceled);
- if (was_canceled()) return {};
- }
+ TriangleMesh result = try_create_mesh(input, was_canceled);
+ if (was_canceled()) return {};
if (result.its.empty()) {
result = priv::create_default_mesh();
@@ -483,16 +478,13 @@ TriangleMesh priv::create_default_mesh()
return triangle_mesh;
}
-void UpdateJob::update_volume(ModelVolume *volume,
- TriangleMesh &&mesh,
- const TextConfiguration &text_configuration,
- const std::string &volume_name)
+void UpdateJob::update_volume(ModelVolume *volume, TriangleMesh &&mesh, const DataBase &base)
{
// check inputs
bool is_valid_input =
volume != nullptr &&
!mesh.empty() &&
- !volume_name.empty();
+ !base.volume_name.empty();
assert(is_valid_input);
if (!is_valid_input) return;
@@ -501,24 +493,17 @@ void UpdateJob::update_volume(ModelVolume *volume,
volume->set_new_unique_id();
volume->calculate_convex_hull();
volume->get_object()->invalidate_bounding_box();
- volume->text_configuration = text_configuration;
- // discard information about rotation, should not be stored in volume
- volume->text_configuration->style.prop.angle.reset();
+ // write data from base into volume
+ base.write(*volume);
- GUI_App &app = wxGetApp(); // may be move to input
- GLCanvas3D *canvas = app.plater()->canvas3D();
- const Selection &selection = canvas->get_selection();
- const GLVolume *gl_volume = selection.get_volume(*selection.get_volume_idxs().begin());
- int object_idx = gl_volume->object_idx();
-
- if (volume->name != volume_name) {
- volume->name = volume_name;
-
- // update volume name in right panel( volume / object name)
- int volume_idx = gl_volume->volume_idx();
- ObjectList *obj_list = app.obj_list();
- obj_list->update_name_in_list(object_idx, volume_idx);
+ GUI_App &app = wxGetApp(); // may be move to input
+ if (volume->name != base.volume_name) {
+ volume->name = base.volume_name;
+
+ ObjectList *obj_list = app.obj_list();
+ if (obj_list != nullptr)
+ priv::update_name_in_list(*obj_list, *volume);
}
// When text is object.
@@ -528,6 +513,8 @@ void UpdateJob::update_volume(ModelVolume *volume,
volume->get_object()->ensure_on_bed();
// redraw scene
+ GLCanvas3D *canvas = app.plater()->canvas3D();
+
bool refresh_immediately = false;
canvas->reload_scene(refresh_immediately);
@@ -535,21 +522,53 @@ void UpdateJob::update_volume(ModelVolume *volume,
canvas->post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
}
+void priv::update_name_in_list(const ObjectList &object_list, const ModelVolume &volume)
+{
+ const ModelObjectPtrs *objects_ptr = object_list.objects();
+ if (objects_ptr == nullptr)
+ return;
+
+ const ModelObjectPtrs &objects = *objects_ptr;
+ const ModelObject *object = volume.get_object();
+ const ObjectID& object_id = object->id();
+
+ // search for index of object
+ int object_index = -1;
+ for (size_t i = 0; i < objects.size(); ++i)
+ if (objects[i]->id() == object_id) {
+ object_index = i;
+ break;
+ }
+
+ const ModelVolumePtrs volumes = object->volumes;
+ const ObjectID& volume_id = volume.id();
+
+ // search for index of volume
+ int volume_index = -1;
+ for (size_t i = 0; i < volumes.size(); ++i)
+ if (volumes[i]->id() == volume_id) {
+ volume_index = i;
+ break;
+ }
+
+ if (object_index < 0 || volume_index < 0)
+ return;
+
+ object_list.update_name_in_list(object_index, volume_index);
+}
+
void priv::update_volume(TriangleMesh &&mesh, const DataUpdate &data, Transform3d* tr)
{
// for sure that some object will be created
if (mesh.its.empty())
return create_message("Empty mesh can't be created.");
- Plater *plater = wxGetApp().plater();
- GLCanvas3D *canvas = plater->canvas3D();
+ Plater *plater = wxGetApp().plater();
+ // Check gizmo is still open otherwise job should be canceled
+ assert(plater->canvas3D()->get_gizmos_manager().get_current_type() == GLGizmosManager::Emboss ||
+ plater->canvas3D()->get_gizmos_manager().get_current_type() == GLGizmosManager::Svg);
- // Check emboss gizmo is still open
- GLGizmosManager &manager = canvas->get_gizmos_manager();
- if (manager.get_current_type() != GLGizmosManager::Emboss)
- return;
-
- std::string snap_name = GUI::format(_L("Text: %1%"), data.text_configuration.text);
+ std::string snap_name = GUI::format(_L("Change: %1%"), data.base->volume_name);
Plater::TakeSnapshot snapshot(plater, snap_name, UndoRedo::SnapshotType::GizmoAction);
ModelVolume *volume = get_volume(plater->model().objects, data.volume_id);
@@ -567,7 +586,7 @@ void priv::update_volume(TriangleMesh &&mesh, const DataUpdate &data, Transform3
volume->set_transformation(volume->get_matrix() * tc->fix_3mf_tr->inverse());
}
- UpdateJob::update_volume(volume, std::move(mesh), data.text_configuration, data.volume_name);
+ UpdateJob::update_volume(volume, std::move(mesh), *data.base);
}
void priv::create_volume(
@@ -609,20 +628,15 @@ void priv::create_volume(
volume->set_mesh(std::move(mesh));
volume->calculate_convex_hull();
-
// set a default extruder value, since user can't add it manually
volume->config.set_key_value("extruder", new ConfigOptionInt(0));
// do not allow model reload from disk
volume->source.is_from_builtin_objects = true;
- volume->name = data.volume_name; // copy
- volume->text_configuration = data.text_configuration; // copy
-
- // discard information about rotation, should not be stored in volume
- volume->text_configuration->style.prop.angle.reset();
-
+ volume->name = data.volume_name; // copy
volume->set_transformation(trmat);
+ data.write(*volume);
// update printable state on canvas
if (type == ModelVolumeType::MODEL_PART) {
@@ -635,7 +649,7 @@ void priv::create_volume(
// change name of volume in right panel
// select only actual volume
// when new volume is created change selection to this volume
- auto add_to_selection = [volume](const ModelVolume *vol) { return vol == volume; };
+ auto add_to_selection = [volume](const ModelVolume *vol) { return vol == volume; };
wxDataViewItemArray sel = obj_list->reorder_volumes_and_get_selection(object_idx, add_to_selection);
if (!sel.IsEmpty()) obj_list->select_item(sel.front());
@@ -698,24 +712,21 @@ OrthoProject3d priv::create_emboss_projection(
}
// input can't be const - cache of font
-TriangleMesh priv::cut_surface(DataBase& input1, const SurfaceVolumeData& input2, std::function was_canceled)
+TriangleMesh priv::cut_surface(DataBase& base, const SurfaceVolumeData& input2, std::function was_canceled)
{
- ExPolygons shapes = create_shape(input1, was_canceled);
+ EmbossShape& emboss_shape = base.create_shape();
+ ExPolygons& shapes = emboss_shape.shapes;
if (shapes.empty())
throw JobException(_u8L("Font doesn't have any shape for given text.").c_str());
if (was_canceled()) return {};
// Define alignment of text - left, right, center, top bottom, ....
- BoundingBox bb = get_extents(shapes);
+ BoundingBox bb = get_extents(shapes);
Point projection_center = bb.center();
for (ExPolygon &shape : shapes) shape.translate(-projection_center);
bb.translate(-projection_center);
- const FontFile &ff = *input1.font_file.font_file;
- const FontProp &fp = input1.text_configuration.style.prop;
- double shape_scale = get_shape_scale(fp, ff);
-
const SurfaceVolumeData::ModelSources &sources = input2.sources;
const SurfaceVolumeData::ModelSource *biggest = nullptr;
@@ -726,9 +737,9 @@ TriangleMesh priv::cut_surface(DataBase& input1, const SurfaceVolumeData& input2
itss.reserve(sources.size());
for (const SurfaceVolumeData::ModelSource &s : sources) {
Transform3d mesh_tr_inv = s.tr.inverse();
- Transform3d cut_projection_tr = mesh_tr_inv * input2.text_tr;
+ Transform3d cut_projection_tr = mesh_tr_inv * input2.transform;
std::pair z_range{0., 1.};
- OrthoProject cut_projection = create_projection_for_cut(cut_projection_tr, shape_scale, z_range);
+ OrthoProject cut_projection = create_projection_for_cut(cut_projection_tr, emboss_shape.scale, z_range);
// copy only part of source model
indexed_triangle_set its = its_cut_AoI(s.mesh->its, bb, cut_projection);
if (its.indices.empty()) continue;
@@ -745,7 +756,7 @@ TriangleMesh priv::cut_surface(DataBase& input1, const SurfaceVolumeData& input2
throw JobException(_u8L("There is no volume in projection direction.").c_str());
Transform3d tr_inv = biggest->tr.inverse();
- Transform3d cut_projection_tr = tr_inv * input2.text_tr;
+ Transform3d cut_projection_tr = tr_inv * input2.transform;
size_t itss_index = s_to_itss[biggest - &sources.front()];
BoundingBoxf3 mesh_bb = bounding_box(itss[itss_index]);
@@ -767,10 +778,10 @@ TriangleMesh priv::cut_surface(DataBase& input1, const SurfaceVolumeData& input2
Transform3d emboss_tr = cut_projection_tr.inverse();
BoundingBoxf3 mesh_bb_tr = mesh_bb.transformed(emboss_tr);
std::pair z_range{mesh_bb_tr.min.z(), mesh_bb_tr.max.z()};
- OrthoProject cut_projection = create_projection_for_cut(cut_projection_tr, shape_scale, z_range);
+ OrthoProject cut_projection = create_projection_for_cut(cut_projection_tr, emboss_shape.scale, z_range);
float projection_ratio = (-z_range.first + safe_extension) / (z_range.second - z_range.first + 2 * safe_extension);
- bool is_text_reflected = Slic3r::has_reflection(input2.text_tr);
+ bool is_text_reflected = Slic3r::has_reflection(input2.transform);
if (is_text_reflected) {
// revert order of points in expolygons
// CW --> CCW
@@ -794,8 +805,8 @@ TriangleMesh priv::cut_surface(DataBase& input1, const SurfaceVolumeData& input2
if (cut.empty()) throw JobException(_u8L("There is no valid surface for text projection.").c_str());
if (was_canceled()) return {};
- // !! Projection needs to transform cut
- OrthoProject3d projection = create_emboss_projection(input2.is_outside, fp.emboss, emboss_tr, cut);
+ // !! Projection needs to transform cut
+ OrthoProject3d projection = create_emboss_projection(input2.is_outside, emboss_shape.depth, emboss_tr, cut);
indexed_triangle_set new_its = cut2model(cut, projection);
assert(!new_its.empty());
if (was_canceled()) return {};
diff --git a/src/slic3r/GUI/Jobs/EmbossJob.hpp b/src/slic3r/GUI/Jobs/EmbossJob.hpp
index d3896c0a65..d909291368 100644
--- a/src/slic3r/GUI/Jobs/EmbossJob.hpp
+++ b/src/slic3r/GUI/Jobs/EmbossJob.hpp
@@ -4,7 +4,8 @@
#include
#include
#include
-#include
+#include "libslic3r/Emboss.hpp"
+#include "libslic3r/EmbossShape.hpp"
#include "slic3r/Utils/RaycastManager.hpp"
#include "slic3r/GUI/Camera.hpp"
#include "Job.hpp"
@@ -17,20 +18,43 @@ class TriangleMesh;
namespace Slic3r::GUI::Emboss {
///
-/// Base data holder for embossing
+/// Base data hold data for create emboss shape
///
-struct DataBase
+class DataBase
{
- // Keep pointer on Data of font (glyph shapes)
- Slic3r::Emboss::FontFileWithCache font_file;
- // font item is not used for create object
- TextConfiguration text_configuration;
- // new volume name created from text
+public:
+ DataBase(std::string volume_name, std::shared_ptr> cancel) : volume_name(volume_name), cancel(std::move(cancel)) {}
+ DataBase(std::string volume_name, std::shared_ptr> cancel, EmbossShape shape)
+ : volume_name(volume_name), cancel(std::move(cancel)), shape(std::move(shape))
+ {}
+ virtual ~DataBase() {}
+
+ ///
+ /// Create shape
+ /// e.g. Text extract glyphs from font
+ /// Not 'const' function because it could modify shape
+ ///
+ virtual EmbossShape &create_shape() { return shape; };
+
+ ///
+ /// Write data how to reconstruct shape to volume
+ ///
+ /// Data object for store emboss params
+ virtual void write(ModelVolume &volume) const
+ {
+ volume.name = volume_name;
+ volume.emboss_shape = shape;
+ };
+
+ // new volume name
std::string volume_name;
// flag that job is canceled
// for time after process.
std::shared_ptr> cancel;
+
+ // shape to emboss
+ EmbossShape shape;
};
///
@@ -38,8 +62,11 @@ struct DataBase
/// Volume is created on the surface of existing volume in object.
/// NOTE: EmbossDataBase::font_file doesn't have to be valid !!!
///
-struct DataCreateVolume : public DataBase
+struct DataCreateVolume
{
+ // Hold data about shape
+ std::unique_ptr base;
+
// define embossed volume type
ModelVolumeType volume_type;
@@ -71,8 +98,11 @@ public:
/// Object is placed on bed under screen coor
/// OR to center of scene when it is out of bed shape
///
-struct DataCreateObject : public DataBase
+struct DataCreateObject
{
+ // Hold data about shape
+ std::unique_ptr base;
+
// define position on screen where to create object
Vec2d screen_coor;
@@ -101,8 +131,11 @@ public:
///
/// Hold neccessary data to update embossed text object in job
///
-struct DataUpdate : public DataBase
+struct DataUpdate
{
+ // Hold data about shape
+ std::unique_ptr base;
+
// unique identifier of volume to change
ObjectID volume_id;
};
@@ -140,18 +173,14 @@ public:
///
/// Volume to be updated
/// New Triangle mesh for volume
- /// Parametric description of volume
- /// Name of volume
- static void update_volume(ModelVolume *volume,
- TriangleMesh &&mesh,
- const TextConfiguration &text_configuration,
- const std::string &volume_name);
+ /// Data to write into volume
+ static void update_volume(ModelVolume *volume, TriangleMesh &&mesh, const DataBase &base);
};
struct SurfaceVolumeData
{
- // Transformation of text volume inside of object
- Transform3d text_tr;
+ // Transformation of volume inside of object
+ Transform3d transform;
// Define projection move
// True (raised) .. move outside from surface
@@ -172,7 +201,10 @@ struct SurfaceVolumeData
///
/// Hold neccessary data to create(cut) volume from surface object in job
///
-struct CreateSurfaceVolumeData : public DataBase, public SurfaceVolumeData{
+struct CreateSurfaceVolumeData : public SurfaceVolumeData{
+ // Hold data about shape
+ std::unique_ptr base;
+
// define embossed volume type
ModelVolumeType volume_type;
diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp
index 2b77fe7ff4..e55a80a107 100644
--- a/src/slic3r/GUI/Selection.cpp
+++ b/src/slic3r/GUI/Selection.cpp
@@ -3435,5 +3435,30 @@ const GLVolume *get_selected_gl_volume(const Selection &selection)
return selection.get_volume(volume_idx);
}
+ModelVolume *get_selected_volume(const ObjectID &volume_id, const Selection &selection) {
+ const Selection::IndicesList &volume_ids = selection.get_volume_idxs();
+ const ModelObjectPtrs &model_objects = selection.get_model()->objects;
+ for (auto id : volume_ids) {
+ const GLVolume *selected_volume = selection.get_volume(id);
+ const GLVolume::CompositeID &cid = selected_volume->composite_id;
+ ModelObject *obj = model_objects[cid.object_id];
+ ModelVolume *volume = obj->volumes[cid.volume_id];
+ if (volume_id == volume->id())
+ return volume;
+ }
+ return nullptr;
+}
+
+ModelVolume *get_volume(const ObjectID &volume_id, const Selection &selection) {
+ const ModelObjectPtrs &objects = selection.get_model()->objects;
+ for (const ModelObject *object : objects) {
+ for (ModelVolume *volume : object->volumes) {
+ if (volume->id() == volume_id)
+ return volume;
+ }
+ }
+ return nullptr;
+}
+
} // namespace GUI
} // namespace Slic3r
diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp
index d3f4567027..e34e0e7732 100644
--- a/src/slic3r/GUI/Selection.hpp
+++ b/src/slic3r/GUI/Selection.hpp
@@ -18,6 +18,7 @@ class Shader;
class Model;
class ModelObject;
class ModelVolume;
+class ObjectID;
class GLVolume;
class GLArrow;
class GLCurvedArrow;
@@ -524,9 +525,12 @@ private:
#endif // ENABLE_WORLD_COORDINATE
};
-ModelVolume *get_selected_volume(const Selection &selection);
+ModelVolume *get_selected_volume (const Selection &selection);
const GLVolume *get_selected_gl_volume(const Selection &selection);
+ModelVolume *get_selected_volume (const ObjectID &volume_id, const Selection &selection);
+ModelVolume *get_volume (const ObjectID &volume_id, const Selection &selection);
+
} // namespace GUI
} // namespace Slic3r
diff --git a/tests/libslic3r/test_cut_surface.cpp b/tests/libslic3r/test_cut_surface.cpp
index ffc762b865..d9376195b5 100644
--- a/tests/libslic3r/test_cut_surface.cpp
+++ b/tests/libslic3r/test_cut_surface.cpp
@@ -23,7 +23,8 @@ TEST_CASE("Cut character from surface", "[]")
Transform3d tr = Transform3d::Identity();
tr.translate(Vec3d(0., 0., -z_depth));
- tr.scale(Emboss::SHAPE_SCALE);
+ double text_shape_scale = 0.001; // Emboss.cpp --> SHAPE_SCALE
+ tr.scale(text_shape_scale);
Emboss::OrthoProject cut_projection(tr, Vec3d(0., 0., z_depth));
auto object = its_make_cube(782 - 49 + 50, 724 + 10 + 50, 5);
@@ -158,7 +159,7 @@ TEST_CASE("CutSurface in 3mf", "[Emboss]")
FontProp fp = tc.style.prop;
ExPolygons shapes = Emboss::text2shapes(ff, tc.text.c_str(), fp);
- double shape_scale = Emboss::get_shape_scale(fp, *ff.font_file);
+ double shape_scale = Emboss::get_text_shape_scale(fp, *ff.font_file);
Emboss::OrthoProject projection = create_projection_for_cut(
cut_projection_tr, shape_scale, get_extents(shapes), z_range);
diff --git a/tests/libslic3r/test_emboss.cpp b/tests/libslic3r/test_emboss.cpp
index 8ab482f9ce..f087dbf3a2 100644
--- a/tests/libslic3r/test_emboss.cpp
+++ b/tests/libslic3r/test_emboss.cpp
@@ -258,7 +258,9 @@ TEST_CASE("Heal of 'i' in ALIENATO.TTF", "[Emboss]")
auto a = heal_and_check(polygons);
Polygons scaled_shape = polygons; // copy
- scale(scaled_shape, 1 / Emboss::SHAPE_SCALE);
+
+ double text_shape_scale = 0.001; // Emboss.cpp --> SHAPE_SCALE
+ scale(scaled_shape, 1 / text_shape_scale);
auto b = heal_and_check(scaled_shape);
// different scale
@@ -468,7 +470,8 @@ TEST_CASE("Cut surface", "[]")
Transform3d tr = Transform3d::Identity();
tr.translate(Vec3d(0., 0., -z_depth));
- tr.scale(Emboss::SHAPE_SCALE);
+ double text_shape_scale = 0.001; // Emboss.cpp --> SHAPE_SCALE
+ tr.scale(text_shape_scale);
Emboss::OrthoProject cut_projection(tr, Vec3d(0., 0., z_depth));
auto object = its_make_cube(782 - 49 + 50, 724 + 10 + 50, 5);
@@ -527,8 +530,8 @@ TEST_CASE("UndoRedo TextConfiguration serialization", "[Emboss]")
TEST_CASE("UndoRedo EmbossShape serialization", "[Emboss]")
{
EmbossShape emboss;
- emboss.shape = {{{0, 0}, {10, 0}, {10, 10}, {0, 10}}, {{5, 5}, {6, 5}, {6, 6}, {5, 6}}};
- emboss.shape_scale = 2.;
+ emboss.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;
@@ -549,8 +552,8 @@ TEST_CASE("UndoRedo EmbossShape serialization", "[Emboss]")
cereal::BinaryInputArchive iarchive(ss); // Create an input archive
iarchive(emboss_loaded);
}
- CHECK(emboss.shape == emboss_loaded.shape);
- CHECK(emboss.shape_scale == emboss_loaded.shape_scale);
+ CHECK(emboss.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);