mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-28 04:12:03 +08:00
Emboss SVG shape
This commit is contained in:
parent
b3d2dbeeb3
commit
51441bc5f0
@ -3508,6 +3508,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||||||
wxGetApp().obj_list()->update_selections();
|
wxGetApp().obj_list()->update_selections();
|
||||||
return;
|
return;
|
||||||
} else if (hover_volume->emboss_shape.has_value()) {
|
} else if (hover_volume->emboss_shape.has_value()) {
|
||||||
|
m_selection.add_volumes(Selection::EMode::Volume, {(unsigned) hover_volume_id});
|
||||||
if (type != GLGizmosManager::EType::Svg)
|
if (type != GLGizmosManager::EType::Svg)
|
||||||
m_gizmos.open_gizmo(GLGizmosManager::EType::Svg);
|
m_gizmos.open_gizmo(GLGizmosManager::EType::Svg);
|
||||||
wxGetApp().obj_list()->update_selections();
|
wxGetApp().obj_list()->update_selections();
|
||||||
|
@ -62,7 +62,6 @@
|
|||||||
#define SHOW_FINE_POSITION // draw convex hull around volume
|
#define SHOW_FINE_POSITION // draw convex hull around volume
|
||||||
#define DRAW_PLACE_TO_ADD_TEXT // Interactive draw of window position
|
#define DRAW_PLACE_TO_ADD_TEXT // Interactive draw of window position
|
||||||
#define ALLOW_OPEN_NEAR_VOLUME
|
#define ALLOW_OPEN_NEAR_VOLUME
|
||||||
#define EXECUTE_PROCESS_ON_MAIN_THREAD // debug execution on main thread
|
|
||||||
#endif // ALLOW_DEBUG_MODE
|
#endif // ALLOW_DEBUG_MODE
|
||||||
|
|
||||||
//#define USE_PIXEL_SIZE_IN_WX_FONT
|
//#define USE_PIXEL_SIZE_IN_WX_FONT
|
||||||
@ -797,16 +796,10 @@ void GLGizmoEmboss::on_set_state()
|
|||||||
// change position of just opened emboss window
|
// change position of just opened emboss window
|
||||||
if (m_allow_open_near_volume) {
|
if (m_allow_open_near_volume) {
|
||||||
m_set_window_offset = calc_fine_position(m_parent.get_selection(), get_minimal_window_size(), m_parent.get_canvas_size());
|
m_set_window_offset = calc_fine_position(m_parent.get_selection(), get_minimal_window_size(), m_parent.get_canvas_size());
|
||||||
} else {
|
} else {
|
||||||
if (m_gui_cfg != nullptr)
|
m_set_window_offset = (m_gui_cfg != nullptr) ?
|
||||||
m_set_window_offset = ImGuiWrapper::change_window_position(on_get_name().c_str(), false);
|
ImGuiWrapper::change_window_position(on_get_name().c_str(), false) : ImVec2(-1, -1);
|
||||||
else
|
|
||||||
m_set_window_offset = ImVec2(-1, -1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// when open by hyperlink it needs to show up
|
|
||||||
// or after key 'T' windows doesn't appear
|
|
||||||
m_parent.set_as_dirty();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1110,29 +1103,6 @@ void GLGizmoEmboss::calculate_scale() {
|
|||||||
m_style_manager.clear_imgui_font();
|
m_style_manager.clear_imgui_font();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef EXECUTE_PROCESS_ON_MAIN_THREAD
|
|
||||||
namespace priv {
|
|
||||||
// Run Job on main thread (blocking) - ONLY DEBUG
|
|
||||||
static inline void execute_job(std::shared_ptr<Job> j)
|
|
||||||
{
|
|
||||||
struct MyCtl : public Job::Ctl
|
|
||||||
{
|
|
||||||
void update_status(int st, const std::string &msg = "") override{};
|
|
||||||
bool was_canceled() const override { return false; }
|
|
||||||
std::future<void> call_on_main_thread(std::function<void()> fn) override
|
|
||||||
{
|
|
||||||
return std::future<void>{};
|
|
||||||
}
|
|
||||||
} ctl;
|
|
||||||
j->process(ctl);
|
|
||||||
wxGetApp().plater()->CallAfter([j]() {
|
|
||||||
std::exception_ptr e_ptr = nullptr;
|
|
||||||
j->finalize(false, e_ptr);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} // namespace priv
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool GLGizmoEmboss::process()
|
bool GLGizmoEmboss::process()
|
||||||
{
|
{
|
||||||
// no volume is selected -> selection from right panel
|
// no volume is selected -> selection from right panel
|
||||||
@ -1151,50 +1121,12 @@ bool GLGizmoEmboss::process()
|
|||||||
if (!m_volume->emboss_shape.has_value()) return false;
|
if (!m_volume->emboss_shape.has_value()) return false;
|
||||||
|
|
||||||
DataUpdate data{create_emboss_data_base(m_text, m_style_manager, m_job_cancel), m_volume->id()};
|
DataUpdate data{create_emboss_data_base(m_text, m_style_manager, m_job_cancel), m_volume->id()};
|
||||||
std::unique_ptr<Job> job = nullptr;
|
bool start = start_update_volume(std::move(data), *m_volume, m_parent.get_selection(), m_raycast_manager);
|
||||||
|
if (start)
|
||||||
|
// notification is removed befor object is changed by job
|
||||||
|
remove_notification_not_valid_font();
|
||||||
|
|
||||||
// check cutting from source mesh
|
return start;
|
||||||
bool &use_surface = data.base->shape.projection.use_surface;
|
|
||||||
if (use_surface && m_volume->is_the_only_one_part())
|
|
||||||
use_surface = false;
|
|
||||||
|
|
||||||
if (use_surface) {
|
|
||||||
// Model to cut surface from.
|
|
||||||
SurfaceVolumeData::ModelSources sources = create_volume_sources(*m_volume);
|
|
||||||
if (sources.empty()) return false;
|
|
||||||
|
|
||||||
Transform3d text_tr = m_volume->get_matrix();
|
|
||||||
auto& fix_3mf = m_volume->emboss_shape->fix_3mf_tr;
|
|
||||||
if (fix_3mf.has_value())
|
|
||||||
text_tr = text_tr * fix_3mf->inverse();
|
|
||||||
|
|
||||||
// when it is new applying of use surface than move origin onto surfaca
|
|
||||||
if (!m_volume->emboss_shape->projection.use_surface) {
|
|
||||||
auto offset = calc_surface_offset(m_parent.get_selection(), m_raycast_manager);
|
|
||||||
if (offset.has_value())
|
|
||||||
text_tr *= Eigen::Translation<double, 3>(*offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
UpdateSurfaceVolumeData surface_data{std::move(data), {text_tr, is_outside, std::move(sources)}};
|
|
||||||
job = std::make_unique<UpdateSurfaceVolumeJob>(std::move(surface_data));
|
|
||||||
} else {
|
|
||||||
job = std::make_unique<UpdateJob>(std::move(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef EXECUTE_PROCESS_ON_MAIN_THREAD
|
|
||||||
auto &worker = wxGetApp().plater()->get_ui_job_worker();
|
|
||||||
queue_job(worker, std::move(job));
|
|
||||||
#else
|
|
||||||
// Run Job on main thread (blocking) - ONLY DEBUG
|
|
||||||
priv::execute_job(std::move(job));
|
|
||||||
#endif // EXECUTE_PROCESS_ON_MAIN_THREAD
|
|
||||||
|
|
||||||
// notification is removed befor object is changed by job
|
|
||||||
remove_notification_not_valid_font();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -2475,38 +2407,6 @@ bool GLGizmoEmboss::rev_slider(const std::string &name,
|
|||||||
undo_tooltip, undo_offset, draw_slider_float);
|
undo_tooltip, undo_offset, draw_slider_float);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoEmboss::do_translate(const Vec3d &relative_move)
|
|
||||||
{
|
|
||||||
assert(m_volume != nullptr);
|
|
||||||
assert(m_volume->text_configuration.has_value());
|
|
||||||
Selection &selection = m_parent.get_selection();
|
|
||||||
assert(!selection.is_empty());
|
|
||||||
selection.setup_cache();
|
|
||||||
selection.translate(relative_move, TransformationType::Local);
|
|
||||||
|
|
||||||
std::string snapshot_name; // empty mean no store undo / redo
|
|
||||||
// NOTE: it use L instead of _L macro because prefix _ is appended inside
|
|
||||||
// function do_move
|
|
||||||
// snapshot_name = L("Set surface distance");
|
|
||||||
m_parent.do_move(snapshot_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLGizmoEmboss::do_rotate(float relative_z_angle)
|
|
||||||
{
|
|
||||||
assert(m_volume != nullptr);
|
|
||||||
assert(m_volume->text_configuration.has_value());
|
|
||||||
Selection &selection = m_parent.get_selection();
|
|
||||||
assert(!selection.is_empty());
|
|
||||||
selection.setup_cache();
|
|
||||||
selection.rotate(Vec3d(0., 0., relative_z_angle), get_transformation_type(selection));
|
|
||||||
|
|
||||||
std::string snapshot_name; // empty meand no store undo / redo
|
|
||||||
// NOTE: it use L instead of _L macro because prefix _ is appended
|
|
||||||
// inside function do_move
|
|
||||||
// snapshot_name = L("Set text rotation");
|
|
||||||
m_parent.do_rotate(snapshot_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLGizmoEmboss::draw_advanced()
|
void GLGizmoEmboss::draw_advanced()
|
||||||
{
|
{
|
||||||
const auto &ff = m_style_manager.get_font_file_with_cache();
|
const auto &ff = m_style_manager.get_font_file_with_cache();
|
||||||
|
@ -35,15 +35,9 @@ using namespace Slic3r::Emboss;
|
|||||||
using namespace Slic3r::GUI;
|
using namespace Slic3r::GUI;
|
||||||
using namespace Slic3r::GUI::Emboss;
|
using namespace Slic3r::GUI::Emboss;
|
||||||
|
|
||||||
namespace priv {
|
|
||||||
|
|
||||||
} // namespace priv
|
|
||||||
|
|
||||||
GLGizmoSVG::GLGizmoSVG(GLCanvas3D &parent)
|
GLGizmoSVG::GLGizmoSVG(GLCanvas3D &parent)
|
||||||
: GLGizmoBase(parent, M_ICON_FILENAME, -3)
|
: GLGizmoBase(parent, M_ICON_FILENAME, -3)
|
||||||
, m_volume(nullptr)
|
|
||||||
, m_rotate_gizmo(parent, GLGizmoRotate::Axis::Z) // grab id = 2 (Z axis)
|
, m_rotate_gizmo(parent, GLGizmoRotate::Axis::Z) // grab id = 2 (Z axis)
|
||||||
, m_job_cancel(nullptr)
|
|
||||||
{
|
{
|
||||||
m_rotate_gizmo.set_group_id(0);
|
m_rotate_gizmo.set_group_id(0);
|
||||||
m_rotate_gizmo.set_force_local_coordinate(true);
|
m_rotate_gizmo.set_force_local_coordinate(true);
|
||||||
@ -111,8 +105,39 @@ std::string volume_name(const EmbossShape& shape);
|
|||||||
/// <param name="volume_type">Type of volume to be created</param>
|
/// <param name="volume_type">Type of volume to be created</param>
|
||||||
/// <returns>Params</returns>
|
/// <returns>Params</returns>
|
||||||
CreateVolumeParams create_input(GLCanvas3D &canvas, RaycastManager &raycaster, ModelVolumeType volume_type);
|
CreateVolumeParams create_input(GLCanvas3D &canvas, RaycastManager &raycaster, ModelVolumeType volume_type);
|
||||||
|
|
||||||
|
// This configs holds GUI layout size given by translated texts.
|
||||||
|
// etc. When language changes, GUI is recreated and this class constructed again,
|
||||||
|
// so the change takes effect. (info by GLGizmoFdmSupports.hpp)
|
||||||
|
struct GuiCfg
|
||||||
|
{
|
||||||
|
// Detect invalid config values when change monitor DPI
|
||||||
|
double screen_scale;
|
||||||
|
float main_toolbar_height;
|
||||||
|
|
||||||
|
// Zero means it is calculated in init function
|
||||||
|
ImVec2 minimal_window_size = ImVec2(0, 0);
|
||||||
|
|
||||||
|
float input_width = 0.f;
|
||||||
|
float input_offset = 0.f;
|
||||||
|
|
||||||
|
float icon_width = 0.f;
|
||||||
|
// Only translations needed for calc GUI size
|
||||||
|
struct Translations
|
||||||
|
{
|
||||||
|
std::string depth;
|
||||||
|
std::string use_surface;
|
||||||
|
std::string rotation;
|
||||||
|
std::string distance; // from surface
|
||||||
|
};
|
||||||
|
Translations translations;
|
||||||
|
};
|
||||||
|
GuiCfg create_gui_configuration();
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
// use private definition
|
||||||
|
struct GLGizmoSVG::GuiCfg: public ::GuiCfg{};
|
||||||
|
|
||||||
bool GLGizmoSVG::create_volume(ModelVolumeType volume_type, const Vec2d &mouse_pos)
|
bool GLGizmoSVG::create_volume(ModelVolumeType volume_type, const Vec2d &mouse_pos)
|
||||||
{
|
{
|
||||||
@ -150,9 +175,8 @@ bool GLGizmoSVG::on_mouse_for_rotation(const wxMouseEvent &mouse_event)
|
|||||||
if (!m_dragging) return used;
|
if (!m_dragging) return used;
|
||||||
|
|
||||||
if (mouse_event.Dragging()) {
|
if (mouse_event.Dragging()) {
|
||||||
auto &angle_opt = m_volume->text_configuration->style.prop.angle;
|
|
||||||
if (!m_rotate_start_angle.has_value())
|
if (!m_rotate_start_angle.has_value())
|
||||||
m_rotate_start_angle = angle_opt.has_value() ? *angle_opt : 0.f;
|
m_rotate_start_angle = m_angle.value_or(0.f);
|
||||||
double angle = m_rotate_gizmo.get_angle();
|
double angle = m_rotate_gizmo.get_angle();
|
||||||
angle -= PI / 2; // Grabber is upward
|
angle -= PI / 2; // Grabber is upward
|
||||||
|
|
||||||
@ -165,11 +189,11 @@ bool GLGizmoSVG::on_mouse_for_rotation(const wxMouseEvent &mouse_event)
|
|||||||
// move to range <-M_PI, M_PI>
|
// move to range <-M_PI, M_PI>
|
||||||
Geometry::to_range_pi_pi(angle);
|
Geometry::to_range_pi_pi(angle);
|
||||||
// propagate angle into property
|
// propagate angle into property
|
||||||
angle_opt = static_cast<float>(angle);
|
m_angle = static_cast<float>(angle);
|
||||||
|
|
||||||
// do not store zero
|
// do not store zero
|
||||||
if (is_approx(*angle_opt, 0.f))
|
if (is_approx(*m_angle, 0.f))
|
||||||
angle_opt.reset();
|
m_angle.reset();
|
||||||
}
|
}
|
||||||
return used;
|
return used;
|
||||||
}
|
}
|
||||||
@ -192,7 +216,7 @@ bool GLGizmoSVG::on_mouse_for_translate(const wxMouseEvent &mouse_event)
|
|||||||
// End with surface dragging?
|
// End with surface dragging?
|
||||||
if (was_dragging && !is_dragging) {
|
if (was_dragging && !is_dragging) {
|
||||||
// Update surface by new position
|
// Update surface by new position
|
||||||
if (m_volume->text_configuration->style.prop.use_surface)
|
if (m_volume->emboss_shape->projection.use_surface)
|
||||||
process();
|
process();
|
||||||
|
|
||||||
// Show correct value of height & depth inside of inputs
|
// Show correct value of height & depth inside of inputs
|
||||||
@ -226,7 +250,7 @@ bool GLGizmoSVG::on_mouse(const wxMouseEvent &mouse_event)
|
|||||||
// not selected volume
|
// not selected volume
|
||||||
if (m_volume == nullptr ||
|
if (m_volume == nullptr ||
|
||||||
get_model_volume(m_volume_id, m_parent.get_selection().get_model()->objects) == nullptr ||
|
get_model_volume(m_volume_id, m_parent.get_selection().get_model()->objects) == nullptr ||
|
||||||
!m_volume->text_configuration.has_value()) return false;
|
!m_volume->emboss_shape.has_value()) return false;
|
||||||
|
|
||||||
if (on_mouse_for_rotation(mouse_event)) return true;
|
if (on_mouse_for_rotation(mouse_event)) return true;
|
||||||
if (on_mouse_for_translate(mouse_event)) return true;
|
if (on_mouse_for_translate(mouse_event)) return true;
|
||||||
@ -244,10 +268,6 @@ bool GLGizmoSVG::on_init()
|
|||||||
m_rotate_gizmo.init();
|
m_rotate_gizmo.init();
|
||||||
ColorRGBA gray_color(.6f, .6f, .6f, .3f);
|
ColorRGBA gray_color(.6f, .6f, .6f, .3f);
|
||||||
m_rotate_gizmo.set_highlight_color(gray_color);
|
m_rotate_gizmo.set_highlight_color(gray_color);
|
||||||
|
|
||||||
// No shortCut
|
|
||||||
// m_shortcut_key = WXK_CONTROL_T;
|
|
||||||
|
|
||||||
// Set rotation gizmo upwardrotate
|
// Set rotation gizmo upwardrotate
|
||||||
m_rotate_gizmo.set_angle(PI / 2);
|
m_rotate_gizmo.set_angle(PI / 2);
|
||||||
return true;
|
return true;
|
||||||
@ -292,15 +312,18 @@ void GLGizmoSVG::on_render_input_window(float x, float y, float bottom_limit)
|
|||||||
// Configuration creation
|
// Configuration creation
|
||||||
double screen_scale = wxDisplay(wxGetApp().plater()).GetScaleFactor();
|
double screen_scale = wxDisplay(wxGetApp().plater()).GetScaleFactor();
|
||||||
float main_toolbar_height = m_parent.get_main_toolbar_height();
|
float main_toolbar_height = m_parent.get_main_toolbar_height();
|
||||||
if (!m_gui_cfg.has_value() || // Exist configuration - first run
|
if (m_gui_cfg == nullptr || // Exist configuration - first run
|
||||||
m_gui_cfg->screen_scale != screen_scale || // change of DPI
|
m_gui_cfg->screen_scale != screen_scale || // change of DPI
|
||||||
m_gui_cfg->main_toolbar_height != main_toolbar_height // change size of view port
|
m_gui_cfg->main_toolbar_height != main_toolbar_height // change size of view port
|
||||||
) {
|
) {
|
||||||
// Create cache for gui offsets
|
// Create cache for gui offsets
|
||||||
GuiCfg cfg = create_gui_configuration();
|
::GuiCfg cfg = create_gui_configuration();
|
||||||
cfg.screen_scale = screen_scale;
|
cfg.screen_scale = screen_scale;
|
||||||
cfg.main_toolbar_height = main_toolbar_height;
|
cfg.main_toolbar_height = main_toolbar_height;
|
||||||
m_gui_cfg.emplace(std::move(cfg));
|
|
||||||
|
GuiCfg gui_cfg{std::move(cfg)};
|
||||||
|
m_gui_cfg = std::make_unique<const GuiCfg>(std::move(gui_cfg));
|
||||||
|
|
||||||
// set position near toolbar
|
// set position near toolbar
|
||||||
m_set_window_offset = ImVec2(-1.f, -1.f);
|
m_set_window_offset = ImVec2(-1.f, -1.f);
|
||||||
}
|
}
|
||||||
@ -358,29 +381,13 @@ void GLGizmoSVG::on_set_state()
|
|||||||
|
|
||||||
// Closing gizmo. e.g. selecting another one
|
// Closing gizmo. e.g. selecting another one
|
||||||
if (GLGizmoBase::m_state == GLGizmoBase::Off) {
|
if (GLGizmoBase::m_state == GLGizmoBase::Off) {
|
||||||
// refuse outgoing during text preview
|
|
||||||
if (false) {
|
|
||||||
GLGizmoBase::m_state = GLGizmoBase::On;
|
|
||||||
auto notification_manager = wxGetApp().plater()->get_notification_manager();
|
|
||||||
notification_manager->push_notification(
|
|
||||||
NotificationType::CustomNotification,
|
|
||||||
NotificationManager::NotificationLevel::RegularNotificationLevel,
|
|
||||||
_u8L("ERROR: Wait until ends or Cancel process."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
reset_volume();
|
reset_volume();
|
||||||
} else if (GLGizmoBase::m_state == GLGizmoBase::On) {
|
} else if (GLGizmoBase::m_state == GLGizmoBase::On) {
|
||||||
// Try(when exist) set text configuration by volume
|
// Try(when exist) set text configuration by volume
|
||||||
set_volume_by_selection();
|
set_volume_by_selection();
|
||||||
|
|
||||||
if (!m_gui_cfg.has_value())
|
m_set_window_offset = (m_gui_cfg != nullptr) ?
|
||||||
m_set_window_offset = ImGuiWrapper::change_window_position(on_get_name().c_str(), false);
|
ImGuiWrapper::change_window_position(on_get_name().c_str(), false) : ImVec2(-1, -1);
|
||||||
else
|
|
||||||
m_set_window_offset = ImVec2(-1, -1);
|
|
||||||
|
|
||||||
// when open by hyperlink it needs to show up
|
|
||||||
// or after key 'T' windows doesn't appear
|
|
||||||
// m_parent.set_as_dirty();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,14 +420,6 @@ void GLGizmoSVG::on_stop_dragging()
|
|||||||
}
|
}
|
||||||
void GLGizmoSVG::on_dragging(const UpdateData &data) { m_rotate_gizmo.dragging(data); }
|
void GLGizmoSVG::on_dragging(const UpdateData &data) { m_rotate_gizmo.dragging(data); }
|
||||||
|
|
||||||
GLGizmoSVG::GuiCfg GLGizmoSVG::create_gui_configuration()
|
|
||||||
{
|
|
||||||
GuiCfg cfg; // initialize by default values;
|
|
||||||
|
|
||||||
|
|
||||||
return cfg;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLGizmoSVG::set_volume_by_selection()
|
void GLGizmoSVG::set_volume_by_selection()
|
||||||
{
|
{
|
||||||
const Selection &selection = m_parent.get_selection();
|
const Selection &selection = m_parent.get_selection();
|
||||||
@ -454,6 +453,7 @@ void GLGizmoSVG::set_volume_by_selection()
|
|||||||
|
|
||||||
m_volume = volume;
|
m_volume = volume;
|
||||||
m_volume_id = volume->id();
|
m_volume_id = volume->id();
|
||||||
|
m_volume_shape = *volume->emboss_shape; // copy
|
||||||
|
|
||||||
// Calculate current angle of up vector
|
// Calculate current angle of up vector
|
||||||
m_angle = calc_up(gl_volume->world_matrix(), Slic3r::GUI::up_limit);
|
m_angle = calc_up(gl_volume->world_matrix(), Slic3r::GUI::up_limit);
|
||||||
@ -469,6 +469,7 @@ void GLGizmoSVG::reset_volume()
|
|||||||
|
|
||||||
m_volume = nullptr;
|
m_volume = nullptr;
|
||||||
m_volume_id.id = 0;
|
m_volume_id.id = 0;
|
||||||
|
m_volume_shape.shapes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoSVG::calculate_scale() {
|
void GLGizmoSVG::calculate_scale() {
|
||||||
@ -496,51 +497,25 @@ bool GLGizmoSVG::process()
|
|||||||
{
|
{
|
||||||
// no volume is selected -> selection from right panel
|
// no volume is selected -> selection from right panel
|
||||||
assert(m_volume != nullptr);
|
assert(m_volume != nullptr);
|
||||||
if (m_volume == nullptr) return false;
|
if (m_volume == nullptr)
|
||||||
|
return false;
|
||||||
//DataUpdate data{create_emboss_data_base(m_text, m_style_manager, m_job_cancel), m_volume->id()};
|
|
||||||
|
assert(m_volume->emboss_shape.has_value());
|
||||||
|
if (!m_volume->emboss_shape.has_value())
|
||||||
|
return false;
|
||||||
|
|
||||||
//std::unique_ptr<Job> job = nullptr;
|
// Cancel previous Job, when it is in process
|
||||||
|
// worker.cancel(); --> Use less in this case I want cancel only previous EmbossJob no other jobs
|
||||||
|
// Cancel only EmbossUpdateJob no others
|
||||||
|
if (m_job_cancel != nullptr)
|
||||||
|
m_job_cancel->store(true);
|
||||||
|
// create new shared ptr to cancel new job
|
||||||
|
m_job_cancel = std::make_shared<std::atomic<bool>>(false);
|
||||||
|
|
||||||
//// check cutting from source mesh
|
EmbossShape shape = m_volume_shape; // copy
|
||||||
//bool &use_surface = data.text_configuration.style.prop.use_surface;
|
auto base = std::make_unique<DataBase>(m_volume->name, m_job_cancel, std::move(shape));
|
||||||
//bool is_object = m_volume->get_object()->volumes.size() == 1;
|
DataUpdate data{std::move(base), m_volume_id};
|
||||||
//if (use_surface && is_object)
|
return start_update_volume(std::move(data), *m_volume, m_parent.get_selection(), m_raycast_manager);
|
||||||
// use_surface = false;
|
|
||||||
//
|
|
||||||
//if (use_surface) {
|
|
||||||
// // Model to cut surface from.
|
|
||||||
// SurfaceVolumeData::ModelSources sources = create_volume_sources(m_volume);
|
|
||||||
// if (sources.empty()) return false;
|
|
||||||
|
|
||||||
// Transform3d text_tr = m_volume->get_matrix();
|
|
||||||
// auto& fix_3mf = m_volume->text_configuration->fix_3mf_tr;
|
|
||||||
// if (fix_3mf.has_value())
|
|
||||||
// text_tr = text_tr * fix_3mf->inverse();
|
|
||||||
|
|
||||||
// // when it is new applying of use surface than move origin onto surfaca
|
|
||||||
// if (!m_volume->text_configuration->style.prop.use_surface) {
|
|
||||||
// auto offset = calc_surface_offset(*m_volume, m_raycast_manager, m_parent.get_selection());
|
|
||||||
// if (offset.has_value())
|
|
||||||
// text_tr *= Eigen::Translation<double, 3>(*offset);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 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());
|
|
||||||
// UpdateSurfaceVolumeData surface_data{std::move(data), {text_tr, is_outside, std::move(sources)}};
|
|
||||||
// job = std::make_unique<UpdateSurfaceVolumeJob>(std::move(surface_data));
|
|
||||||
//} else {
|
|
||||||
// job = std::make_unique<UpdateJob>(std::move(data));
|
|
||||||
//}
|
|
||||||
|
|
||||||
//auto &worker = wxGetApp().plater()->get_ui_job_worker();
|
|
||||||
//queue_job(worker, std::move(job));
|
|
||||||
|
|
||||||
//// notification is removed befor object is changed by job
|
|
||||||
//remove_notification_not_valid_font();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoSVG::close()
|
void GLGizmoSVG::close()
|
||||||
@ -555,18 +530,54 @@ void GLGizmoSVG::draw_window()
|
|||||||
{
|
{
|
||||||
if (m_volume != nullptr && m_volume->emboss_shape.has_value())
|
if (m_volume != nullptr && m_volume->emboss_shape.has_value())
|
||||||
ImGui::Text("SVG file path is %s", m_volume->emboss_shape->svg_file_path.c_str());
|
ImGui::Text("SVG file path is %s", m_volume->emboss_shape->svg_file_path.c_str());
|
||||||
//draw_use_surface();
|
|
||||||
|
ImGui::Indent(m_gui_cfg->icon_width);
|
||||||
|
draw_depth();
|
||||||
|
draw_use_surface();
|
||||||
draw_distance();
|
draw_distance();
|
||||||
draw_rotation();
|
draw_rotation();
|
||||||
|
ImGui::Unindent(m_gui_cfg->icon_width);
|
||||||
|
|
||||||
if (ImGui::Button("change file")) {
|
if (ImGui::Button("change file")) {
|
||||||
auto data = create_emboss_data_base(m_job_cancel);
|
auto data = create_emboss_data_base(m_job_cancel);
|
||||||
std::string file = choose_svg_file();
|
std::string file = ::choose_svg_file();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
draw_model_type();
|
draw_model_type();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLGizmoSVG::draw_depth()
|
||||||
|
{
|
||||||
|
ImGuiWrapper::text(m_gui_cfg->translations.depth);
|
||||||
|
ImGui::SameLine(m_gui_cfg->input_offset);
|
||||||
|
ImGui::SetNextItemWidth(m_gui_cfg->input_width);
|
||||||
|
|
||||||
|
bool use_inch = wxGetApp().app_config->get_bool("use_inches");
|
||||||
|
double &value = m_volume_shape.projection.depth;
|
||||||
|
const wxString tooltip = _L("Size in emboss direction.");
|
||||||
|
if (use_inch) {
|
||||||
|
const char *size_format = "%.2f in";
|
||||||
|
double value_inch = value * ObjectManipulation::mm_to_in;
|
||||||
|
if (ImGui::InputDouble("##depth", &value_inch, 1., 10., size_format)) {
|
||||||
|
value = value_inch * ObjectManipulation::in_to_mm;
|
||||||
|
process();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const char *size_format = "%.1f mm";
|
||||||
|
if (ImGui::InputDouble("##depth", &value, 1., 10., size_format))
|
||||||
|
process();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoSVG::draw_use_surface()
|
||||||
|
{
|
||||||
|
ImGuiWrapper::text(m_gui_cfg->translations.use_surface);
|
||||||
|
ImGui::SameLine(m_gui_cfg->input_offset);
|
||||||
|
|
||||||
|
if (ImGui::Checkbox("##useSurface", &m_volume_shape.projection.use_surface))
|
||||||
|
process();
|
||||||
|
}
|
||||||
|
|
||||||
void GLGizmoSVG::draw_distance()
|
void GLGizmoSVG::draw_distance()
|
||||||
{
|
{
|
||||||
@ -584,7 +595,10 @@ void GLGizmoSVG::draw_distance()
|
|||||||
m_imgui->disabled_begin(!allowe_surface_distance);
|
m_imgui->disabled_begin(!allowe_surface_distance);
|
||||||
ScopeGuard sg([imgui = m_imgui]() { imgui->disabled_end(); });
|
ScopeGuard sg([imgui = m_imgui]() { imgui->disabled_end(); });
|
||||||
|
|
||||||
ImGuiWrapper::text(_L("distance"));
|
ImGuiWrapper::text(m_gui_cfg->translations.distance);
|
||||||
|
ImGui::SameLine(m_gui_cfg->input_offset);
|
||||||
|
ImGui::SetNextItemWidth(m_gui_cfg->input_width);
|
||||||
|
|
||||||
bool use_inch = wxGetApp().app_config->get_bool("use_inches");
|
bool use_inch = wxGetApp().app_config->get_bool("use_inches");
|
||||||
const wxString move_tooltip = _L("Distance of the center of the text to the model surface.");
|
const wxString move_tooltip = _L("Distance of the center of the text to the model surface.");
|
||||||
bool is_moved = false;
|
bool is_moved = false;
|
||||||
@ -606,13 +620,16 @@ void GLGizmoSVG::draw_distance()
|
|||||||
is_moved = true;
|
is_moved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
float undo_offset = ImGui::GetStyle().FramePadding.x;
|
m_imgui->disabled_begin(!m_distance.has_value() && allowe_surface_distance);
|
||||||
ImGui::SameLine(undo_offset);
|
ScopeGuard sg2([imgui = m_imgui]() { imgui->disabled_end(); });
|
||||||
|
|
||||||
|
float reset_offset = ImGui::GetStyle().FramePadding.x;
|
||||||
|
ImGui::SameLine(reset_offset);
|
||||||
if (ImGui::Button("R##distance_reset")){
|
if (ImGui::Button("R##distance_reset")){
|
||||||
m_distance.reset();
|
m_distance.reset();
|
||||||
is_moved = true;
|
is_moved = true;
|
||||||
} else if (ImGui::IsItemHovered())
|
} else if (ImGui::IsItemHovered())
|
||||||
ImGui::SetTooltip("%s", _u8L("Reset distance to zero value"));
|
ImGui::SetTooltip("%s", _u8L("Reset distance to zero value").c_str());
|
||||||
|
|
||||||
if (is_moved)
|
if (is_moved)
|
||||||
do_local_z_move(m_parent, m_distance.value_or(.0f) - prev_distance);
|
do_local_z_move(m_parent, m_distance.value_or(.0f) - prev_distance);
|
||||||
@ -622,13 +639,18 @@ void GLGizmoSVG::draw_rotation()
|
|||||||
{
|
{
|
||||||
if (m_volume == nullptr)
|
if (m_volume == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
ImGuiWrapper::text(m_gui_cfg->translations.rotation);
|
||||||
|
ImGui::SameLine(m_gui_cfg->input_offset);
|
||||||
|
ImGui::SetNextItemWidth(m_gui_cfg->input_width);
|
||||||
|
|
||||||
// slider for Clock-wise angle in degress
|
// slider for Clock-wise angle in degress
|
||||||
// stored angle is optional CCW and in radians
|
// stored angle is optional CCW and in radians
|
||||||
// Convert stored value to degress
|
// Convert stored value to degress
|
||||||
// minus create clock-wise roation from CCW
|
// minus create clock-wise roation from CCW
|
||||||
float angle = m_angle.value_or(0.f);
|
float angle = m_angle.value_or(0.f);
|
||||||
float angle_deg = static_cast<float>(-angle * 180 / M_PI);
|
float angle_deg = static_cast<float>(-angle * 180 / M_PI);
|
||||||
if (m_imgui->slider_float("##angle", &angle, limits.angle.min, limits.angle.max, u8"%.2f DEG", 1.f, false, _L("Rotate text Clock-wise."))){
|
if (m_imgui->slider_float("##angle", &angle_deg, limits.angle.min, limits.angle.max, u8"%.2f DEG", 1.f, false, _L("Rotate text Clock-wise."))){
|
||||||
// convert back to radians and CCW
|
// convert back to radians and CCW
|
||||||
double angle_rad = -angle_deg * M_PI / 180.0;
|
double angle_rad = -angle_deg * M_PI / 180.0;
|
||||||
Geometry::to_range_pi_pi(angle_rad);
|
Geometry::to_range_pi_pi(angle_rad);
|
||||||
@ -645,6 +667,22 @@ void GLGizmoSVG::draw_rotation()
|
|||||||
process();
|
process();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset button
|
||||||
|
m_imgui->disabled_begin(!m_angle.has_value());
|
||||||
|
ScopeGuard sg([imgui = m_imgui]() { imgui->disabled_end(); });
|
||||||
|
|
||||||
|
float reset_offset = ImGui::GetStyle().FramePadding.x;
|
||||||
|
ImGui::SameLine(reset_offset);
|
||||||
|
if (ImGui::Button("R##angle_reset")) {
|
||||||
|
do_local_z_rotate(m_parent, -(*m_angle));
|
||||||
|
m_angle.reset();
|
||||||
|
|
||||||
|
// recalculate for surface cut
|
||||||
|
if (m_volume->emboss_shape->projection.use_surface)
|
||||||
|
process();
|
||||||
|
} else if (ImGui::IsItemHovered())
|
||||||
|
ImGui::SetTooltip("%s", _u8L("Reset rotation to zero value").c_str());
|
||||||
|
|
||||||
// Keep up - lock button icon
|
// Keep up - lock button icon
|
||||||
//ImGui::SameLine(m_gui_cfg->lock_offset);
|
//ImGui::SameLine(m_gui_cfg->lock_offset);
|
||||||
//const IconManager::Icon &icon = get_icon(m_icons, m_keep_up ? IconType::lock : IconType::unlock, IconState::activable);
|
//const IconManager::Icon &icon = get_icon(m_icons, m_keep_up ? IconType::lock : IconType::unlock, IconState::activable);
|
||||||
@ -788,6 +826,39 @@ CreateVolumeParams create_input(GLCanvas3D &canvas, RaycastManager& raycaster, M
|
|||||||
plater->get_ui_job_worker(), volume_type, raycaster, gizmo, gl_volume};
|
plater->get_ui_job_worker(), volume_type, raycaster, gizmo, gl_volume};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GuiCfg create_gui_configuration() {
|
||||||
|
GuiCfg cfg; // initialize by default values;
|
||||||
|
|
||||||
|
float line_height = ImGui::GetTextLineHeight();
|
||||||
|
float line_height_with_spacing = ImGui::GetTextLineHeightWithSpacing();
|
||||||
|
|
||||||
|
float space = line_height_with_spacing - line_height;
|
||||||
|
|
||||||
|
cfg.icon_width = line_height;
|
||||||
|
|
||||||
|
GuiCfg::Translations &tr = cfg.translations;
|
||||||
|
|
||||||
|
tr.depth = _u8L("Depth");
|
||||||
|
tr.use_surface = _u8L("Use surface");
|
||||||
|
tr.distance = _u8L("From surface");
|
||||||
|
tr.rotation = _u8L("Rotation");
|
||||||
|
float max_tr_width = std::max({
|
||||||
|
ImGui::CalcTextSize(tr.depth.c_str()).x,
|
||||||
|
ImGui::CalcTextSize(tr.use_surface.c_str()).x,
|
||||||
|
ImGui::CalcTextSize(tr.distance.c_str()).x,
|
||||||
|
ImGui::CalcTextSize(tr.rotation.c_str()).x,
|
||||||
|
});
|
||||||
|
|
||||||
|
const ImGuiStyle &style = ImGui::GetStyle();
|
||||||
|
cfg.input_offset = style.WindowPadding.x + max_tr_width + space + cfg.icon_width;
|
||||||
|
|
||||||
|
ImVec2 letter_m_size = ImGui::CalcTextSize("M");
|
||||||
|
const float count_letter_M_in_input = 12.f;
|
||||||
|
cfg.input_width = letter_m_size.x * count_letter_M_in_input;
|
||||||
|
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
std::string choose_svg_file()
|
std::string choose_svg_file()
|
||||||
{
|
{
|
||||||
wxWindow *parent = nullptr;
|
wxWindow *parent = nullptr;
|
||||||
|
@ -98,6 +98,8 @@ private:
|
|||||||
bool process();
|
bool process();
|
||||||
void close();
|
void close();
|
||||||
void draw_window();
|
void draw_window();
|
||||||
|
void draw_depth();
|
||||||
|
void draw_use_surface();
|
||||||
void draw_distance();
|
void draw_distance();
|
||||||
void draw_rotation();
|
void draw_rotation();
|
||||||
void draw_model_type();
|
void draw_model_type();
|
||||||
@ -105,41 +107,20 @@ private:
|
|||||||
// process mouse event
|
// 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);
|
||||||
|
|
||||||
// This configs holds GUI layout size given by translated texts.
|
struct GuiCfg;
|
||||||
// etc. When language changes, GUI is recreated and this class constructed again,
|
std::unique_ptr<const GuiCfg> m_gui_cfg = nullptr;
|
||||||
// so the change takes effect. (info by GLGizmoFdmSupports.hpp)
|
|
||||||
struct GuiCfg
|
|
||||||
{
|
|
||||||
// Detect invalid config values when change monitor DPI
|
|
||||||
double screen_scale;
|
|
||||||
float main_toolbar_height;
|
|
||||||
|
|
||||||
// Zero means it is calculated in init function
|
|
||||||
ImVec2 minimal_window_size = ImVec2(0, 0);
|
|
||||||
|
|
||||||
float input_width = 0.f;
|
|
||||||
float input_offset = 0.f;
|
|
||||||
|
|
||||||
// Only translations needed for calc GUI size
|
|
||||||
struct Translations
|
|
||||||
{
|
|
||||||
std::string font;
|
|
||||||
};
|
|
||||||
Translations translations;
|
|
||||||
};
|
|
||||||
std::optional<const GuiCfg> m_gui_cfg;
|
|
||||||
static GuiCfg create_gui_configuration();
|
|
||||||
|
|
||||||
// actual selected only one volume - with emboss data
|
// actual selected only one volume - with emboss data
|
||||||
ModelVolume *m_volume;
|
ModelVolume *m_volume = nullptr;
|
||||||
|
EmbossShape m_volume_shape; // copy from m_volume for edit
|
||||||
|
|
||||||
// When work with undo redo stack there could be situation that
|
// When work with undo redo stack there could be situation that
|
||||||
// m_volume point to unexisting volume so One need also objectID
|
// m_volume point to unexisting volume so One need also objectID
|
||||||
ObjectID m_volume_id;
|
ObjectID m_volume_id;
|
||||||
|
|
||||||
// cancel for previous update of volume to cancel finalize part
|
// cancel for previous update of volume to cancel finalize part
|
||||||
std::shared_ptr<std::atomic<bool>> m_job_cancel;
|
std::shared_ptr<std::atomic<bool>> m_job_cancel = nullptr;
|
||||||
|
|
||||||
// Rotation gizmo
|
// Rotation gizmo
|
||||||
GLGizmoRotate m_rotate_gizmo;
|
GLGizmoRotate m_rotate_gizmo;
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#include "slic3r/Utils/UndoRedo.hpp"
|
#include "slic3r/Utils/UndoRedo.hpp"
|
||||||
#include "slic3r/Utils/RaycastManager.hpp"
|
#include "slic3r/Utils/RaycastManager.hpp"
|
||||||
|
|
||||||
|
// #define EXECUTE_UPDATE_ON_MAIN_THREAD // debug execution on main thread
|
||||||
|
|
||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
using namespace Slic3r::Emboss;
|
using namespace Slic3r::Emboss;
|
||||||
using namespace Slic3r::GUI;
|
using namespace Slic3r::GUI;
|
||||||
@ -607,6 +609,74 @@ bool start_create_volume_without_position(CreateVolumeParams &input, DataBasePtr
|
|||||||
bool try_no_coor = false;
|
bool try_no_coor = false;
|
||||||
return ::start_create_volume_on_surface_job(input, std::move(data), coor, try_no_coor);
|
return ::start_create_volume_on_surface_job(input, std::move(data), coor, try_no_coor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef EXECUTE_UPDATE_ON_MAIN_THREAD
|
||||||
|
namespace {
|
||||||
|
// Run Job on main thread (blocking) - ONLY DEBUG
|
||||||
|
static inline bool execute_job(std::shared_ptr<Job> j)
|
||||||
|
{
|
||||||
|
struct MyCtl : public Job::Ctl
|
||||||
|
{
|
||||||
|
void update_status(int st, const std::string &msg = "") override{};
|
||||||
|
bool was_canceled() const override { return false; }
|
||||||
|
std::future<void> call_on_main_thread(std::function<void()> fn) override { return std::future<void>{}; }
|
||||||
|
} ctl;
|
||||||
|
j->process(ctl);
|
||||||
|
wxGetApp().plater()->CallAfter([j]() {
|
||||||
|
std::exception_ptr e_ptr = nullptr;
|
||||||
|
j->finalize(false, e_ptr);
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool start_update_volume(DataUpdate &&data, const ModelVolume &volume, const Selection &selection, RaycastManager& raycaster)
|
||||||
|
{
|
||||||
|
assert(data.volume_id == volume.id());
|
||||||
|
|
||||||
|
// check cutting from source mesh
|
||||||
|
bool &use_surface = data.base->shape.projection.use_surface;
|
||||||
|
if (use_surface && volume.is_the_only_one_part())
|
||||||
|
use_surface = false;
|
||||||
|
|
||||||
|
std::unique_ptr<Job> job = nullptr;
|
||||||
|
if (use_surface) {
|
||||||
|
// Model to cut surface from.
|
||||||
|
SurfaceVolumeData::ModelSources sources = create_volume_sources(volume);
|
||||||
|
if (sources.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Transform3d volume_tr = volume.get_matrix();
|
||||||
|
const std::optional<Transform3d> &fix_3mf = volume.emboss_shape->fix_3mf_tr;
|
||||||
|
if (fix_3mf.has_value())
|
||||||
|
volume_tr = volume_tr * fix_3mf->inverse();
|
||||||
|
|
||||||
|
// when it is new applying of use surface than move origin onto surfaca
|
||||||
|
if (!volume.emboss_shape->projection.use_surface) {
|
||||||
|
auto offset = calc_surface_offset(selection, raycaster);
|
||||||
|
if (offset.has_value())
|
||||||
|
volume_tr *= Eigen::Translation<double, 3>(*offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_outside = volume.is_model_part();
|
||||||
|
// check that there is not unexpected volume type
|
||||||
|
assert(is_outside || volume.is_negative_volume() || volume.is_modifier());
|
||||||
|
UpdateSurfaceVolumeData surface_data{std::move(data), {volume_tr, is_outside, std::move(sources)}};
|
||||||
|
job = std::make_unique<UpdateSurfaceVolumeJob>(std::move(surface_data));
|
||||||
|
} else {
|
||||||
|
job = std::make_unique<UpdateJob>(std::move(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef EXECUTE_UPDATE_ON_MAIN_THREAD
|
||||||
|
auto &worker = wxGetApp().plater()->get_ui_job_worker();
|
||||||
|
return queue_job(worker, std::move(job));
|
||||||
|
#else
|
||||||
|
// Run Job on main thread (blocking) - ONLY DEBUG
|
||||||
|
return execute_job(std::move(job));
|
||||||
|
#endif // EXECUTE_UPDATE_ON_MAIN_THREAD
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Slic3r::GUI::Emboss
|
} // namespace Slic3r::GUI::Emboss
|
||||||
|
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
|
@ -25,6 +25,7 @@ class RaycastManager;
|
|||||||
class Plater;
|
class Plater;
|
||||||
class GLCanvas3D;
|
class GLCanvas3D;
|
||||||
class Worker;
|
class Worker;
|
||||||
|
class Selection;
|
||||||
}}
|
}}
|
||||||
|
|
||||||
namespace Slic3r::GUI::Emboss {
|
namespace Slic3r::GUI::Emboss {
|
||||||
@ -217,6 +218,17 @@ bool start_create_volume(CreateVolumeParams &input, DataBasePtr data, const Vec2
|
|||||||
/// Need to suggest position or put near the selection
|
/// Need to suggest position or put near the selection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool start_create_volume_without_position(CreateVolumeParams &input, DataBasePtr data);
|
bool start_create_volume_without_position(CreateVolumeParams &input, DataBasePtr data);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Start job for update embossed volume
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">define update data</param>
|
||||||
|
/// <param name="volume">Volume to be updated</param>
|
||||||
|
/// <param name="selection">Keep model and gl_volumes - when start use surface volume must be selected</param>
|
||||||
|
/// <param name="raycaster">Could cast ray to scene</param>
|
||||||
|
/// <returns>True when start job otherwise false</returns>
|
||||||
|
bool start_update_volume(DataUpdate &&data, const ModelVolume &volume, const Selection &selection, RaycastManager &raycaster);
|
||||||
|
|
||||||
} // namespace Slic3r::GUI
|
} // namespace Slic3r::GUI
|
||||||
|
|
||||||
#endif // slic3r_EmbossJob_hpp_
|
#endif // slic3r_EmbossJob_hpp_
|
||||||
|
@ -310,7 +310,7 @@ std::optional<Vec3d> calc_surface_offset(const Selection &selection, RaycastMana
|
|||||||
auto cond = RaycastManager::SkipVolume(volume->id().id);
|
auto cond = RaycastManager::SkipVolume(volume->id().id);
|
||||||
raycast_manager.actualize(*instance, &cond);
|
raycast_manager.actualize(*instance, &cond);
|
||||||
|
|
||||||
Transform3d to_world = world_matrix_fixed(gl_volume, selection.get_model()->objects);
|
Transform3d to_world = world_matrix_fixed(gl_volume, objects);
|
||||||
Vec3d point = to_world * Vec3d::Zero();
|
Vec3d point = to_world * Vec3d::Zero();
|
||||||
Vec3d direction = to_world.linear() * (-Vec3d::UnitZ());
|
Vec3d direction = to_world.linear() * (-Vec3d::UnitZ());
|
||||||
|
|
||||||
@ -491,8 +491,12 @@ void do_local_z_rotate(GLCanvas3D &canvas, double relative_angle)
|
|||||||
assert(!selection.is_empty());
|
assert(!selection.is_empty());
|
||||||
if(selection.is_empty()) return;
|
if(selection.is_empty()) return;
|
||||||
|
|
||||||
|
assert(selection.is_single_full_object() || selection.is_single_volume());
|
||||||
|
if (!selection.is_single_full_object() && !selection.is_single_volume()) return;
|
||||||
|
|
||||||
selection.setup_cache();
|
selection.setup_cache();
|
||||||
TransformationType transformation_type = TransformationType::Local_Relative_Joint;
|
TransformationType transformation_type = selection.is_single_volume() ?
|
||||||
|
TransformationType::Local_Relative_Joint : TransformationType::Instance_Relative_Joint;
|
||||||
selection.rotate(Vec3d(0., 0., relative_angle), transformation_type);
|
selection.rotate(Vec3d(0., 0., relative_angle), transformation_type);
|
||||||
|
|
||||||
std::string snapshot_name; // empty meand no store undo / redo
|
std::string snapshot_name; // empty meand no store undo / redo
|
||||||
|
Loading…
x
Reference in New Issue
Block a user