diff --git a/src/libslic3r/CutSurface.cpp b/src/libslic3r/CutSurface.cpp
index 6c00ed33d..fa61f6ce3 100644
--- a/src/libslic3r/CutSurface.cpp
+++ b/src/libslic3r/CutSurface.cpp
@@ -152,7 +152,7 @@ struct IntersectingElement
/// CGAL mesh - half edge mesh
CutMesh to_cgal(const indexed_triangle_set &its);
-using Project = Emboss::IProject;
+using Project = Emboss::IProjection;
///
/// Covert 2d shape (e.g. Glyph) to CGAL model
///
@@ -434,9 +434,9 @@ void store(const SurfaceCuts &cut, const std::string &dir);
} // namespace privat
-SurfaceCuts Slic3r::cut_surface(const indexed_triangle_set &model,
+SurfaceCut Slic3r::cut_surface(const indexed_triangle_set &model,
const ExPolygons &shapes,
- const Emboss::IProject &projection)
+ const Emboss::IProjection &projection)
{
priv::CutMesh cgal_model = priv::to_cgal(model);
@@ -519,12 +519,11 @@ SurfaceCuts Slic3r::cut_surface(const indexed_triangle_set &model,
priv::store(result, DEBUG_OUTPUT_DIR + "cuts/"); // only debug
#endif // DEBUG_OUTPUT_DIR
- // TODO: Filter surfaceCuts to only the top most.
- return result;
+ return merge(std::move(result));
}
-indexed_triangle_set Slic3r::cuts2model(const SurfaceCuts &cuts,
- const Emboss::IProject &projection)
+indexed_triangle_set Slic3r::cuts2model(const SurfaceCuts &cuts,
+ const Emboss::IProject3f &projection)
{
indexed_triangle_set result;
size_t count_vertices = 0;
@@ -604,8 +603,8 @@ indexed_triangle_set Slic3r::cuts2model(const SurfaceCuts &cuts,
return result;
}
-indexed_triangle_set Slic3r::cut2model(const SurfaceCut &cut,
- const Emboss::IProject &projection)
+indexed_triangle_set Slic3r::cut2model(const SurfaceCut &cut,
+ const Emboss::IProject3f &projection)
{
assert(!cut.empty());
size_t count_vertices = cut.vertices.size() * 2;
@@ -707,7 +706,7 @@ priv::CutMesh priv::to_cgal(const ExPolygons &shapes,
indices.reserve(polygon.points.size() * 2);
size_t num_vertices_old = result.number_of_vertices();
for (const Point &p2 : polygon.points) {
- auto p = projection.project(p2);
+ auto p = projection.create_front_back(p2);
CutMesh::Point v_first{p.first.x(), p.first.y(), p.first.z()};
CutMesh::Point v_second{p.second.x(), p.second.y(), p.second.z()};
@@ -1388,7 +1387,7 @@ void priv::filter_cuts(CutAOIs &cuts,
// compare distances of vertices
Point p = get_point(*i);
- Vec3f source_point = projection.project(p).first;
+ Vec3f source_point = projection.create_front_back(p).first;
const auto &prev = mesh.point(ci.vi);
Vec3f prev_point(prev.x(), prev.y(), prev.z());
float prev_sq_norm = (source_point - prev_point).squaredNorm();
diff --git a/src/libslic3r/CutSurface.hpp b/src/libslic3r/CutSurface.hpp
index 0b65bccd2..a76d16b23 100644
--- a/src/libslic3r/CutSurface.hpp
+++ b/src/libslic3r/CutSurface.hpp
@@ -57,9 +57,9 @@ SurfaceCut merge(SurfaceCuts&& cuts);
/// Multiple shape to cut from model
/// Define transformation from 2d coordinate of shape to 3d
/// Cutted surface from model
-SurfaceCuts cut_surface(const indexed_triangle_set &model,
- const ExPolygons &shapes,
- const Emboss::IProject &projection);
+SurfaceCut cut_surface(const indexed_triangle_set &model,
+ const ExPolygons &shapes,
+ const Emboss::IProjection &projection);
///
/// Create model from surface cuts by projection
@@ -67,16 +67,16 @@ SurfaceCuts cut_surface(const indexed_triangle_set &model,
/// Surfaces from model
/// Way of emboss
/// Mesh
-indexed_triangle_set cuts2model(const SurfaceCuts &cuts,
- const Emboss::IProject &projection);
+indexed_triangle_set cuts2model(const SurfaceCuts &cuts,
+ const Emboss::IProject3f &projection);
///
/// Create model from surface cuts by projection
///
/// Surface from model with outlines
/// Way of emboss
/// Mesh
-indexed_triangle_set cut2model(const SurfaceCut &cut,
- const Emboss::IProject &projection);
+indexed_triangle_set cut2model(const SurfaceCut &cut,
+ const Emboss::IProject3f &projection);
} // namespace Slic3r
diff --git a/src/libslic3r/Emboss.cpp b/src/libslic3r/Emboss.cpp
index 07be4e026..b9741cfe2 100644
--- a/src/libslic3r/Emboss.cpp
+++ b/src/libslic3r/Emboss.cpp
@@ -769,7 +769,7 @@ std::string Emboss::create_range_text(const std::string &text,
indexed_triangle_set Emboss::polygons2model(const ExPolygons &shape2d,
- const IProject &projection)
+ const IProjection &projection)
{
indexed_triangle_set result;
size_t count_point = count_points(shape2d);
@@ -782,7 +782,7 @@ indexed_triangle_set Emboss::polygons2model(const ExPolygons &shape2d,
auto insert_point = [&projection, &front_points,
&back_points](const Polygon& polygon) {
for (const Point& p : polygon.points) {
- auto p2 = projection.project(p);
+ auto p2 = projection.create_front_back(p);
front_points.emplace_back(p2.first);
back_points.emplace_back(p2.second);
}
@@ -832,7 +832,7 @@ indexed_triangle_set Emboss::polygons2model(const ExPolygons &shape2d,
return result;
}
-std::pair Emboss::ProjectZ::project(const Point &p) const
+std::pair Emboss::ProjectZ::create_front_back(const Point &p) const
{
Vec3f front(
static_cast(p.x() * SHAPE_SCALE),
@@ -902,7 +902,7 @@ Transform3d Emboss::create_transformation_onto_surface(const Vec3f &position,
// OrthoProject
-std::pair Emboss::OrthoProject::project(const Point &p) const {
+std::pair Emboss::OrthoProject::create_front_back(const Point &p) const {
Vec3d front(p.x(), p.y(), 0.);
Vec3f front_tr = (m_matrix * front).cast();
return std::make_pair(front_tr, project(front_tr));
diff --git a/src/libslic3r/Emboss.hpp b/src/libslic3r/Emboss.hpp
index 143890108..1467eaef9 100644
--- a/src/libslic3r/Emboss.hpp
+++ b/src/libslic3r/Emboss.hpp
@@ -183,23 +183,12 @@ public:
static std::string create_range_text(const std::string &text, const FontFile &font, unsigned int font_index, bool* exist_unknown = nullptr);
///
- /// Project 2d point into space
- /// Could be plane, sphere, cylindric, ...
+ /// Project spatial point
///
- class IProject
+ class IProject3f
{
public:
- virtual ~IProject() = default;
- ///
- /// convert 2d point to 3d point
- ///
- /// 2d coordinate
- ///
- /// first - front spatial point
- /// second - back spatial point
- ///
- virtual std::pair project(const Point &p) const = 0;
-
+ virtual ~IProject3f() = default;
///
/// Move point with respect to projection direction
/// e.g. Orthogonal projection will move with point by direction
@@ -210,13 +199,33 @@ public:
virtual Vec3f project(const Vec3f &point) const = 0;
};
+ ///
+ /// Project 2d point into space
+ /// Could be plane, sphere, cylindric, ...
+ ///
+ class IProjection : public IProject3f
+ {
+ public:
+ virtual ~IProjection() = default;
+
+ ///
+ /// convert 2d point to 3d points
+ ///
+ /// 2d coordinate
+ ///
+ /// first - front spatial point
+ /// second - back spatial point
+ ///
+ virtual std::pair create_front_back(const Point &p) const = 0;
+ };
+
///
/// Create triangle model for text
///
/// text or image
/// Define transformation from 2d to 3d(orientation, position, scale, ...)
/// Projected shape into space
- static indexed_triangle_set polygons2model(const ExPolygons &shape2d, const IProject& projection);
+ static indexed_triangle_set polygons2model(const ExPolygons &shape2d, const IProjection& projection);
///
/// Create transformation for emboss text object to lay on surface point
@@ -228,29 +237,29 @@ public:
static Transform3d create_transformation_onto_surface(
const Vec3f &position, const Vec3f &normal, float up_limit = 0.9f);
- class ProjectZ : public IProject
+ class ProjectZ : public IProjection
{
public:
ProjectZ(float depth) : m_depth(depth) {}
// Inherited via IProject
- std::pair project(const Point &p) const override;
+ std::pair create_front_back(const Point &p) const override;
Vec3f project(const Vec3f &point) const override;
float m_depth;
};
- class ProjectScale : public IProject
+ class ProjectScale : public IProjection
{
- std::unique_ptr core;
+ std::unique_ptr core;
float m_scale;
public:
- ProjectScale(std::unique_ptr core, float scale)
+ ProjectScale(std::unique_ptr core, float scale)
: core(std::move(core)), m_scale(scale)
{}
// Inherited via IProject
- std::pair project(const Point &p) const override
+ std::pair create_front_back(const Point &p) const override
{
- auto res = core->project(p);
+ auto res = core->create_front_back(p);
return std::make_pair(res.first * m_scale, res.second * m_scale);
}
Vec3f project(const Vec3f &point) const override{
@@ -258,7 +267,16 @@ public:
}
};
- class OrthoProject: public Emboss::IProject {
+ class OrthoProject3f : public Emboss::IProject3f
+ {
+ // size and direction of emboss for ortho projection
+ Vec3f m_direction;
+ public:
+ OrthoProject3f(Vec3f direction) : m_direction(direction) {}
+ Vec3f project(const Vec3f &point) const override{ return point + m_direction;}
+ };
+
+ class OrthoProject: public Emboss::IProjection {
Transform3d m_matrix;
// size and direction of emboss for ortho projection
Vec3f m_direction;
@@ -267,7 +285,7 @@ public:
: m_matrix(matrix), m_direction(direction)
{}
// Inherited via IProject
- std::pair project(const Point &p) const override;
+ std::pair create_front_back(const Point &p) const override;
Vec3f project(const Vec3f &point) const override;
};
};
diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp
index f8c0b8d97..b6bf9252a 100644
--- a/src/libslic3r/Format/3mf.cpp
+++ b/src/libslic3r/Format/3mf.cpp
@@ -157,6 +157,7 @@ static constexpr const char *CHAR_GAP_ATTR = "char_gap";
static constexpr const char *LINE_GAP_ATTR = "line_gap";
static constexpr const char *LINE_HEIGHT_ATTR = "line_height";
static constexpr const char *DEPTH_ATTR = "depth";
+static constexpr const char *USE_SURFACE_ATTR = "use_surface";
static constexpr const char *BOLDNESS_ATTR = "boldness";
static constexpr const char *SKEW_ATTR = "skew";
static constexpr const char *DISTANCE_ATTR = "distance";
@@ -3335,6 +3336,8 @@ void TextConfigurationSerialization::to_xml(std::stringstream &stream, const Tex
stream << LINE_HEIGHT_ATTR << "=\"" << fp.size_in_mm << "\" ";
stream << DEPTH_ATTR << "=\"" << fp.emboss << "\" ";
+ if (fp.use_surface)
+ stream << USE_SURFACE_ATTR << "=\"" << 1 << "\" ";
if (fp.boldness.has_value())
stream << BOLDNESS_ATTR << "=\"" << *fp.boldness << "\" ";
if (fp.skew.has_value())
@@ -3416,7 +3419,9 @@ std::optional TextConfigurationSerialization::read(const char
fp.skew = skew;
float distance = get_attribute_value_float(attributes, num_attributes, DISTANCE_ATTR);
if (std::fabs(distance) > std::numeric_limits::epsilon())
- fp.distance = distance;
+ fp.distance = distance;
+ std::string use_surface = get_attribute_value_string(attributes, num_attributes, USE_SURFACE_ATTR);
+ if (!use_surface.empty()) fp.use_surface = true;
float angle = get_attribute_value_float(attributes, num_attributes, ANGLE_ATTR);
if (std::fabs(angle) > std::numeric_limits::epsilon())
fp.angle = angle;
diff --git a/src/libslic3r/TextConfiguration.hpp b/src/libslic3r/TextConfiguration.hpp
index 9e44f7a0d..53b76acd1 100644
--- a/src/libslic3r/TextConfiguration.hpp
+++ b/src/libslic3r/TextConfiguration.hpp
@@ -25,6 +25,12 @@ struct FontProp
// Z depth of text
float emboss; // [in mm]
+ // Flag that text should use surface cutted from object
+ // FontProp::distance should without value
+ // FontProp::emboss should be positive number
+ // Note: default value is false
+ bool use_surface;
+
// positive value mean wider character shape
// negative value mean tiner character shape
// When not set value is zero and is not stored
@@ -85,13 +91,14 @@ struct FontProp
/// Y size of text [in mm]
/// Z size of text [in mm]
FontProp(float line_height = 10.f, float depth = 2.f)
- : emboss(depth), size_in_mm(line_height)
+ : emboss(depth), size_in_mm(line_height), use_surface(false)
{}
bool operator==(const FontProp& other) const {
return
char_gap == other.char_gap &&
line_gap == other.line_gap &&
+ use_surface == other.use_surface &&
is_approx(emboss, other.emboss) &&
is_approx(size_in_mm, other.size_in_mm) &&
is_approx(boldness, other.boldness) &&
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
index 95bdc15f1..7149b9256 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
@@ -603,13 +603,15 @@ void GLGizmoEmboss::initialize()
int count_letter_M_in_input = 12;
cfg.advanced_input_width = letter_m_size.x * count_letter_M_in_input;
GuiCfg::Translations &tr = cfg.translations;
- tr.font = _u8L("Font");
- tr.size = _u8L("Height");
- tr.depth = _u8L("Depth");
+ tr.font = _u8L("Font");
+ tr.size = _u8L("Height");
+ tr.depth = _u8L("Depth");
+ tr.use_surface = _u8L("Use surface");
float max_edit_text_width = std::max(
{ImGui::CalcTextSize(tr.font.c_str()).x,
ImGui::CalcTextSize(tr.size.c_str()).x,
- ImGui::CalcTextSize(tr.depth.c_str()).x });
+ ImGui::CalcTextSize(tr.depth.c_str()).x,
+ ImGui::CalcTextSize(tr.use_surface.c_str()).x });
cfg.edit_input_offset =
3 * space + ImGui::GetTreeNodeToLabelSpacing() +
max_edit_text_width;
@@ -646,7 +648,7 @@ void GLGizmoEmboss::initialize()
float window_width = cfg.style_combobox_width + style.WindowPadding.x * 2;
cfg.minimal_window_size = ImVec2(window_width, window_height);
- float addition_edit_height = input_height * 3 + tree_header;
+ float addition_edit_height = input_height * 4 + tree_header;
cfg.minimal_window_size_with_edit = ImVec2(cfg.minimal_window_size.x,
cfg.minimal_window_size.y +
addition_edit_height);
@@ -869,11 +871,40 @@ bool GLGizmoEmboss::process()
m_update_job_cancel = std::make_shared >(false);
EmbossDataBase base{font, create_configuration(), create_volume_name()};
EmbossDataUpdate data{std::move(base), m_volume->id(), m_update_job_cancel};
+
+ std::unique_ptr job = nullptr;
+
+ // check cutting from source mesh
+ const TextConfiguration &tc = data.text_configuration;
+ if (tc.font_item.prop.use_surface) {
+ // Model to cut surface from.
+ const ModelVolume *mesh = get_volume_to_cut_surface_from();
+ if (mesh == nullptr) return false;
+
+ Transform3d text_tr = m_volume->get_matrix();
+ if (tc.fix_3mf_tr.has_value())
+ text_tr = text_tr * tc.fix_3mf_tr->inverse();
+
+ bool is_outside = m_volume->is_model_part();
+ // check that there is not unexpected volume type
+ assert(is_outside || m_volume->is_negative_volume() ||
+ m_volume->is_modifier());
+ UseSurfaceData surface_data{std::move(data),
+ text_tr,
+ is_outside,
+ mesh->mesh().its /*copy*/,
+ mesh->get_matrix(),
+ mesh->mesh().bounding_box()};
+ job = std::make_unique(std::move(surface_data));
+ } else {
+ job = std::make_unique(std::move(data));
+ }
+
//*
auto &worker = wxGetApp().plater()->get_ui_job_worker();
- queue_job(worker, std::make_unique(std::move(data)));
+ queue_job(worker, std::move(job));
/*/ // Run Job on main thread (blocking) - ONLY DEBUG
- execute_job(std::make_shared(std::move(data)));
+ execute_job(std::move(job));
// */
// notification is removed befor object is changed by job
@@ -913,49 +944,18 @@ void GLGizmoEmboss::select_stored_font_item()
m_stored_font_item = it->second;
}
-///
-/// choose valid source object for cut surface
-///
-/// Source model volume
-/// triangle set OR nullptr
-const indexed_triangle_set *get_source_object(const ModelVolume* mv) {
- if (mv == nullptr) return nullptr;
- if (!mv->text_configuration.has_value()) return nullptr;
- const auto &volumes = mv->get_object()->volumes;
- // no other volume in object
- if (volumes.size() <= 1) return nullptr;
-
- // Improve create object from part or use gl_volume
- // Get first model part in object
- for (const ModelVolume *v : volumes) {
- if (v->id() == mv->id()) continue;
- if (!v->is_model_part()) continue;
- const TriangleMesh &tm = v->mesh();
- if (tm.empty()) continue;
- return &tm.its;
- }
-
- // No valid source volume in objct volumes
- return nullptr;
-}
-
-///
-/// Choose valid source Volume to project on(cut surface from).
-///
-/// Volume with text
-/// ModelVolume to project on
-const ModelVolume *get_source_volume(const ModelVolume *text_volume)
+const ModelVolume * GLGizmoEmboss::get_volume_to_cut_surface_from()
{
- if (text_volume == nullptr) return nullptr;
- if (!text_volume->text_configuration.has_value()) return nullptr;
- const auto &volumes = text_volume->get_object()->volumes;
+ if (m_volume == nullptr) return nullptr;
+ if (!m_volume->text_configuration.has_value()) return nullptr;
+ const auto &volumes = m_volume->get_object()->volumes;
// no other volume in object
if (volumes.size() <= 1) return nullptr;
// Improve create object from part or use gl_volume
// Get first model part in object
for (const ModelVolume *v : volumes) {
- if (v->id() == text_volume->id()) continue;
+ if (v->id() == m_volume->id()) continue;
if (!v->is_model_part()) continue;
const TriangleMesh &tm = v->mesh();
if (tm.empty()) continue;
@@ -967,169 +967,36 @@ const ModelVolume *get_source_volume(const ModelVolume *text_volume)
return nullptr;
}
-double get_shape_scale(const FontProp &fp, const Emboss::FontFile &ff)
-{
- const auto &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;
- // Shape is scaled for store point coordinate as integer
- return scale * Emboss::SHAPE_SCALE;
-}
-
-///
-/// Create cut_projection for cut surface
-///
-/// Volume transformation in object
-/// Configuration of embossig
-/// Font file for size --> unit per em
-/// Bounding box 2d of shape to center result volume
-/// Bounding box 3d of model volume for projection ranges
-/// Orthogonal cut_projection
-std::unique_ptr create_projection_for_cut(
- Transform3d tr,
- const TextConfiguration &tc,
- const Emboss::FontFile &ff,
- const BoundingBox &shape_bb,
- const std::pair& z_range)
-{
- // create sure that emboss object is bigger than source object
- const float safe_extension = 1.0f;
- float min_z = z_range.first - safe_extension;
- float max_z = z_range.second + safe_extension;
- assert(min_z < max_z);
- // range between min and max value
- double projection_size = max_z - min_z;
- Matrix3d transformation_for_vector = tr.linear();
- // Projection must be negative value.
- // System of text coordinate
- // X .. from left to right
- // Y .. from bottom to top
- // Z .. from text to eye
- Vec3d untransformed_direction(0., 0., projection_size);
- Vec3f project_direction =
- (transformation_for_vector * untransformed_direction).cast();
-
- // Projection is in direction from far plane
- tr.translate(Vec3d(0., 0., min_z));
-
- tr.scale(get_shape_scale(tc.font_item.prop, ff));
- // Text alignemnt to center 2D
- Vec2d move = -(shape_bb.max + shape_bb.min).cast() / 2.;
- tr.translate(Vec3d(move.x(), move.y(), 0.));
- return std::make_unique(tr, project_direction);
-}
-
-#include "libslic3r/CutSurface.hpp"
-///
-/// Create tranformation for emboss
-///
-/// True .. raise, False .. engrave
-/// Text configuration
-/// Text voliume transformation inside object
-/// Cutted surface from model
-/// Projection
-static std::unique_ptr create_emboss_projection(
- bool is_outside,
- const TextConfiguration &tc,
- Transform3d tr,
- SurfaceCut &cut)
-{
- // Offset of clossed side to model
- const float surface_offset = 1e-3f; // [in mm]
-
- const FontProp &fp = tc.font_item.prop;
- float front_move, back_move;
- if (is_outside) {
- front_move = fp.emboss;
- back_move = -surface_offset;
- } else {
- front_move = surface_offset;
- back_move = -fp.emboss;
- }
- Matrix3d rot_i = tr.linear().inverse();
- its_transform(cut, rot_i);
-
- BoundingBoxf3 bb = Slic3r::bounding_box(cut);
- float z_move = -bb.max.z();
- float x_center = (bb.max.x() + bb.min.x()) / 2;
- float y_center = (bb.max.y() + bb.min.y()) / 2;
- // move to front distance
- Vec3f move(x_center, y_center, front_move + z_move);
-
- its_translate(cut, move);
-
- Vec3f from_front_to_back(0.f, 0.f, back_move - front_move);
- return std::make_unique(Transform3d::Identity() /*not used*/,
- from_front_to_back);
-}
-
void GLGizmoEmboss::use_surface() {
- // Model to cut surface from.
- const ModelVolume *source = get_source_volume(m_volume);
- if (source == nullptr) return;
-
// font face with glyph cache
auto ffc = m_font_manager.get_font().font_file_with_cache;
if (!ffc.has_value()) return;
+ // Model to cut surface from.
+ const ModelVolume *mesh = get_volume_to_cut_surface_from();
+ if (mesh == nullptr) return;
+
+ // Cancel previous job
+ if (m_update_job_cancel != nullptr) m_update_job_cancel->store(true);
+ // create new shared ptr to cancel new job
+ m_update_job_cancel = std::make_shared>(false);
+ EmbossDataBase base{ffc, create_configuration(), create_volume_name()};
+ EmbossDataUpdate data{std::move(base), m_volume->id(), m_update_job_cancel};
+
+ assert(m_volume->text_configuration.has_value());
+ if (!m_volume->text_configuration.has_value()) return;
const TextConfiguration &tc = *m_volume->text_configuration;
- const char *text = tc.text.c_str();
- const FontProp& fp = tc.font_item.prop;
- ExPolygons shapes = Emboss::text2shapes(ffc, text, fp);
-
- if (shapes.empty()) return;
- if (shapes.front().contour.empty()) return;
-
- BoundingBox bb = get_extents(shapes);
-
Transform3d text_tr = m_volume->get_matrix();
if (tc.fix_3mf_tr.has_value())
- text_tr = text_tr * tc.fix_3mf_tr->inverse();
-
- Transform3d source_tr = source->get_matrix();
- Transform3d source_tr_inv = source_tr.inverse();
- Transform3d cut_projection_tr = source_tr_inv * text_tr;
- //Transform3d cut_projection_tr = source_tr * text_tr.inverse();
-
- BoundingBoxf3 source_bb = source->mesh().bounding_box();
- BoundingBoxf3 source_bb_tr = source_bb.transformed(cut_projection_tr.inverse());
- std::pair z_range{source_bb_tr.min.z(), source_bb_tr.max.z()};
-
- const Emboss::FontFile &ff = *ffc.font_file;
- auto cut_projection = create_projection_for_cut(cut_projection_tr, tc, ff, bb, z_range);
- if (cut_projection == nullptr) return;
-
- SurfaceCuts cuts = cut_surface(source->mesh().its, shapes, *cut_projection);
- if (cuts.empty()) return;
-
+ text_tr = text_tr * tc.fix_3mf_tr->inverse();
bool is_outside = m_volume->is_model_part();
+ // check that there is not unexpected volume type
assert(is_outside || m_volume->is_negative_volume() || m_volume->is_modifier());
-
- SurfaceCut cut = merge(std::move(cuts));
- // !! Projection needs to transform cut
- auto projection = create_emboss_projection(is_outside, tc, cut_projection_tr, cut);
- if (projection == nullptr) return;
+ UseSurfaceData surface_data{std::move(data), text_tr, is_outside,
+ mesh->mesh().its /*copy*/, mesh->get_matrix(), mesh->mesh().bounding_box()};
- indexed_triangle_set new_its = cut2model(cut, *projection);
- its_write_obj(new_its, "C:/data/temp/projected.obj"); // only debug
-
- TriangleMesh tm(std::move(new_its));
- // center triangle mesh
- Vec3d shift = tm.bounding_box().center();
- // do not center in emboss direction
- shift.z() = 0;
- tm.translate(-shift.cast());
-
- // discard fix transformation when exists
- if (tc.fix_3mf_tr.has_value()) {
- m_volume->set_transformation(text_tr);
- m_volume->text_configuration->fix_3mf_tr = {};
- }
-
- m_volume->set_mesh(std::move(tm));
- m_volume->set_new_unique_id();
- wxGetApp().plater()->canvas3D()->reload_scene(true);
+ auto &worker = wxGetApp().plater()->get_ui_job_worker();
+ queue_job(worker, std::make_unique(std::move(surface_data)));
}
void GLGizmoEmboss::draw_window()
@@ -1907,6 +1774,25 @@ bool GLGizmoEmboss::rev_input(const std::string &name,
return revertible(name, value, default_value, exist_change, undo_tooltip, undo_offset, draw_offseted_input);
}
+bool GLGizmoEmboss::rev_checkbox(const std::string &name,
+ bool &value,
+ bool *default_value,
+ const std::string &undo_tooltip)
+{
+ // draw offseted input
+ auto draw_offseted_input = [&]() -> bool {
+ float input_offset = m_gui_cfg->edit_input_offset;
+ ImGui::SameLine(input_offset);
+ return ImGui::Checkbox(("##" + name).c_str(), &value);
+ };
+ float undo_offset = ImGui::GetStyle().FramePadding.x;
+ bool exist_change = default_value != nullptr ?
+ (value != *default_value) :
+ false;
+ return revertible(name, value, default_value, exist_change, undo_tooltip,
+ undo_offset, draw_offseted_input);
+}
+
void GLGizmoEmboss::draw_style_edit() {
const GuiCfg::Translations &tr = m_gui_cfg->translations;
@@ -2006,6 +1892,18 @@ void GLGizmoEmboss::draw_style_edit() {
_u8L("Revert embossed depth."), 0.1f, 0.25, "%.2f mm"))
process();
+ bool *def_use_surface = m_stored_font_item.has_value() ?
+ &m_stored_font_item->prop.use_surface : nullptr;
+ if (rev_checkbox(tr.use_surface, font_prop.use_surface, def_use_surface,
+ _u8L("Revert using of model surface."))) {
+ if (font_prop.use_surface) {
+ font_prop.distance.reset();
+ if (font_prop.emboss < 0.1)
+ font_prop.emboss = 1;
+ }
+ process();
+ }
+
if (ImGui::TreeNode(_u8L("advanced").c_str())) {
if (!m_is_advanced_edit_style) {
set_minimal_window_size(true, true);
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp
index 27ae78892..7637e0ffd 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp
@@ -115,6 +115,12 @@ private:
// TODO: only for developing - remove it
void use_surface();
+ ///
+ /// Choose valid source Volume to project on(cut surface from).
+ ///
+ /// ModelVolume to project on
+ const ModelVolume *get_volume_to_cut_surface_from();
+
///
/// Reversible input float with option to restor default value
/// TODO: make more general, static and move to ImGuiWrapper
@@ -123,6 +129,7 @@ private:
bool rev_input(const std::string &name, float &value, float *default_value,
const std::string &undo_tooltip, float step, float step_fast, const char *format,
ImGuiInputTextFlags flags = 0);
+ bool rev_checkbox(const std::string &name, bool &value, bool* default_value, const std::string &undo_tooltip);
bool rev_slider(const std::string &name, std::optional& value, std::optional *default_value,
const std::string &undo_tooltip, int v_min, int v_max, const std::string &format, const wxString &tooltip);
bool rev_slider(const std::string &name, std::optional& value, std::optional *default_value,
@@ -185,6 +192,7 @@ private:
std::string font;
std::string size;
std::string depth;
+ std::string use_surface;
// advanced
std::string char_gap;
diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp
index a31932d5e..899fed7a4 100644
--- a/src/slic3r/GUI/Jobs/EmbossJob.cpp
+++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp
@@ -2,6 +2,7 @@
#include
#include // load_obj for default mesh
+#include // use surface cuts
#include "slic3r/GUI/Plater.hpp"
#include "slic3r/GUI/NotificationManager.hpp"
@@ -40,105 +41,46 @@ static TriangleMesh create_mesh(const char *text,
///
/// Not empty model(index trinagle set - its)
static TriangleMesh create_default_mesh();
+
+///
+/// Must be called on main thread
+///
+/// New mesh data
+/// Text configuration, ...
+static void update_volume(TriangleMesh &&mesh, const EmbossDataUpdate &data);
+
+///
+/// Create projection for cut surface from mesh
+///
+/// Volume transformation in object
+/// Configuration of embossig
+/// Font file for size --> unit per em
+/// Bounding box 2d of shape to center result
+/// volume Bounding box 3d of model volume for
+/// projection ranges Orthogonal cut_projection
+static std::unique_ptr create_projection_for_cut(
+ Transform3d tr,
+ const TextConfiguration &tc,
+ const Emboss::FontFile &ff,
+ const BoundingBox &shape_bb,
+ const std::pair &z_range);
+
+///
+/// Create tranformation for emboss Cutted surface
+///
+/// True .. raise, False .. engrave
+/// Text configuration
+/// Text voliume transformation inside object
+/// Cutted surface from model
+/// Projection
+static std::unique_ptr create_emboss_projection(
+ bool is_outside,
+ const TextConfiguration &tc,
+ Transform3d tr,
+ SurfaceCut &cut);
+
}
-
-/////////////////
-/// Update Volume
-EmbossUpdateJob::EmbossUpdateJob(EmbossDataUpdate&& input)
- : m_input(std::move(input))
-{
- assert(m_input.cancel != nullptr);
- assert(m_input.font_file.has_value());
- assert(!m_input.text_configuration.text.empty());
- assert(!m_input.text_configuration.fix_3mf_tr.has_value());
-}
-
-void EmbossUpdateJob::process(Ctl &ctl)
-{
- auto was_canceled = [&ctl, &cancel = m_input.cancel]()->bool {
- if (cancel->load()) return true;
- return ctl.was_canceled();
- };
-
- // check if exist valid font
- if (!m_input.font_file.has_value()) return;
-
- const TextConfiguration &cfg = m_input.text_configuration;
- m_result = priv::create_mesh(cfg.text.c_str(), m_input.font_file,
- cfg.font_item.prop, was_canceled);
- if (m_result.its.empty()) return;
- if (was_canceled()) return;
-
- // center triangle mesh
- Vec3d shift = m_result.bounding_box().center();
- m_result.translate(-shift.cast());
-}
-
-void EmbossUpdateJob::finalize(bool canceled, std::exception_ptr &)
-{
- if (canceled || m_input.cancel->load()) return;
-
- // for sure that some object is created from shape
- if (m_result.its.indices.empty()) return;
-
- GUI_App & app = wxGetApp(); // may be move to input
- Plater * plater = app.plater();
- GLCanvas3D * canvas = plater->canvas3D();
-
- // 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%"), m_input.text_configuration.text);
- Plater::TakeSnapshot snapshot(plater, snap_name, UndoRedo::SnapshotType::GizmoAction);
-
- ModelVolume *volume = nullptr;
- Model &model = plater->model();
- for (auto obj : model.objects)
- for (auto vol : obj->volumes)
- if (vol->id() == m_input.volume_id) {
- volume = vol;
- break;
- }
-
- // could appear when user delete edited volume
- if (volume == nullptr)
- return;
-
- // apply fix matrix made by store to .3mf
- const auto &tc = volume->text_configuration;
- assert(tc.has_value());
- if (tc.has_value() && tc->fix_3mf_tr.has_value())
- volume->set_transformation(volume->get_matrix() * tc->fix_3mf_tr->inverse());
-
- // update volume
- volume->set_mesh(std::move(m_result));
- volume->set_new_unique_id();
- volume->calculate_convex_hull();
- volume->get_object()->invalidate_bounding_box();
- volume->name = m_input.volume_name;
- volume->text_configuration = m_input.text_configuration;
-
- // update volume in right panel( volume / object name)
- 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();
- int volume_idx = gl_volume->volume_idx();
- ObjectList *obj_list = app.obj_list();
- obj_list->update_name_in_list(object_idx, volume_idx);
-
- // update printable state on canvas
- if (volume->type() == ModelVolumeType::MODEL_PART)
- canvas->update_instance_printable_state_for_object((size_t) object_idx);
-
- // redraw scene
- bool refresh_immediately = false;
- canvas->reload_scene(refresh_immediately);
-}
-
-
/////////////////
/// Create Volume
EmbossCreateVolumeJob::EmbossCreateVolumeJob(EmbossDataCreateVolume &&input)
@@ -296,6 +238,104 @@ void EmbossCreateObjectJob::finalize(bool canceled, std::exception_ptr &)
canvas->reload_scene(true);
}
+/////////////////
+/// Update Volume
+EmbossUpdateJob::EmbossUpdateJob(EmbossDataUpdate&& input)
+ : m_input(std::move(input))
+{
+ assert(m_input.cancel != nullptr);
+ assert(m_input.font_file.has_value());
+ assert(!m_input.text_configuration.text.empty());
+ assert(!m_input.text_configuration.fix_3mf_tr.has_value());
+}
+
+void EmbossUpdateJob::process(Ctl &ctl)
+{
+ auto was_canceled = [&ctl, &cancel = m_input.cancel]()->bool {
+ if (cancel->load()) return true;
+ return ctl.was_canceled();
+ };
+
+ // check if exist valid font
+ if (!m_input.font_file.has_value()) return;
+
+ const TextConfiguration &cfg = m_input.text_configuration;
+ m_result = priv::create_mesh(cfg.text.c_str(), m_input.font_file,
+ cfg.font_item.prop, was_canceled);
+ if (m_result.its.empty()) return;
+ if (was_canceled()) return;
+
+ // center triangle mesh
+ Vec3d shift = m_result.bounding_box().center();
+ m_result.translate(-shift.cast());
+}
+
+void EmbossUpdateJob::finalize(bool canceled, std::exception_ptr &)
+{
+ if (canceled || m_input.cancel->load()) return;
+ priv::update_volume(std::move(m_result), m_input);
+}
+
+/////////////////
+/// Cut Surface
+UseSurfaceJob::UseSurfaceJob(UseSurfaceData &&input)
+ : m_input(std::move(input))
+{}
+
+void UseSurfaceJob::process(Ctl &ctl) {
+ // font face with glyph cache
+ if (!m_input.font_file.has_value()) return;
+
+ // check cancelation of process
+ auto was_canceled = [&ctl, &cancel = m_input.cancel]()->bool {
+ if (cancel->load()) return true;
+ return ctl.was_canceled();
+ };
+
+ const TextConfiguration &tc = m_input.text_configuration;
+ const char *text = tc.text.c_str();
+ const FontProp &fp = tc.font_item.prop;
+ ExPolygons shapes = Emboss::text2shapes(m_input.font_file, text, fp);
+ if (shapes.empty()) return;
+ if (shapes.front().contour.empty()) return;
+ if (was_canceled()) return;
+
+ BoundingBox bb = get_extents(shapes);
+
+ Transform3d mesh_tr_inv = m_input.mesh_tr.inverse();
+ Transform3d cut_projection_tr = mesh_tr_inv * m_input.text_tr;
+ BoundingBoxf3 mesh_bb_tr = m_input.mesh_bb.transformed(cut_projection_tr.inverse());
+ std::pair z_range{mesh_bb_tr.min.z(), mesh_bb_tr.max.z()};
+
+ const Emboss::FontFile &ff = *m_input.font_file.font_file;
+ auto cut_projection = priv::create_projection_for_cut(cut_projection_tr, tc, ff, bb, z_range);
+ if (cut_projection == nullptr) return;
+
+ // Use CGAL to cut surface from triangle mesh
+ SurfaceCut cut = cut_surface(m_input.mesh_its, shapes, *cut_projection);
+ if (cut.empty()) return;
+ if (was_canceled()) return;
+
+ // !! Projection needs to transform cut
+ auto projection = priv::create_emboss_projection(m_input.is_outside, tc, cut_projection_tr, cut);
+ if (projection == nullptr) return;
+
+ indexed_triangle_set new_its = cut2model(cut, *projection);
+ if (was_canceled()) return;
+ //its_write_obj(new_its, "C:/data/temp/projected.obj"); // only debug
+
+ m_result = TriangleMesh(std::move(new_its));
+ Vec3d shift = -m_result.bounding_box().center();
+ // do not center in emboss direction
+ shift.z() = 0;
+ m_result.translate(shift.cast());
+}
+
+void UseSurfaceJob::finalize(bool canceled, std::exception_ptr &)
+{
+ if (canceled || m_input.cancel->load()) return;
+ priv::update_volume(std::move(m_result), m_input);
+}
////////////////////////////
/// private namespace implementation
@@ -334,4 +374,149 @@ TriangleMesh priv::create_default_mesh()
return TriangleMesh(its_make_cube(36., 4., 2.5));
}
return triangle_mesh;
-}
\ No newline at end of file
+}
+
+static ModelVolume *get_volume(const ObjectID &volume_id, Model &model)
+{
+ for (auto obj : model.objects)
+ for (auto vol : obj->volumes)
+ if (vol->id() == volume_id)
+ return vol;
+ return nullptr;
+}
+
+static ModelVolume *get_volume(const ObjectID &volume_id) {
+ return get_volume(volume_id, wxGetApp().plater()->model());
+}
+
+void priv::update_volume(TriangleMesh &&mesh,
+ const EmbossDataUpdate &data)
+{
+ // for sure that some object will be created
+ if (mesh.its.empty()) return;
+
+ GUI_App & app = wxGetApp(); // may be move to input
+ Plater * plater = app.plater();
+ GLCanvas3D * canvas = plater->canvas3D();
+
+ // 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);
+ Plater::TakeSnapshot snapshot(plater, snap_name, UndoRedo::SnapshotType::GizmoAction);
+
+ ModelVolume *volume = get_volume(data.volume_id, plater->model());
+ // could appear when user delete edited volume
+ if (volume == nullptr)
+ return;
+
+ // apply fix matrix made by store to .3mf
+ const auto &tc = volume->text_configuration;
+ assert(tc.has_value());
+ if (tc.has_value() && tc->fix_3mf_tr.has_value())
+ volume->set_transformation(volume->get_matrix() * tc->fix_3mf_tr->inverse());
+
+ // update volume
+ volume->set_mesh(std::move(mesh));
+ volume->set_new_unique_id();
+ volume->calculate_convex_hull();
+ volume->get_object()->invalidate_bounding_box();
+ volume->name = data.volume_name;
+ volume->text_configuration = data.text_configuration;
+
+ // update volume in right panel( volume / object name)
+ 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();
+ int volume_idx = gl_volume->volume_idx();
+ ObjectList *obj_list = app.obj_list();
+ obj_list->update_name_in_list(object_idx, volume_idx);
+
+ // update printable state on canvas
+ if (volume->type() == ModelVolumeType::MODEL_PART)
+ canvas->update_instance_printable_state_for_object((size_t) object_idx);
+
+ // redraw scene
+ bool refresh_immediately = false;
+ canvas->reload_scene(refresh_immediately);
+}
+
+static double get_shape_scale(const FontProp &fp, const Emboss::FontFile &ff)
+{
+ const auto &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;
+ // Shape is scaled for store point coordinate as integer
+ return scale * Emboss::SHAPE_SCALE;
+}
+
+std::unique_ptr priv::create_projection_for_cut(
+ Transform3d tr,
+ const TextConfiguration &tc,
+ const Emboss::FontFile &ff,
+ const BoundingBox &shape_bb,
+ const std::pair &z_range)
+{
+ // create sure that emboss object is bigger than source object
+ const float safe_extension = 1.0f;
+ float min_z = z_range.first - safe_extension;
+ float max_z = z_range.second + safe_extension;
+ assert(min_z < max_z);
+ // range between min and max value
+ double projection_size = max_z - min_z;
+ Matrix3d transformation_for_vector = tr.linear();
+ // Projection must be negative value.
+ // System of text coordinate
+ // X .. from left to right
+ // Y .. from bottom to top
+ // Z .. from text to eye
+ Vec3d untransformed_direction(0., 0., projection_size);
+ Vec3f project_direction =
+ (transformation_for_vector * untransformed_direction).cast();
+
+ // Projection is in direction from far plane
+ tr.translate(Vec3d(0., 0., min_z));
+
+ tr.scale(get_shape_scale(tc.font_item.prop, ff));
+ // Text alignemnt to center 2D
+ Vec2d move = -(shape_bb.max + shape_bb.min).cast() / 2.;
+ tr.translate(Vec3d(move.x(), move.y(), 0.));
+ return std::make_unique(tr, project_direction);
+}
+
+std::unique_ptr priv::create_emboss_projection(
+ bool is_outside,
+ const TextConfiguration &tc,
+ Transform3d tr,
+ SurfaceCut &cut)
+{
+ // Offset of clossed side to model
+ const float surface_offset = 1e-3f; // [in mm]
+
+ const FontProp &fp = tc.font_item.prop;
+ float front_move, back_move;
+ if (is_outside) {
+ front_move = fp.emboss;
+ back_move = -surface_offset;
+ } else {
+ front_move = surface_offset;
+ back_move = -fp.emboss;
+ }
+ Matrix3d rot_i = tr.linear().inverse();
+ its_transform(cut, rot_i);
+
+ BoundingBoxf3 bb = Slic3r::bounding_box(cut);
+ float z_move = -bb.max.z();
+ float x_center = (bb.max.x() + bb.min.x()) / 2;
+ float y_center = (bb.max.y() + bb.min.y()) / 2;
+ // move to front distance
+ Vec3f move(x_center, y_center, front_move + z_move);
+
+ its_translate(cut, move);
+
+ Vec3f from_front_to_back(0.f, 0.f, back_move - front_move);
+ return std::make_unique(from_front_to_back);
+}
diff --git a/src/slic3r/GUI/Jobs/EmbossJob.hpp b/src/slic3r/GUI/Jobs/EmbossJob.hpp
index cc7cae31b..e0a7aee3d 100644
--- a/src/slic3r/GUI/Jobs/EmbossJob.hpp
+++ b/src/slic3r/GUI/Jobs/EmbossJob.hpp
@@ -30,19 +30,6 @@ struct EmbossDataBase
std::string volume_name;
};
-///
-/// Hold neccessary data to update embossed text object in job
-///
-struct EmbossDataUpdate : public EmbossDataBase
-{
- // unique identifier of volume to change
- ObjectID volume_id;
-
- // flag that job is canceled
- // for time after process.
- std::shared_ptr > cancel;
-};
-
///
/// Hold neccessary data to create ModelVolume in job
/// Volume is created on the surface of existing volume in object.
@@ -67,6 +54,22 @@ struct EmbossDataCreateVolume : public EmbossDataBase
Transform3d hit_instance_tr;
};
+///
+/// Create new TextVolume on the surface of ModelObject
+/// Should not be stopped
+///
+class EmbossCreateVolumeJob : public Job
+{
+ EmbossDataCreateVolume m_input;
+ TriangleMesh m_result;
+ Transform3d m_transformation;
+
+public:
+ EmbossCreateVolumeJob(EmbossDataCreateVolume&& input);
+ void process(Ctl &ctl) override;
+ void finalize(bool canceled, std::exception_ptr &) override;
+};
+
///
/// Hold neccessary data to create ModelObject in job
/// Object is placed on bed under screen coor
@@ -84,51 +87,6 @@ struct EmbossDataCreateObject : public EmbossDataBase
std::vector bed_shape;
};
-///
-/// Update text shape in existing text volume
-/// Predict that there is only one runnig(not canceled) instance of it
-///
-class EmbossUpdateJob : public Job
-{
- EmbossDataUpdate m_input;
- TriangleMesh m_result;
-public:
- // only move params to private variable
- EmbossUpdateJob(EmbossDataUpdate&& input);
-
- ///
- /// Create volume movel by input data
- ///
- /// Control containing cancel flag
- void process(Ctl &ctl) override;
-
- ///
- /// Update volume - change object_id
- ///
- /// Was process canceled.
- /// NOTE: Be carefull it doesn't care about
- /// time between finished process and started finalize part.
- /// unused
- void finalize(bool canceled, std::exception_ptr &) override;
-};
-
-
-///
-/// Create new TextVolume on the surface of ModelObject
-/// Should not be stopped
-///
-class EmbossCreateVolumeJob : public Job
-{
- EmbossDataCreateVolume m_input;
- TriangleMesh m_result;
- Transform3d m_transformation;
-
-public:
- EmbossCreateVolumeJob(EmbossDataCreateVolume&& input);
- void process(Ctl &ctl) override;
- void finalize(bool canceled, std::exception_ptr &) override;
-};
-
///
/// Create new TextObject on the platter
/// Should not be stopped
@@ -138,13 +96,91 @@ class EmbossCreateObjectJob : public Job
EmbossDataCreateObject m_input;
TriangleMesh m_result;
Transform3d m_transformation;
-
public:
EmbossCreateObjectJob(EmbossDataCreateObject&& input);
void process(Ctl &ctl) override;
void finalize(bool canceled, std::exception_ptr &) override;
};
+///
+/// Hold neccessary data to update embossed text object in job
+///
+struct EmbossDataUpdate : public EmbossDataBase
+{
+ // unique identifier of volume to change
+ ObjectID volume_id;
+
+ // flag that job is canceled
+ // for time after process.
+ std::shared_ptr> cancel;
+};
+
+///
+/// Update text shape in existing text volume
+/// Predict that there is only one runnig(not canceled) instance of it
+///
+class EmbossUpdateJob : public Job
+{
+ EmbossDataUpdate m_input;
+ TriangleMesh m_result;
+
+public:
+ // move params to private variable
+ EmbossUpdateJob(EmbossDataUpdate &&input);
+
+ ///
+ /// Create new embossed volume by m_input data and store to m_result
+ ///
+ /// Control containing cancel flag
+ void process(Ctl &ctl) override;
+
+ ///
+ /// Update volume - change object_id
+ ///
+ /// Was process canceled.
+ /// NOTE: Be carefull it doesn't care about
+ /// time between finished process and started finalize part.
+ /// unused
+ void finalize(bool canceled, std::exception_ptr &) override;
+};
+
+///
+/// Hold neccessary data to update embossed text object in job
+///
+struct UseSurfaceData : public EmbossDataUpdate
+{
+ // Transformation of text volume inside of object
+ Transform3d text_tr;
+
+ // Define projection move
+ // True (raised) .. move outside from surface
+ // False (engraved).. move into object
+ bool is_outside;
+
+ // IMPROVE: copy of source mesh tringles
+ // copy could slow down on big meshes
+ indexed_triangle_set mesh_its;
+ // Transformation of volume inside of object
+ Transform3d mesh_tr;
+ // extract bounds for projection
+ BoundingBoxf3 mesh_bb;
+};
+
+///
+/// Update text volume to use surface from object
+///
+class UseSurfaceJob : public Job
+{
+ UseSurfaceData m_input;
+ TriangleMesh m_result;
+
+public:
+ // move params to private variable
+ UseSurfaceJob(UseSurfaceData &&input);
+ void process(Ctl &ctl) override;
+ void finalize(bool canceled, std::exception_ptr &) override;
+};
+
} // namespace Slic3r::GUI
#endif // slic3r_EmbossJob_hpp_
diff --git a/src/slic3r/Utils/FontListSerializable.cpp b/src/slic3r/Utils/FontListSerializable.cpp
index 2203339f6..c79bee4c0 100644
--- a/src/slic3r/Utils/FontListSerializable.cpp
+++ b/src/slic3r/Utils/FontListSerializable.cpp
@@ -10,6 +10,7 @@ const std::string FontListSerializable::APP_CONFIG_FONT_NAME = "name";
const std::string FontListSerializable::APP_CONFIG_FONT_DESCRIPTOR = "descriptor";
const std::string FontListSerializable::APP_CONFIG_FONT_LINE_HEIGHT = "line_height";
const std::string FontListSerializable::APP_CONFIG_FONT_DEPTH = "depth";
+const std::string FontListSerializable::APP_CONFIG_FONT_USE_SURFACE = "use_surface";
const std::string FontListSerializable::APP_CONFIG_FONT_BOLDNESS = "boldness";
const std::string FontListSerializable::APP_CONFIG_FONT_SKEW = "skew";
const std::string FontListSerializable::APP_CONFIG_FONT_DISTANCE = "distance";
@@ -23,6 +24,15 @@ std::string FontListSerializable::create_section_name(unsigned index)
return AppConfig::SECTION_FONT + ':' + std::to_string(index);
}
+// check only existence of flag
+bool FontListSerializable::read(const std::map& section, const std::string& key, bool& value){
+ auto item = section.find(key);
+ if (item == section.end()) return false;
+
+ value = true;
+ return true;
+}
+
#include "fast_float/fast_float.h"
bool FontListSerializable::read(const std::map& section, const std::string& key, float& value){
auto item = section.find(key);
@@ -92,6 +102,7 @@ std::optional FontListSerializable::load_font_item(
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);
@@ -115,6 +126,8 @@ void FontListSerializable::store_font_item(AppConfig & cfg,
const FontProp &fp = fi.prop;
cfg.set(section_name, APP_CONFIG_FONT_LINE_HEIGHT, std::to_string(fp.size_in_mm));
cfg.set(section_name, APP_CONFIG_FONT_DEPTH, std::to_string(fp.emboss));
+ if (fp.use_surface)
+ cfg.set(section_name, APP_CONFIG_FONT_USE_SURFACE, "true");
if (fp.boldness.has_value())
cfg.set(section_name, APP_CONFIG_FONT_BOLDNESS, std::to_string(*fp.boldness));
if (fp.skew.has_value())
diff --git a/src/slic3r/Utils/FontListSerializable.hpp b/src/slic3r/Utils/FontListSerializable.hpp
index 607efef85..16c8c7744 100644
--- a/src/slic3r/Utils/FontListSerializable.hpp
+++ b/src/slic3r/Utils/FontListSerializable.hpp
@@ -21,6 +21,7 @@ class FontListSerializable
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;
@@ -37,10 +38,11 @@ public:
private:
// TODO: move to app config like read from section
+ static bool read(const std::map& section, const std::string& key, bool& value);
static bool read(const std::map& section, const std::string& key, float& value);
static bool read(const std::map& section, const std::string& key, std::optional& value);
static bool read(const std::map& section, const std::string& key, std::optional& value);
- static bool read(const std::map& section, const std::string& key, std::optional& value);
+ static bool read(const std::map& section, const std::string& key, std::optional& value);
};
} // namespace Slic3r
diff --git a/tests/libslic3r/test_emboss.cpp b/tests/libslic3r/test_emboss.cpp
index 5ea785565..1ebc3e6c7 100644
--- a/tests/libslic3r/test_emboss.cpp
+++ b/tests/libslic3r/test_emboss.cpp
@@ -330,10 +330,9 @@ TEST_CASE("Cut surface", "[]")
CHECK(!surfaces.empty());
Emboss::OrthoProject projection(Transform3d::Identity(), Vec3f(0.f, 0.f, 10.f));
- for (auto &surface : surfaces)
- its_translate(surface, Vec3f(0.f, 0.f, 10));
+ its_translate(surfaces, Vec3f(0.f, 0.f, 10));
- indexed_triangle_set its = cuts2model(surfaces, projection);
+ indexed_triangle_set its = cut2model(surfaces, projection);
CHECK(!its.empty());
//its_write_obj(its, "C:/data/temp/projected.obj");
}
@@ -479,12 +478,12 @@ namespace Slic3r::MeshBoolean::cgal2 {
/// Name of property map to store conversion from face to contour
/// Identify point on shape contour
/// CGAL model of extruded shape
- CGALMesh to_cgal(const ExPolygons &shape,
- const Slic3r::Emboss::IProject &projection,
- int32_t shape_id,
- const std::string &edge_shape_map_name,
- const std::string &face_shape_map_name,
- std::vector &contour_indices)
+ CGALMesh to_cgal(const ExPolygons &shape,
+ const Slic3r::Emboss::IProjection &projection,
+ int32_t shape_id,
+ const std::string &edge_shape_map_name,
+ const std::string &face_shape_map_name,
+ std::vector &contour_indices)
{
CGALMesh result;
if (shape.empty()) return result;
@@ -500,7 +499,7 @@ namespace Slic3r::MeshBoolean::cgal2 {
int32_t vertex_index = static_cast(contour_indices.size());
contour_indices.push_back({iexpoly, id, int32_t(num_vertices_old) });
for (const Point& p2 : polygon.points) {
- auto p = projection.project(p2);
+ auto p = projection.create_front_back(p2);
auto vi = result.add_vertex(typename CGALMesh::Point{ p.first.x(), p.first.y(), p.first.z() });
assert((size_t)vi == indices.size() + num_vertices_old);
indices.emplace_back(vi);
@@ -565,7 +564,7 @@ namespace Slic3r::MeshBoolean::cgal2 {
/// Cutted surface, Its do not represent Volume
indexed_triangle_set cut_shape(const indexed_triangle_set &source,
const ExPolygon &shape,
- const Emboss::IProject &projection)
+ const Emboss::IProjection &projection)
{
// NOT implemented yet
return {};
@@ -580,7 +579,7 @@ indexed_triangle_set cut_shape(const indexed_triangle_set &source,
/// Cutted surface, Its do not represent Volume
indexed_triangle_set cut_shape(const indexed_triangle_set &source,
const ExPolygons &shapes,
- const Emboss::IProject &projection)
+ const Emboss::IProjection &projection)
{
indexed_triangle_set result;
for (const ExPolygon &shape : shapes)