mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 12:05:54 +08:00
Offseted move with text volume over surface
+ use fix of .3mf transformation
This commit is contained in:
parent
630b1bb956
commit
7c1cf6fa7e
@ -27,7 +27,7 @@ Points CameraUtils::project(const Camera & camera,
|
|||||||
result.reserve(points.size());
|
result.reserve(points.size());
|
||||||
int window_height = viewport[3];
|
int window_height = viewport[3];
|
||||||
|
|
||||||
// Iterate over all points and determine whether they're in the rectangle.
|
// convert to points --> loss precision
|
||||||
for (int i = 0; i < projections.rows(); ++i) {
|
for (int i = 0; i < projections.rows(); ++i) {
|
||||||
double x = projections(i, 0);
|
double x = projections(i, 0);
|
||||||
double y = projections(i, 1);
|
double y = projections(i, 1);
|
||||||
@ -37,6 +37,12 @@ Points CameraUtils::project(const Camera & camera,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Point CameraUtils::project(const Camera &camera, const Vec3d &point)
|
||||||
|
{
|
||||||
|
// IMPROVE: do it faster when you need it (inspire in project multi point)
|
||||||
|
return project(camera, std::vector{point}).front();
|
||||||
|
}
|
||||||
|
|
||||||
Slic3r::Polygon CameraUtils::create_hull2d(const Camera & camera,
|
Slic3r::Polygon CameraUtils::create_hull2d(const Camera & camera,
|
||||||
const GLVolume &volume)
|
const GLVolume &volume)
|
||||||
{
|
{
|
||||||
|
@ -25,6 +25,7 @@ public:
|
|||||||
/// <returns>projected points by camera into coordinate of camera.
|
/// <returns>projected points by camera into coordinate of camera.
|
||||||
/// x(from left to right), y(from top to bottom)</returns>
|
/// x(from left to right), y(from top to bottom)</returns>
|
||||||
static Points project(const Camera& camera, const std::vector<Vec3d> &points);
|
static Points project(const Camera& camera, const std::vector<Vec3d> &points);
|
||||||
|
static Point project(const Camera& camera, const Vec3d &point);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create hull around GLVolume in 2d space of camera
|
/// Create hull around GLVolume in 2d space of camera
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
#define SHOW_FONT_FILE_PROPERTY // ascent, descent, line gap, cache --> in advanced <tree header>
|
#define SHOW_FONT_FILE_PROPERTY // ascent, descent, line gap, cache --> in advanced <tree header>
|
||||||
#define SHOW_FONT_COUNT // count of enumerated font --> in font combo box
|
#define SHOW_FONT_COUNT // count of enumerated font --> in font combo box
|
||||||
#define SHOW_CONTAIN_3MF_FIX // when contain fix matrix --> show gray '3mf' next to close button
|
#define SHOW_CONTAIN_3MF_FIX // when contain fix matrix --> show gray '3mf' next to close button
|
||||||
|
#define SHOW_OFFSET_DURING_DRAGGING // when drag with text over surface visualize used center
|
||||||
#define SHOW_IMGUI_ATLAS
|
#define SHOW_IMGUI_ATLAS
|
||||||
#define SHOW_ICONS_TEXTURE
|
#define SHOW_ICONS_TEXTURE
|
||||||
#define SHOW_FINE_POSITION
|
#define SHOW_FINE_POSITION
|
||||||
@ -106,32 +107,6 @@ void GLGizmoEmboss::set_fine_position()
|
|||||||
ImGuiWrapper::draw(rect);
|
ImGuiWrapper::draw(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SHOW_FINE_POSITION
|
|
||||||
static void draw_fine_position(const Selection &selection)
|
|
||||||
{
|
|
||||||
const Selection::IndicesList indices = selection.get_volume_idxs();
|
|
||||||
// no selected volume
|
|
||||||
if (indices.empty()) return;
|
|
||||||
const GLVolume *volume = selection.get_volume(*indices.begin());
|
|
||||||
// bad volume selected (e.g. deleted one)
|
|
||||||
if (volume == nullptr) return;
|
|
||||||
|
|
||||||
const Camera &camera = wxGetApp().plater()->get_camera();
|
|
||||||
Slic3r::Polygon hull = CameraUtils::create_hull2d(camera, *volume);
|
|
||||||
|
|
||||||
ImVec2 windows_size(174, 202);
|
|
||||||
Size c_size = m_parent.get_canvas_size();
|
|
||||||
ImVec2 canvas_size(c_size.get_width(), c_size.get_height());
|
|
||||||
ImVec2 offset = ImGuiWrapper::suggest_location(windows_size, hull,canvas_size);
|
|
||||||
Slic3r::Polygon rect(
|
|
||||||
{Point(offset.x, offset.y), Point(offset.x + windows_size.x, offset.y),
|
|
||||||
Point(offset.x + windows_size.x, offset.y + windows_size.y),
|
|
||||||
Point(offset.x, offset.y + windows_size.y)});
|
|
||||||
ImGuiWrapper::draw(hull);
|
|
||||||
ImGuiWrapper::draw(rect);
|
|
||||||
}
|
|
||||||
#endif // SHOW_FINE_POSITION
|
|
||||||
|
|
||||||
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 ||
|
assert(volume_type == ModelVolumeType::MODEL_PART ||
|
||||||
@ -168,20 +143,6 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mous
|
|||||||
queue_job(worker, std::make_unique<EmbossCreateObjectJob>(std::move(data)));
|
queue_job(worker, std::make_unique<EmbossCreateObjectJob>(std::move(data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DRAW_PLACE_TO_ADD_TEXT
|
|
||||||
static void draw_place_to_add_text() {
|
|
||||||
ImVec2 mp = ImGui::GetMousePos();
|
|
||||||
Vec2d mouse_pos(mp.x, mp.y);
|
|
||||||
const Camera &camera = wxGetApp().plater()->get_camera();
|
|
||||||
Vec3d p1 = CameraUtils::get_z0_position(camera, mouse_pos);
|
|
||||||
std::vector<Vec3d> rect3d{p1 + Vec3d(5, 5, 0), p1 + Vec3d(-5, 5, 0),
|
|
||||||
p1 + Vec3d(-5, -5, 0), p1 + Vec3d(5, -5, 0)};
|
|
||||||
Points rect2d = CameraUtils::project(camera, rect3d);
|
|
||||||
ImGuiWrapper::draw(Slic3r::Polygon(rect2d));
|
|
||||||
}
|
|
||||||
#endif // DRAW_PLACE_TO_ADD_TEXT
|
|
||||||
|
|
||||||
|
|
||||||
bool GLGizmoEmboss::on_mouse_for_rotation(const wxMouseEvent &mouse_event)
|
bool GLGizmoEmboss::on_mouse_for_rotation(const wxMouseEvent &mouse_event)
|
||||||
{
|
{
|
||||||
if (mouse_event.Moving()) return false;
|
if (mouse_event.Moving()) return false;
|
||||||
@ -226,6 +187,43 @@ bool GLGizmoEmboss::on_mouse_for_rotation(const wxMouseEvent &mouse_event)
|
|||||||
return used;
|
return used;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Vec2d calc_mouse_to_center_text_offset(const Vec2d& mouse, const ModelVolume& mv) {
|
||||||
|
const Transform3d &volume_tr = mv.get_matrix();
|
||||||
|
const Camera &camera = wxGetApp().plater()->get_camera();
|
||||||
|
assert(mv.text_configuration.has_value());
|
||||||
|
|
||||||
|
auto calc_offset = [&mouse, &volume_tr, &camera, &mv]
|
||||||
|
(const Transform3d &instrance_tr) -> Vec2d {
|
||||||
|
Transform3d to_world = instrance_tr * volume_tr;
|
||||||
|
|
||||||
|
// Use fix of .3mf loaded tranformation when exist
|
||||||
|
if (mv.text_configuration->fix_3mf_tr.has_value())
|
||||||
|
to_world = to_world * (*mv.text_configuration->fix_3mf_tr);
|
||||||
|
// zero point of volume in world coordinate system
|
||||||
|
Vec3d volume_center = to_world.translation();
|
||||||
|
// screen coordinate of volume center
|
||||||
|
Vec2i coor = CameraUtils::project(camera, volume_center);
|
||||||
|
return coor.cast<double>() - mouse;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto object = mv.get_object();
|
||||||
|
assert(!object->instances.empty());
|
||||||
|
// Speed up for one instance
|
||||||
|
if (object->instances.size() == 1)
|
||||||
|
return calc_offset(object->instances.front()->get_matrix());
|
||||||
|
|
||||||
|
Vec2d nearest_offset;
|
||||||
|
double nearest_offset_size = std::numeric_limits<double>::max();
|
||||||
|
for (const ModelInstance *instance : object->instances) {
|
||||||
|
Vec2d offset = calc_offset(instance->get_matrix());
|
||||||
|
double offset_size = offset.norm();
|
||||||
|
if (nearest_offset_size < offset_size) continue;
|
||||||
|
nearest_offset_size = offset_size;
|
||||||
|
nearest_offset = offset;
|
||||||
|
}
|
||||||
|
return nearest_offset;
|
||||||
|
}
|
||||||
|
|
||||||
bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
|
bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
|
||||||
{
|
{
|
||||||
// filter events
|
// filter events
|
||||||
@ -257,6 +255,10 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
|
|||||||
allowed_volumes_id.emplace_back(v->id().id);
|
allowed_volumes_id.emplace_back(v->id().id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wxCoord == int --> wx/types.h
|
||||||
|
Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY());
|
||||||
|
Vec2d mouse_pos = mouse_coord.cast<double>();
|
||||||
RaycastManager::AllowVolumes condition(std::move(allowed_volumes_id));
|
RaycastManager::AllowVolumes condition(std::move(allowed_volumes_id));
|
||||||
|
|
||||||
// detect start text dragging
|
// detect start text dragging
|
||||||
@ -265,14 +267,14 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
|
|||||||
// IMPROVE: move to job, for big scene it slows down
|
// IMPROVE: move to job, for big scene it slows down
|
||||||
ModelObject *act_model_object = act_model_volume->get_object();
|
ModelObject *act_model_object = act_model_volume->get_object();
|
||||||
m_raycast_manager.actualize(act_model_object, &condition);
|
m_raycast_manager.actualize(act_model_object, &condition);
|
||||||
|
m_dragging_mouse_offset = calc_mouse_to_center_text_offset(mouse_pos, *m_volume);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// wxCoord == int --> wx/types.h
|
|
||||||
Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY());
|
|
||||||
Vec2d mouse_pos = mouse_coord.cast<double>();
|
|
||||||
const Camera &camera = wxGetApp().plater()->get_camera();
|
const Camera &camera = wxGetApp().plater()->get_camera();
|
||||||
auto hit = m_raycast_manager.unproject(mouse_pos, camera, &condition);
|
assert(m_dragging_mouse_offset.has_value());
|
||||||
|
Vec2d offseted_mouse = mouse_pos + *m_dragging_mouse_offset;
|
||||||
|
auto hit = m_raycast_manager.unproject(offseted_mouse, camera, &condition);
|
||||||
if (!hit.has_value()) {
|
if (!hit.has_value()) {
|
||||||
// there is no hit
|
// there is no hit
|
||||||
// show common translation of object
|
// show common translation of object
|
||||||
@ -310,7 +312,8 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
|
|||||||
|
|
||||||
m_parent.toggle_model_objects_visibility(true);
|
m_parent.toggle_model_objects_visibility(true);
|
||||||
// Apply temporary position
|
// Apply temporary position
|
||||||
m_temp_transformation = {};
|
m_temp_transformation = {};
|
||||||
|
m_dragging_mouse_offset = {};
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -414,6 +417,61 @@ void GLGizmoEmboss::on_render_for_picking() {
|
|||||||
m_rotate_gizmo.render_for_picking();
|
m_rotate_gizmo.render_for_picking();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SHOW_FINE_POSITION
|
||||||
|
// draw suggested position of window
|
||||||
|
static void draw_fine_position(const Selection &selection,
|
||||||
|
const Size &canvas,
|
||||||
|
const ImVec2 &windows_size)
|
||||||
|
{
|
||||||
|
const Selection::IndicesList indices = selection.get_volume_idxs();
|
||||||
|
// no selected volume
|
||||||
|
if (indices.empty()) return;
|
||||||
|
const GLVolume *volume = selection.get_volume(*indices.begin());
|
||||||
|
// bad volume selected (e.g. deleted one)
|
||||||
|
if (volume == nullptr) return;
|
||||||
|
|
||||||
|
const Camera &camera = wxGetApp().plater()->get_camera();
|
||||||
|
Slic3r::Polygon hull = CameraUtils::create_hull2d(camera, *volume);
|
||||||
|
ImVec2 canvas_size(canvas.get_width(), canvas.get_height());
|
||||||
|
ImVec2 offset = ImGuiWrapper::suggest_location(windows_size, hull,
|
||||||
|
canvas_size);
|
||||||
|
Slic3r::Polygon rect(
|
||||||
|
{Point(offset.x, offset.y), Point(offset.x + windows_size.x, offset.y),
|
||||||
|
Point(offset.x + windows_size.x, offset.y + windows_size.y),
|
||||||
|
Point(offset.x, offset.y + windows_size.y)});
|
||||||
|
ImGuiWrapper::draw(hull);
|
||||||
|
ImGuiWrapper::draw(rect);
|
||||||
|
}
|
||||||
|
#endif // SHOW_FINE_POSITION
|
||||||
|
|
||||||
|
#ifdef DRAW_PLACE_TO_ADD_TEXT
|
||||||
|
static void draw_place_to_add_text()
|
||||||
|
{
|
||||||
|
ImVec2 mp = ImGui::GetMousePos();
|
||||||
|
Vec2d mouse_pos(mp.x, mp.y);
|
||||||
|
const Camera &camera = wxGetApp().plater()->get_camera();
|
||||||
|
Vec3d p1 = CameraUtils::get_z0_position(camera, mouse_pos);
|
||||||
|
std::vector<Vec3d> rect3d{p1 + Vec3d(5, 5, 0), p1 + Vec3d(-5, 5, 0),
|
||||||
|
p1 + Vec3d(-5, -5, 0), p1 + Vec3d(5, -5, 0)};
|
||||||
|
Points rect2d = CameraUtils::project(camera, rect3d);
|
||||||
|
ImGuiWrapper::draw(Slic3r::Polygon(rect2d));
|
||||||
|
}
|
||||||
|
#endif // DRAW_PLACE_TO_ADD_TEXT
|
||||||
|
|
||||||
|
#ifdef SHOW_OFFSET_DURING_DRAGGING
|
||||||
|
static void draw_mouse_offset(const std::optional<Vec2d> &offset)
|
||||||
|
{
|
||||||
|
if (!offset.has_value()) return;
|
||||||
|
// debug draw
|
||||||
|
auto draw_list = ImGui::GetOverlayDrawList();
|
||||||
|
ImVec2 p1 = ImGui::GetMousePos();
|
||||||
|
ImVec2 p2(p1.x + offset->x(), p1.y + offset->y());
|
||||||
|
ImU32 color = ImGui::GetColorU32(ImGuiWrapper::COL_ORANGE_LIGHT);
|
||||||
|
float thickness = 3.f;
|
||||||
|
draw_list->AddLine(p1, p2, color, thickness);
|
||||||
|
}
|
||||||
|
#endif // SHOW_OFFSET_DURING_DRAGGING
|
||||||
|
|
||||||
void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit)
|
void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit)
|
||||||
{
|
{
|
||||||
initialize();
|
initialize();
|
||||||
@ -424,13 +482,14 @@ void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit)
|
|||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, min_window_size);
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, min_window_size);
|
||||||
|
|
||||||
#ifdef SHOW_FINE_POSITION
|
#ifdef SHOW_FINE_POSITION
|
||||||
// draw suggested position of window
|
draw_fine_position(m_parent.get_selection(), m_parent.get_canvas_size(), min_window_size);
|
||||||
draw_fine_position(m_parent.get_selection());
|
|
||||||
#endif // SHOW_FINE_POSITION
|
#endif // SHOW_FINE_POSITION
|
||||||
#ifdef DRAW_PLACE_TO_ADD_TEXT
|
#ifdef DRAW_PLACE_TO_ADD_TEXT
|
||||||
draw_place_to_add_text();
|
draw_place_to_add_text();
|
||||||
#endif // DRAW_PLACE_TO_ADD_TEXT
|
#endif // DRAW_PLACE_TO_ADD_TEXT
|
||||||
|
#ifdef SHOW_OFFSET_DURING_DRAGGING
|
||||||
|
draw_mouse_offset(m_dragging_mouse_offset);
|
||||||
|
#endif // SHOW_OFFSET_DURING_DRAGGING
|
||||||
|
|
||||||
// check if is set window offset
|
// check if is set window offset
|
||||||
if (m_set_window_offset.has_value()) {
|
if (m_set_window_offset.has_value()) {
|
||||||
|
@ -232,6 +232,9 @@ private:
|
|||||||
// Rotation gizmo
|
// Rotation gizmo
|
||||||
GLGizmoRotate m_rotate_gizmo;
|
GLGizmoRotate m_rotate_gizmo;
|
||||||
|
|
||||||
|
// when draging with text object hold screen offset of cursor from object center
|
||||||
|
std::optional<Vec2d> m_dragging_mouse_offset;
|
||||||
|
|
||||||
// TODO: it should be accessible by other gizmo too.
|
// TODO: it should be accessible by other gizmo too.
|
||||||
// May be move to plater?
|
// May be move to plater?
|
||||||
RaycastManager m_raycast_manager;
|
RaycastManager m_raycast_manager;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user