Core refactor -> preparation to face the came

This commit is contained in:
Filip Sykala - NTB T15p 2023-10-24 12:34:29 +02:00
parent 7324d032a1
commit 00c1c9a4c1
5 changed files with 196 additions and 105 deletions

View File

@ -544,12 +544,9 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
if (m_volume == nullptr)
return false;
std::optional<double> wanted_up_limit;
if (m_keep_up)
wanted_up_limit = up_limit;
const Camera &camera = wxGetApp().plater()->get_camera();
bool was_dragging = m_surface_drag.has_value();
bool res = on_mouse_surface_drag(mouse_event, camera, m_surface_drag, m_parent, m_raycast_manager, up_limit);
bool res = on_mouse_surface_drag(mouse_event, camera, m_surface_drag, m_parent, m_raycast_manager, UP_LIMIT);
bool is_dragging = m_surface_drag.has_value();
// End with surface dragging?
@ -570,12 +567,13 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
// Recalculate angle for GUI
if (!m_keep_up) {
const GLVolume *gl_volume = get_selected_gl_volume(m_parent.get_selection());
const Selection &selection = m_parent.get_selection();
const GLVolume *gl_volume = get_selected_gl_volume(selection);
assert(gl_volume != nullptr);
assert(m_style_manager.is_active_font());
if (gl_volume == nullptr || !m_style_manager.is_active_font())
return res;
m_style_manager.get_style().angle = calc_up(gl_volume->world_matrix(), Slic3r::GUI::up_limit);
m_style_manager.get_style().angle = calc_angle(selection);
}
volume_transformation_changing();
@ -994,11 +992,12 @@ void GLGizmoEmboss::on_stop_dragging()
m_parent.do_rotate(L("Text-Rotate"));
// Re-Calculate current angle of up vector
const GLVolume *gl_volume = get_selected_gl_volume(m_parent.get_selection());
const Selection &selection = m_parent.get_selection();
const GLVolume *gl_volume = get_selected_gl_volume(selection);
assert(m_style_manager.is_active_font());
assert(gl_volume != nullptr);
if (m_style_manager.is_active_font() && gl_volume != nullptr)
m_style_manager.get_style().angle = calc_up(gl_volume->world_matrix(), Slic3r::GUI::up_limit);
m_style_manager.get_style().angle = calc_angle(selection);
m_rotate_start_angle.reset();
@ -1235,7 +1234,7 @@ void GLGizmoEmboss::set_volume_by_selection()
StyleManager::Style style_{style}; // copy
style_.projection = volume->emboss_shape->projection;
style_.angle = calc_up(gl_volume->world_matrix(), Slic3r::GUI::up_limit);
style_.angle = calc_angle(selection);
style_.distance = calc_distance(*gl_volume, m_raycast_manager, m_parent);
if (auto it = std::find_if(styles.begin(), styles.end(), has_same_name);
@ -1283,7 +1282,7 @@ void GLGizmoEmboss::set_volume_by_selection()
// Calculate current angle of up vector
assert(m_style_manager.is_active_font());
if (m_style_manager.is_active_font())
m_style_manager.get_style().angle = calc_up(gl_volume->world_matrix(), up_limit);
m_style_manager.get_style().angle = calc_angle(selection);
// calculate scale for height and depth inside of scaled object instance
calculate_scale();
@ -2890,11 +2889,12 @@ void GLGizmoEmboss::draw_advanced()
do_local_z_rotate(m_parent, diff_angle);
// calc angle after rotation
const GLVolume *gl_volume = get_selected_gl_volume(m_parent.get_selection());
const Selection &selection = m_parent.get_selection();
const GLVolume *gl_volume = get_selected_gl_volume(selection);
assert(gl_volume != nullptr);
assert(m_style_manager.is_active_font());
if (m_style_manager.is_active_font() && gl_volume != nullptr)
m_style_manager.get_style().angle = calc_up(gl_volume->world_matrix(), Slic3r::GUI::up_limit);
m_style_manager.get_style().angle = calc_angle(selection);
if (font_prop.per_glyph)
reinit_text_lines(m_text_lines.get_lines().size());
@ -2955,12 +2955,26 @@ void GLGizmoEmboss::draw_advanced()
if (ImGui::Button(_u8L("Set text to face camera").c_str())) {
assert(get_selected_volume(m_parent.get_selection()) == m_volume);
const Camera &cam = wxGetApp().plater()->get_camera();
FontProp& fp = m_style_manager.get_font_prop();
if (face_selected_volume_to_camera(cam, m_parent) &&
(use_surface || fp.per_glyph)) {
auto wanted_up_limit = (m_keep_up) ? std::optional<double>(UP_LIMIT) : std::optional<double>{};
if (face_selected_volume_to_camera(cam, m_parent, wanted_up_limit)) {
if (!m_keep_up) {
// update current style
m_style_manager.get_style().angle = calc_angle(m_parent.get_selection());
} else {
// after set face to camera, angle should be the same
assert(is_approx(m_style_manager.get_style().angle, calc_angle(m_parent.get_selection())));
}
FontProp &fp = m_style_manager.get_font_prop();
if (use_surface || fp.per_glyph) {
if (fp.per_glyph)
reinit_text_lines();
process();
} else {
// Check outside bed
m_parent.requires_check_outside_state();
}
}
} else if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("%s", _u8L("Orient the text towards the camera.").c_str());

View File

@ -279,38 +279,13 @@ bool GLGizmoSVG::on_mouse_for_rotation(const wxMouseEvent &mouse_event)
return used;
}
namespace{
std::optional<float> calculate_angle(const Selection& selection)
{
const GLVolume *gl_volume = selection.get_first_volume();
assert(gl_volume != nullptr);
if (gl_volume == nullptr)
return {};
Transform3d to_world = gl_volume->world_matrix();
const ModelVolume* volume = get_model_volume(*gl_volume, selection.get_model()->objects);
assert(volume != nullptr);
assert(volume->emboss_shape.has_value());
if (volume == nullptr ||
!volume->emboss_shape.has_value() ||
!volume->emboss_shape->fix_3mf_tr)
return calc_up(to_world, Slic3r::GUI::up_limit);
// exist fix matrix and must be applied before calculation
to_world = to_world * volume->emboss_shape->fix_3mf_tr->inverse();
return calc_up(to_world, Slic3r::GUI::up_limit);
}
}
bool GLGizmoSVG::on_mouse_for_translate(const wxMouseEvent &mouse_event)
{
// exist selected volume?
if (m_volume == nullptr)
return false;
std::optional<double> up_limit;
if (m_keep_up)
up_limit = Slic3r::GUI::up_limit;
auto up_limit = m_keep_up ? std::optional<double>(UP_LIMIT) : std::optional<double>{};
const Camera &camera = wxGetApp().plater()->get_camera();
bool was_dragging = m_surface_drag.has_value();
@ -346,7 +321,7 @@ bool GLGizmoSVG::on_mouse_for_translate(const wxMouseEvent &mouse_event)
// Recalculate angle for GUI
if (!m_keep_up)
m_angle = calculate_angle(m_parent.get_selection());
m_angle = calc_angle(m_parent.get_selection());
}
return res;
}
@ -1213,7 +1188,7 @@ void GLGizmoSVG::set_volume_by_selection()
m_shape_warnings = create_shape_warnings(es, get_scale_for_tolerance());
// Calculate current angle of up vector
m_angle = calculate_angle(selection);
m_angle = calc_angle(selection);
m_distance = calc_distance(*gl_volume, m_raycast_manager, m_parent);
m_shape_bb = get_extents(m_volume_shape.shapes_with_ids);
@ -1351,9 +1326,22 @@ void GLGizmoSVG::draw_window()
if (ImGui::Button(_u8L("Face the camera").c_str())) {
const Camera &cam = wxGetApp().plater()->get_camera();
if (face_selected_volume_to_camera(cam, m_parent) &&
m_volume->emboss_shape->projection.use_surface)
auto wanted_up_limit = (m_keep_up) ? std::optional<double>(UP_LIMIT) : std::optional<double>{};
if (face_selected_volume_to_camera(cam, m_parent, wanted_up_limit)) {
if (!m_keep_up) {
m_angle = calc_angle(m_parent.get_selection());
} else {
// after set face to camera, angle should be the same
assert(is_approx(m_angle, calc_angle(m_parent.get_selection())));
}
if (m_volume->emboss_shape->projection.use_surface) {
process();
} else {
// Check outside bed
m_parent.requires_check_outside_state();
}
}
}
ImGui::Unindent(m_gui_cfg->icon_width);
@ -1895,7 +1883,7 @@ void GLGizmoSVG::draw_rotation()
do_local_z_rotate(m_parent, diff_angle);
// calc angle after rotation
m_angle = calculate_angle(m_parent.get_selection());
m_angle = calc_angle(m_parent.get_selection());
// recalculate for surface cut
if (m_volume->emboss_shape->projection.use_surface)

View File

@ -1561,7 +1561,7 @@ bool start_create_volume_on_surface_job(CreateVolumeParams &input, DataBasePtr d
return on_bad_state(std::move(data), object);
// Create result volume transformation
Transform3d surface_trmat = create_transformation_onto_surface(hit->position, hit->normal, Slic3r::GUI::up_limit);
Transform3d surface_trmat = create_transformation_onto_surface(hit->position, hit->normal, UP_LIMIT);
apply_transformation(input.angle, input.distance, surface_trmat);
Transform3d transform = instance->get_matrix().inverse() * surface_trmat;
auto gizmo_type = static_cast<GLGizmosManager::EType>(input.gizmo);

View File

@ -56,7 +56,7 @@ bool start_dragging(const Vec2d &mouse_pos,
/// <returns></returns>
bool dragging(const Vec2d &mouse_pos,
const Camera &camera,
std::optional<SurfaceDrag> &surface_drag,
SurfaceDrag &surface_drag, // need to write whether exist hit
GLCanvas3D &canvas,
const RaycastManager &raycast_manager,
const std::optional<double> &up_limit);
@ -80,7 +80,7 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event,
std::optional<SurfaceDrag> &surface_drag,
GLCanvas3D &canvas,
RaycastManager &raycast_manager,
std::optional<double> up_limit)
const std::optional<double>&up_limit)
{
// Fix when leave window during dragging
// Fix when click right button
@ -109,7 +109,7 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event,
return false;
if (mouse_event.Dragging())
return dragging(mouse_position(mouse_event), camera, surface_drag, canvas, raycast_manager, up_limit);
return dragging(mouse_position(mouse_event), camera, *surface_drag, canvas, raycast_manager, up_limit);
return false;
}
@ -228,6 +228,25 @@ std::optional<float> calc_distance(const GLVolume &gl_volume, const RaycastManag
return sign * static_cast<float>(sqrt(distance_sq));
}
std::optional<float> calc_angle(const Selection &selection)
{
const GLVolume *gl_volume = selection.get_first_volume();
assert(gl_volume != nullptr);
if (gl_volume == nullptr)
return {};
Transform3d to_world = gl_volume->world_matrix();
const ModelVolume *volume = get_model_volume(*gl_volume, selection.get_model()->objects);
assert(volume != nullptr);
assert(volume->emboss_shape.has_value());
if (volume == nullptr || !volume->emboss_shape.has_value() || !volume->emboss_shape->fix_3mf_tr)
return Emboss::calc_up(to_world, UP_LIMIT);
// exist fix matrix and must be applied before calculation
to_world = to_world * volume->emboss_shape->fix_3mf_tr->inverse();
return Emboss::calc_up(to_world, UP_LIMIT);
}
Transform3d world_matrix_fixed(const GLVolume &gl_volume, const ModelObjectPtrs &objects)
{
Transform3d res = gl_volume.world_matrix();
@ -287,15 +306,40 @@ void selection_transform(Selection &selection, const std::function<void()> &sele
selection.setup_cache();
}
bool face_selected_volume_to_camera(const Camera &camera, GLCanvas3D &canvas)
bool face_selected_volume_to_camera(const Camera &camera, GLCanvas3D &canvas, const std::optional<double>& wanted_up_limit)
{
const Vec3d &cam_dir = camera.get_dir_forward();
Selection &sel = canvas.get_selection();
if (sel.is_empty())
const Selection &selection = canvas.get_selection();
if (selection.is_empty())
return false;
GLVolume *gl_volume_ptr = get_selected_gl_volume(canvas);
if (gl_volume_ptr == nullptr)
return false;
const GLVolume &gl_volume = *gl_volume_ptr;
const ModelObjectPtrs &objects = canvas.get_model()->objects;
const ModelObject *object_ptr = get_model_object(gl_volume, objects);
assert(object_ptr != nullptr);
if (object_ptr == nullptr)
return false;
const ModelObject &object = *object_ptr;
const ModelInstance *instance_ptr = get_model_instance(gl_volume, object);
assert(instance_ptr != nullptr);
if (instance_ptr == nullptr)
return false;
const ModelInstance &instance = *instance_ptr;
const ModelVolume *volume_ptr = get_model_volume(gl_volume, object);
assert(volume_ptr != nullptr);
if (volume_ptr == nullptr)
return false;
const ModelVolume &volume = *volume_ptr;
const Vec3d &cam_dir = camera.get_dir_forward();
// camera direction transformed into volume coordinate system
Transform3d to_world = world_matrix_fixed(sel);
Transform3d to_world = world_matrix_fixed(gl_volume, objects);
Vec3d cam_dir_tr = to_world.inverse().linear() * cam_dir;
cam_dir_tr.normalize();
@ -305,11 +349,12 @@ bool face_selected_volume_to_camera(const Camera &camera, GLCanvas3D &canvas)
if (is_approx(cam_dir_tr, emboss_dir))
return false;
assert(sel.get_volume_idxs().size() == 1);
GLVolume *gl_volume = sel.get_volume(*sel.get_volume_idxs().begin());
assert(selection.get_volume_idxs().size() == 1);
if (selection.get_volume_idxs().size() != 1)
return false;
Transform3d vol_rot;
Transform3d vol_tr = gl_volume->get_volume_transformation().get_matrix();
Transform3d vol_tr = gl_volume.get_volume_transformation().get_matrix();
// check whether cam_dir is opposit to emboss dir
if (is_approx(cam_dir_tr, -emboss_dir)) {
// rotate 180 DEG by y
@ -325,9 +370,24 @@ bool face_selected_volume_to_camera(const Camera &camera, GLCanvas3D &canvas)
Vec3d offset = vol_tr * Vec3d::Zero();
Vec3d offset_inv = vol_rot.inverse() * offset;
Transform3d res = vol_tr * Eigen::Translation<double, 3>(-offset) * vol_rot * Eigen::Translation<double, 3>(offset_inv);
// Transform3d res = vol_tr * vol_rot;
gl_volume->set_volume_transformation(Geometry::Transformation(res));
get_model_volume(*gl_volume, sel.get_model()->objects)->set_transformation(res);
// Need modifiable gl volume
GLVolume *gl_volume_ptr_ = canvas.get_selection().get_volume(*selection.get_volume_idxs().begin());
assert(gl_volume_ptr_ != nullptr);
if (gl_volume_ptr_ == nullptr)
return false;
// Need modifiable model volume
ModelVolume *model_volume_ptr_ = get_model_volume(gl_volume, objects);
assert(model_volume_ptr_ != nullptr);
if (model_volume_ptr_ == nullptr)
return false;
// write result transformation
gl_volume_ptr_->set_volume_transformation(Geometry::Transformation(res));
model_volume_ptr_->set_transformation(res);
return true;
}
@ -501,25 +561,19 @@ bool start_dragging(const Vec2d &mouse_pos,
return true;
}
bool dragging(const Vec2d &mouse_pos,
const Camera &camera,
std::optional<SurfaceDrag> &surface_drag,
GLCanvas3D &canvas,
const RaycastManager &raycast_manager,
const std::optional<double> &up_limit)
Transform3d get_volume_transformation(
Transform3d world, // from volume
const Vec3d& world_dir, // wanted new direction
const Vec3d& world_position, // wanted new position
const std::optional<Transform3d>& fix, // [optional] fix matrix
// Invers transformation of text volume instance
// Help convert world transformation to instance space
const Transform3d& instance_inv,
// initial rotation in Z axis
std::optional<float> current_angle = {},
const std::optional<double> &up_limit = {})
{
Vec2d offseted_mouse = mouse_pos + surface_drag->mouse_offset_without_sla_shift;
std::optional<RaycastManager::Hit> hit = ray_from_camera(
raycast_manager, offseted_mouse, camera, &surface_drag->condition);
surface_drag->exist_hit = hit.has_value();
if (!hit.has_value()) {
// cross hair need redraw
canvas.set_as_dirty();
return true;
}
auto world_linear = surface_drag->world.linear();
auto world_linear = world.linear();
// Calculate offset: transformation to wanted position
{
// Reset skew of the text Z axis:
@ -530,8 +584,8 @@ bool dragging(const Vec2d &mouse_pos,
}
Vec3d text_z_world = world_linear.col(2); // world_linear * Vec3d::UnitZ()
auto z_rotation = Eigen::Quaternion<double, Eigen::DontAlign>::FromTwoVectors(text_z_world, hit->normal);
Transform3d world_new = z_rotation * surface_drag->world;
auto z_rotation = Eigen::Quaternion<double, Eigen::DontAlign>::FromTwoVectors(text_z_world, world_dir);
Transform3d world_new = z_rotation * world;
auto world_new_linear = world_new.linear();
// Fix direction of up vector to zero initial rotation
@ -548,32 +602,59 @@ bool dragging(const Vec2d &mouse_pos,
}
// Edit position from right
Transform3d volume_new{Eigen::Translation<double, 3>(surface_drag->instance_inv * hit->position)};
volume_new.linear() = surface_drag->instance_inv.linear() * world_new_linear;
Transform3d volume_new{Eigen::Translation<double, 3>(instance_inv * world_position)};
volume_new.linear() = instance_inv.linear() * world_new_linear;
// Check that transformation matrix is valid transformation
assert(volume_new.matrix()(0, 0) == volume_new.matrix()(0, 0)); // Check valid transformation not a NAN
if (volume_new.matrix()(0, 0) != volume_new.matrix()(0, 0))
return true;
return Transform3d::Identity();
// Check that scale in world did not changed
assert(!calc_scale(world_linear, world_new_linear, Vec3d::UnitY()).has_value());
assert(!calc_scale(world_linear, world_new_linear, Vec3d::UnitZ()).has_value());
const ModelVolume *volume = get_model_volume(*surface_drag->gl_volume, canvas.get_model()->objects);
// fix baked transformation from .3mf store process
if (volume != nullptr && volume->emboss_shape.has_value()) {
const std::optional<Slic3r::Transform3d> &fix = volume->emboss_shape->fix_3mf_tr;
if (fix.has_value())
volume_new = volume_new * (*fix);
// apply move in Z direction and rotation by up vector
Emboss::apply_transformation(surface_drag->start_angle, surface_drag->start_distance, volume_new);
Emboss::apply_transformation(current_angle, {}, volume_new);
return volume_new;
}
bool dragging(const Vec2d &mouse_pos,
const Camera &camera,
SurfaceDrag &surface_drag,
GLCanvas3D &canvas,
const RaycastManager &raycast_manager,
const std::optional<double> &up_limit)
{
Vec2d offseted_mouse = mouse_pos + surface_drag.mouse_offset_without_sla_shift;
std::optional<RaycastManager::Hit> hit = ray_from_camera(
raycast_manager, offseted_mouse, camera, &surface_drag.condition);
surface_drag.exist_hit = hit.has_value();
if (!hit.has_value()) {
// cross hair need redraw
canvas.set_as_dirty();
return true;
}
const ModelVolume *volume = get_model_volume(*surface_drag.gl_volume, canvas.get_model()->objects);
std::optional<Transform3d> fix;
if (volume !=nullptr &&
volume->emboss_shape.has_value() &&
volume->emboss_shape->fix_3mf_tr.has_value())
fix = volume->emboss_shape->fix_3mf_tr;
Transform3d volume_new = get_volume_transformation(surface_drag.world, hit->normal, hit->position,
fix, surface_drag.instance_inv, surface_drag.start_angle, up_limit);
// Update transformation for all instances
for (GLVolume *vol : canvas.get_volumes().volumes) {
if (vol->object_idx() != surface_drag->gl_volume->object_idx() || vol->volume_idx() != surface_drag->gl_volume->volume_idx())
if (vol->object_idx() != surface_drag.gl_volume->object_idx() ||
vol->volume_idx() != surface_drag.gl_volume->volume_idx())
continue;
vol->set_volume_transformation(volume_new);
}

View File

@ -51,7 +51,7 @@ struct SurfaceDrag
// Limit direction of up vector on model
// Between side and top surface
constexpr double up_limit = 0.9;
constexpr double UP_LIMIT = 0.9;
/// <summary>
/// Mouse event handler, when move(drag&drop) volume over model surface
@ -70,7 +70,7 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event,
std::optional<SurfaceDrag> &surface_drag,
GLCanvas3D &canvas,
RaycastManager &raycast_manager,
std::optional<double> up_limit = {});
const std::optional<double>&up_limit = {});
/// <summary>
/// Calculate translation of volume onto surface of model
@ -90,6 +90,13 @@ std::optional<Vec3d> calc_surface_offset(const Selection &selection, RaycastMana
std::optional<float> calc_distance(const GLVolume &gl_volume, RaycastManager &raycaster, GLCanvas3D &canvas);
std::optional<float> calc_distance(const GLVolume &gl_volume, const RaycastManager &raycaster, const RaycastManager::ISkip *condition);
/// <summary>
/// Calculate up vector angle
/// </summary>
/// <param name="selection">Calculation of angle is for selected one volume</param>
/// <returns></returns>
std::optional<float> calc_angle(const Selection &selection);
/// <summary>
/// Get transformation to world
/// - use fix after store to 3mf when exists
@ -123,8 +130,9 @@ void selection_transform(Selection &selection, const std::function<void()>& sele
/// </summary>
/// <param name="camera">Define view vector</param>
/// <param name="canvas">Containe Selected ModelVolume to modify orientation</param>
/// <param name="wanted_up_limit">[Optional]Limit for direction of up vector</param>
/// <returns>True when apply change otherwise false</returns>
bool face_selected_volume_to_camera(const Camera &camera, GLCanvas3D &canvas);
bool face_selected_volume_to_camera(const Camera &camera, GLCanvas3D &canvas, const std::optional<double> &wanted_up_limit = {});
/// <summary>
/// Rotation around z Axis(emboss direction)