Initial shape for emboss is not cached any more

This commit is contained in:
Filip Sykala 2022-01-04 13:21:31 +01:00
parent 0a3fc00851
commit 5869f86d97
4 changed files with 133 additions and 81 deletions

View File

@ -642,3 +642,54 @@ std::pair<Vec3f, Vec3f> Emboss::ProjectZ::project(const Point &p) const
back.z() = m_depth; back.z() = m_depth;
return std::make_pair(front, back); return std::make_pair(front, back);
} }
Transform3d Emboss::create_transformation_onto_surface(const Vec3f &position,
const Vec3f &normal,
float up_limit)
{
// up and emboss direction for generated model
Vec3d text_up_dir = Vec3d::UnitY();
Vec3d text_emboss_dir = Vec3d::UnitZ();
// wanted up direction of result
Vec3d wanted_up_side = Vec3d::UnitZ();
if (std::fabs(normal.z()) > up_limit) wanted_up_side = Vec3d::UnitY();
Vec3d wanted_emboss_dir = normal.cast<double>();
// after cast from float it needs to be normalized again
wanted_emboss_dir.normalize();
// create perpendicular unit vector to surface triangle normal vector
// lay on surface of triangle and define up vector for text
Vec3d wanted_up_dir = wanted_emboss_dir
.cross(wanted_up_side)
.cross(wanted_emboss_dir);
// normal3d is NOT perpendicular to normal_up_dir
wanted_up_dir.normalize();
// perpendicular to emboss vector of text and normal
Vec3d axis_view = text_emboss_dir.cross(wanted_emboss_dir);
double angle_view = std::acos(text_emboss_dir.dot(wanted_emboss_dir)); // in rad
axis_view.normalize();
Eigen::AngleAxis view_rot(angle_view, axis_view);
Vec3d wanterd_up_rotated = view_rot.matrix().inverse() * wanted_up_dir;
wanterd_up_rotated.normalize();
double angle_up = std::acos(text_up_dir.dot(wanterd_up_rotated));
// text_view and text_view2 should have same direction
Vec3d text_view2 = text_up_dir.cross(wanterd_up_rotated);
Vec3d diff_view = text_emboss_dir - text_view2;
if (std::fabs(diff_view.x()) > 1. ||
std::fabs(diff_view.y()) > 1. ||
std::fabs(diff_view.z()) > 1.) // oposit direction
angle_up *= -1.;
Eigen::AngleAxis up_rot(angle_up, text_emboss_dir);
Transform3d transform = Transform3d::Identity();
transform.translate(position.cast<double>());
transform.rotate(view_rot);
transform.rotate(up_rot);
return transform;
}

View File

@ -129,6 +129,16 @@ public:
/// <returns>Projected shape into space</returns> /// <returns>Projected shape into space</returns>
static indexed_triangle_set polygons2model(const ExPolygons &shape2d, const IProject& projection); static indexed_triangle_set polygons2model(const ExPolygons &shape2d, const IProject& projection);
/// <summary>
/// Create transformation for emboss text object to lay on surface point
/// </summary>
/// <param name="position">Position of surface point</param>
/// <param name="normal">Normal of surface point</param>
/// <param name="up_limit">Is compared with normal.z to suggest up direction</param>
/// <returns>Transformation onto surface point</returns>
static Transform3d create_transformation_onto_surface(
const Vec3f &position, const Vec3f &normal, float up_limit = 0.9f);
class ProjectZ : public IProject class ProjectZ : public IProject
{ {
public: public:

View File

@ -110,16 +110,19 @@ static void draw_fine_position(const Selection &selection)
void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mouse_pos) void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mouse_pos)
{ {
assert(volume_type == ModelVolumeType::MODEL_PART ||
volume_type == ModelVolumeType::NEGATIVE_VOLUME ||
volume_type == ModelVolumeType::PARAMETER_MODIFIER);
if (!m_is_initialized) initialize(); if (!m_is_initialized) initialize();
const Selection &selection = m_parent.get_selection(); const Selection &selection = m_parent.get_selection();
if(selection.is_empty()) return; if(selection.is_empty()) return;
set_default_configuration(); set_default_configuration();
TriangleMesh tm = m_default_mesh; // copy
// By position of cursor create transformation to put text on surface of model // By position of cursor create transformation to put text on surface of model
Transform3d transformation = Transform3d::Identity(); Transform3d transformation = Transform3d::Identity();
// TODO: calculate X,Y offset position for lay on platter by mouse position
CommonGizmosDataObjects::Raycaster *raycaster = m_c->raycaster(); CommonGizmosDataObjects::Raycaster *raycaster = m_c->raycaster();
if (raycaster == nullptr) return; if (raycaster == nullptr) return;
@ -143,7 +146,7 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mous
std::optional<Transform3d> tr = transform_on_surface(mouse_pos, raycasters, raycasters_tr); std::optional<Transform3d> tr = transform_on_surface(mouse_pos, raycasters, raycasters_tr);
if (tr.has_value()) transformation = *tr; if (tr.has_value()) transformation = *tr;
create_emboss_volume(std::move(tm), transformation, create_volume_name(), create_emboss_volume(create_mesh(), transformation, create_volume_name(),
create_configuration(), volume_type, create_configuration(), volume_type,
selection.get_object_idx()); selection.get_object_idx());
} }
@ -211,7 +214,7 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
} }
Transform3d object_trmat = m_raycast_manager.get_transformation(hit->tr_key); Transform3d object_trmat = m_raycast_manager.get_transformation(hit->tr_key);
Transform3d trmat = get_emboss_transformation(hit->position, hit->normal); Transform3d trmat = Emboss::create_transformation_onto_surface(hit->position, hit->normal);
if (mouse_event.Dragging()) { if (mouse_event.Dragging()) {
// hide common dragging of object // hide common dragging of object
m_parent.toggle_model_objects_visibility(false, m_volume->get_object(), gl_volume->instance_idx(), m_volume); m_parent.toggle_model_objects_visibility(false, m_volume->get_object(), gl_volume->instance_idx(), m_volume);
@ -367,8 +370,7 @@ void GLGizmoEmboss::on_set_state()
// When add Text on empty plate, Create new object with volume // When add Text on empty plate, Create new object with volume
if (create_new_object) { if (create_new_object) {
set_default_configuration(); set_default_configuration();
TriangleMesh tm = m_default_mesh; // copy create_emboss_object(create_mesh(), create_volume_name(), create_configuration());
create_emboss_object(std::move(tm), create_volume_name(), create_configuration());
// gizmo will open when successfuly create new object // gizmo will open when successfuly create new object
GLGizmoBase::m_state = GLGizmoBase::Off; GLGizmoBase::m_state = GLGizmoBase::Off;
@ -449,7 +451,6 @@ void GLGizmoEmboss::initialize()
assert(success); assert(success);
load_font_list(); load_font_list();
// try to load valid font // try to load valid font
m_font_selected = 0; m_font_selected = 0;
bool is_font_loaded = load_font(); bool is_font_loaded = load_font();
@ -458,28 +459,7 @@ void GLGizmoEmboss::initialize()
m_font_list.erase(m_font_list.begin()); m_font_list.erase(m_font_list.begin());
is_font_loaded = load_font(); is_font_loaded = load_font();
} }
set_default_configuration(); set_default_configuration();
// create default mesh to faster add new volume
// solve state when no font loaded
if (is_font_loaded) {
// create default
ExPolygons shapes = Emboss::text2shapes(*m_font, m_text.c_str(), m_font_prop);
float scale = m_font_prop.size_in_mm / m_font->ascent;
float depth = m_font_prop.emboss / scale;
auto projectZ = std::make_unique<Emboss::ProjectZ>(depth);
Emboss::ProjectScale project(std::move(projectZ), scale);
m_default_mesh = TriangleMesh(Emboss::polygons2model(shapes, project));
} else {
// When cant load any font use default object loaded from file
std::string path = Slic3r::resources_dir() +
"/data/embossed_text.stl";
if (!load_obj(path.c_str(), &m_default_mesh)) {
// when can't load mesh use cube
m_default_mesh = TriangleMesh(its_make_cube(36., 4., 2.5));
}
}
} }
FontList GLGizmoEmboss::create_default_font_list() { FontList GLGizmoEmboss::create_default_font_list() {
@ -497,6 +477,41 @@ void GLGizmoEmboss::set_default_configuration()
load_font(); // reload actual font - because of font size load_font(); // reload actual font - because of font size
} }
Slic3r::TriangleMesh GLGizmoEmboss::create_default_mesh()
{
// When cant load any font use default object loaded from file
std::string path = Slic3r::resources_dir() + "/data/embossed_text.stl";
TriangleMesh triangle_mesh;
if (!load_obj(path.c_str(), &triangle_mesh)) {
// when can't load mesh use cube
return TriangleMesh(its_make_cube(36., 4., 2.5));
}
return triangle_mesh;
}
Slic3r::TriangleMesh GLGizmoEmboss::create_mesh()
{
// It is neccessary to create some shape
// Emboss text window is opened by creation new embosstext object
if (m_font == nullptr) return create_default_mesh();
TriangleMesh result = create_mesh(m_text.c_str(), *m_font, m_font_prop);
if (result.its.empty()) return create_default_mesh();
return result;
}
Slic3r::TriangleMesh GLGizmoEmboss::create_mesh(const char * text,
Emboss::Font &font,
const FontProp& font_prop)
{
ExPolygons shapes = Emboss::text2shapes(font, text, font_prop);
float scale = font_prop.size_in_mm / font.ascent;
float depth = font_prop.emboss / scale;
auto projectZ = std::make_unique<Emboss::ProjectZ>(depth);
Emboss::ProjectScale project(std::move(projectZ), scale);
return TriangleMesh(Emboss::polygons2model(shapes, project));
}
#include "imgui/imgui_internal.h" // to unfocus input --> ClearActiveID #include "imgui/imgui_internal.h" // to unfocus input --> ClearActiveID
void GLGizmoEmboss::check_selection() void GLGizmoEmboss::check_selection()
{ {
@ -618,9 +633,8 @@ void GLGizmoEmboss::draw_window()
if (ImGui::Button(_u8L("Generate preview").c_str())) { if (ImGui::Button(_u8L("Generate preview").c_str())) {
const Selection &s = m_parent.get_selection(); const Selection &s = m_parent.get_selection();
auto selected_indices = s.get_instance_idxs(); auto selected_indices = s.get_instance_idxs();
TriangleMesh mesh = m_default_mesh; // copy
if (selected_indices.empty()) { if (selected_indices.empty()) {
create_emboss_object(std::move(mesh), create_volume_name(), create_configuration()); create_emboss_object(create_mesh(), create_volume_name(), create_configuration());
} else { } else {
create_volume(ModelVolumeType::MODEL_PART); create_volume(ModelVolumeType::MODEL_PART);
} }
@ -629,51 +643,6 @@ void GLGizmoEmboss::draw_window()
m_imgui->disabled_end(); m_imgui->disabled_end();
} }
Transform3d GLGizmoEmboss::get_emboss_transformation(const Vec3f &position,
const Vec3f &emboss_dir)
{
// up and emboss direction for generated model
Vec3d text_up_dir = Vec3d::UnitY();
Vec3d text_emboss_dir = Vec3d::UnitZ();
// wanted up direction of result
Vec3d wanted_up_side = Vec3d::UnitZ();
if (std::fabs(emboss_dir.z()) > 0.9) wanted_up_side = Vec3d::UnitY();
Vec3d wanted_emboss_dir = emboss_dir.cast<double>();
wanted_emboss_dir.normalize(); // after cast from float it needs to be normalized again
// create perpendicular unit vector to surface triangle normal vector
// lay on surface of triangle and define up vector for text
Vec3d wanted_up_dir = wanted_emboss_dir.cross(wanted_up_side).cross(wanted_emboss_dir);
wanted_up_dir.normalize(); // normal3d is NOT perpendicular to normal_up_dir
// perpendicular to emboss vector of text and normal
Vec3d axis_view = text_emboss_dir.cross(wanted_emboss_dir);
double angle_view = std::acos(text_emboss_dir.dot(wanted_emboss_dir)); // in rad
axis_view.normalize();
Eigen::AngleAxis view_rot(angle_view, axis_view);
Vec3d wanterd_up_rotated = view_rot.matrix().inverse() * wanted_up_dir;
wanterd_up_rotated.normalize();
double angle_up = std::acos(text_up_dir.dot(wanterd_up_rotated));
// text_view and text_view2 should have same direction
Vec3d text_view2 = text_up_dir.cross(wanterd_up_rotated);
Vec3d diff_view = text_emboss_dir - text_view2;
if (std::fabs(diff_view.x()) > 1. || std::fabs(diff_view.y()) > 1. ||
std::fabs(diff_view.z()) > 1.) // oposit direction
angle_up *= -1.;
Eigen::AngleAxis up_rot(angle_up, text_emboss_dir);
Transform3d transform = Transform3d::Identity();
transform.translate(position.cast<double>());
transform.rotate(view_rot);
transform.rotate(up_rot);
return transform;
}
std::optional<Transform3d> GLGizmoEmboss::transform_on_surface( std::optional<Transform3d> GLGizmoEmboss::transform_on_surface(
const Vec2d &mouse_pos, const Vec2d &mouse_pos,
const std::vector<const MeshRaycaster *> &raycasters, const std::vector<const MeshRaycaster *> &raycasters,
@ -712,7 +681,7 @@ std::optional<Transform3d> GLGizmoEmboss::transform_on_surface(
// check exist hit // check exist hit
if (!closest.has_value()) return {}; if (!closest.has_value()) return {};
return get_emboss_transformation(closest->position, closest->normal); return Emboss::create_transformation_onto_surface(closest->position, closest->normal);
} }
void GLGizmoEmboss::draw_font_list() void GLGizmoEmboss::draw_font_list()

View File

@ -36,7 +36,17 @@ class GLGizmoEmboss : public GLGizmoBase
public: public:
GLGizmoEmboss(GLCanvas3D& parent); GLGizmoEmboss(GLCanvas3D& parent);
/// <summary>
/// Create new embossed text volume by type on position of mouse
/// </summary>
/// <param name="volume_type">Object part / Negative volume / Modifier</param>
/// <param name="mouse_pos">Define position of new volume</param>
void create_volume(ModelVolumeType volume_type, const Vec2d &mouse_pos = Vec2d(-1,-1)); void create_volume(ModelVolumeType volume_type, const Vec2d &mouse_pos = Vec2d(-1,-1));
/// <summary>
/// Move window for edit emboss text near to embossed object
/// NOTE: embossed object must be selected
/// </summary>
void set_fine_position(); void set_fine_position();
/// <summary> /// <summary>
@ -67,6 +77,21 @@ private:
void initialize(); void initialize();
static FontList create_default_font_list(); static FontList create_default_font_list();
void set_default_configuration(); void set_default_configuration();
TriangleMesh create_default_mesh();
TriangleMesh create_mesh();
/// <summary>
/// Create mesh from text
/// </summary>
/// <param name="text">Text to convert on mesh</param>
/// <param name="font">Define shape of characters.
/// NOTE: Can't be const cache glyphs</param>
/// <param name="font_prop">Property of font</param>
/// <returns>Triangle mesh model</returns>
static TriangleMesh create_mesh(const char * text,
Emboss::Font & font,
const FontProp &font_prop);
void check_selection(); void check_selection();
// more general function --> move to select // more general function --> move to select
ModelVolume *get_selected_volume(); ModelVolume *get_selected_volume();
@ -79,7 +104,7 @@ private:
void draw_font_list(); void draw_font_list();
void draw_text_input(); void draw_text_input();
void draw_advanced(); void draw_advanced();
// process mouse event
bool on_mouse_for_rotation(const wxMouseEvent &mouse_event); bool on_mouse_for_rotation(const wxMouseEvent &mouse_event);
bool on_mouse_for_translate(const wxMouseEvent &mouse_event); bool on_mouse_for_translate(const wxMouseEvent &mouse_event);
@ -105,8 +130,6 @@ private:
std::string create_volume_name(); std::string create_volume_name();
static Transform3d get_emboss_transformation(const Vec3f &position,
const Vec3f &emboss_dir);
std::optional<Transform3d> transform_on_surface(const Vec2d &mouse_pos, std::optional<Transform3d> transform_on_surface(const Vec2d &mouse_pos,
const std::vector<const MeshRaycaster *> &raycasters, const std::vector<const MeshRaycaster *> &raycasters,
const std::vector<Transform3d> & raycasters_tr const std::vector<Transform3d> & raycasters_tr
@ -151,7 +174,6 @@ private:
std::shared_ptr<Emboss::Font> m_font; std::shared_ptr<Emboss::Font> m_font;
std::string m_text; std::string m_text;
FontProp m_font_prop; FontProp m_font_prop;
TriangleMesh m_default_mesh; // when add new text this shape is used
// actual volume // actual volume
ModelVolume *m_volume; ModelVolume *m_volume;