mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-18 05:55:54 +08:00
Separate raycaster manager
Dragging text object over model surface - only temporary preview
This commit is contained in:
parent
1259b878fb
commit
e55e418c61
@ -247,6 +247,8 @@ set(SLIC3R_GUI_SOURCES
|
|||||||
Utils/Process.cpp
|
Utils/Process.cpp
|
||||||
Utils/Process.hpp
|
Utils/Process.hpp
|
||||||
Utils/Profile.hpp
|
Utils/Profile.hpp
|
||||||
|
Utils/RaycastManager.cpp
|
||||||
|
Utils/RaycastManager.hpp
|
||||||
Utils/UndoRedo.cpp
|
Utils/UndoRedo.cpp
|
||||||
Utils/UndoRedo.hpp
|
Utils/UndoRedo.hpp
|
||||||
Utils/HexFile.cpp
|
Utils/HexFile.cpp
|
||||||
|
@ -36,6 +36,8 @@
|
|||||||
// uncomment for easier debug
|
// uncomment for easier debug
|
||||||
//#define ALLOW_DEBUG_MODE
|
//#define ALLOW_DEBUG_MODE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
using namespace Slic3r::GUI;
|
using namespace Slic3r::GUI;
|
||||||
|
|
||||||
@ -168,61 +170,58 @@ bool GLGizmoEmboss::on_mouse_for_rotation(const wxMouseEvent &mouse_event)
|
|||||||
bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
|
bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
|
||||||
{
|
{
|
||||||
// filter events
|
// filter events
|
||||||
if (!mouse_event.Dragging() && !mouse_event.LeftUp()) return false;
|
if (!mouse_event.Dragging() &&
|
||||||
|
!mouse_event.LeftUp() &&
|
||||||
|
!mouse_event.LeftDown())
|
||||||
|
return false;
|
||||||
|
|
||||||
Selection& selection = m_parent.get_selection();
|
// text volume must be selected
|
||||||
if (!selection.is_single_volume()) return false;
|
if (m_volume == nullptr) return false;
|
||||||
|
|
||||||
bool drag_text = selection.is_dragging();
|
// must exist hover object
|
||||||
if (!drag_text) return false;
|
int hovered_id = m_parent.get_first_hover_volume_idx();
|
||||||
|
if (hovered_id < 0) return false;
|
||||||
|
|
||||||
|
GLVolume *gl_volume = m_parent.get_volumes().volumes[hovered_id];
|
||||||
|
const ModelObjectPtrs &objects = wxGetApp().plater()->model().objects;
|
||||||
|
ModelVolume *act_model_volume = get_model_volume(gl_volume, objects);
|
||||||
|
|
||||||
|
// hovered object must be actual text volume
|
||||||
|
if (m_volume != act_model_volume) return false;
|
||||||
|
|
||||||
|
RaycastManager::SkipVolume skip(m_volume->id().id);
|
||||||
|
// detect start text dragging
|
||||||
|
if (mouse_event.LeftDown()) {
|
||||||
|
// initialize raycasters
|
||||||
|
// TODO: move to job, for big scene it slow down
|
||||||
|
m_raycast_manager.actualize(objects, &skip);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// wxCoord == int --> wx/types.h
|
// wxCoord == int --> wx/types.h
|
||||||
Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY());
|
Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY());
|
||||||
Vec2d mouse_pos = mouse_coord.cast<double>();
|
Vec2d mouse_pos = mouse_coord.cast<double>();
|
||||||
|
auto hit = m_raycast_manager.unproject(mouse_pos, &skip);
|
||||||
|
if (!hit.has_value()) {
|
||||||
//auto trmat2 = transform_on_surface(mouse_pos);
|
// there is no hit
|
||||||
//if (!trmat2.has_value()) return false;
|
m_parent.toggle_model_objects_visibility(true);
|
||||||
|
m_temp_transformation = {};
|
||||||
int hovered_id = m_parent.get_first_hover_volume_idx();
|
|
||||||
if (hovered_id < 0) return false;
|
|
||||||
|
|
||||||
GLVolume *gl_volume = m_parent.get_volumes().volumes[hovered_id];
|
|
||||||
auto & objects = wxGetApp().plater()->model().objects;
|
|
||||||
ModelVolume *act_model_volume = get_model_volume(gl_volume, objects);
|
|
||||||
|
|
||||||
static ModelVolume *model_volume = nullptr;
|
|
||||||
static std::unique_ptr<MeshRaycaster> mrc;
|
|
||||||
if (act_model_volume == nullptr) {
|
|
||||||
mrc = nullptr;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model_volume != act_model_volume) {
|
|
||||||
// hovered different object create different raycaster
|
|
||||||
model_volume = act_model_volume;
|
|
||||||
mrc = std::make_unique<MeshRaycaster>(model_volume->mesh());
|
|
||||||
}
|
|
||||||
|
|
||||||
Transform3d trafo = gl_volume->world_matrix();
|
|
||||||
const Camera &camera = wxGetApp().plater()->get_camera();
|
|
||||||
|
|
||||||
Vec3f position = Vec3f::Zero();
|
|
||||||
Vec3f normal = Vec3f::UnitZ();
|
|
||||||
if (!mrc->unproject_on_mesh(mouse_pos, trafo, camera, position, normal))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Transform3d trmat = get_emboss_transformation(position, normal);
|
|
||||||
// TODO: store z-rotation and aply after transformation matrix
|
|
||||||
|
|
||||||
if (mouse_event.Dragging()) {
|
if (mouse_event.Dragging()) {
|
||||||
// create temporary position
|
// Show temporary position
|
||||||
//selection.translate(Vec3d(), ECoordinatesType::Local);
|
m_parent.toggle_model_objects_visibility(false, m_volume->get_object(), gl_volume->instance_idx(), m_volume);
|
||||||
//selection.get_insvolume(0);
|
|
||||||
return true;
|
// TODO: store z-rotation and aply after transformation matrix
|
||||||
|
Transform3d object_trmat = m_raycast_manager.get_transformation(hit->tr_key);
|
||||||
|
RaycastManager::SurfacePoint sp = *hit;
|
||||||
|
Transform3d trmat = get_emboss_transformation(sp.position, sp.normal);
|
||||||
|
m_temp_transformation = object_trmat * trmat;
|
||||||
} else if (mouse_event.LeftUp()) {
|
} else if (mouse_event.LeftUp()) {
|
||||||
|
// Apply temporary position
|
||||||
|
m_parent.toggle_model_objects_visibility(true);
|
||||||
|
m_temp_transformation = {};
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -258,20 +257,24 @@ void GLGizmoEmboss::on_render() {
|
|||||||
|
|
||||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||||
|
|
||||||
m_rotate_gizmo.render();
|
if (m_temp_transformation.has_value()) {
|
||||||
|
// draw text volume on temporary position
|
||||||
|
const Selection &selection = m_parent.get_selection();
|
||||||
|
const GLVolume& gl_volume = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||||
|
glsafe(::glPushMatrix());
|
||||||
|
glsafe(::glMultMatrixd(m_temp_transformation->data()));
|
||||||
|
GLShaderProgram *shader = wxGetApp().get_shader("gouraud_light");
|
||||||
|
shader->start_using();
|
||||||
|
// dragging object must be selected so draw it with selected color
|
||||||
|
shader->set_uniform("uniform_color", GLVolume::SELECTED_COLOR);
|
||||||
|
gl_volume.indexed_vertex_array.render();
|
||||||
|
shader->stop_using();
|
||||||
|
glsafe(::glPopMatrix());
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_preview.is_initialized()) return;
|
// Do NOT render rotation when dragging
|
||||||
|
if (!m_parent.is_dragging() || m_dragging)
|
||||||
glsafe(::glPushMatrix());
|
m_rotate_gizmo.render();
|
||||||
glsafe(::glMultMatrixd(m_preview_trmat.data()));
|
|
||||||
auto *contour_shader = wxGetApp().get_shader("mm_contour");
|
|
||||||
contour_shader->start_using();
|
|
||||||
glsafe(::glLineWidth(1.0f));
|
|
||||||
glsafe(::glPolygonMode(GL_FRONT_AND_BACK, GL_LINE));
|
|
||||||
m_preview.render();
|
|
||||||
glsafe(::glPolygonMode(GL_FRONT_AND_BACK, GL_FILL));
|
|
||||||
contour_shader->stop_using();
|
|
||||||
glsafe(::glPopMatrix());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoEmboss::on_render_for_picking() {
|
void GLGizmoEmboss::on_render_for_picking() {
|
||||||
@ -510,7 +513,7 @@ ModelVolume *GLGizmoEmboss::get_selected_volume()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ModelVolume *GLGizmoEmboss::get_model_volume(const GLVolume * gl_volume,
|
ModelVolume *GLGizmoEmboss::get_model_volume(const GLVolume * gl_volume,
|
||||||
const ModelObjectPtrs objects)
|
const ModelObjectPtrs& objects)
|
||||||
{
|
{
|
||||||
const GLVolume::CompositeID &id = gl_volume->composite_id;
|
const GLVolume::CompositeID &id = gl_volume->composite_id;
|
||||||
|
|
||||||
@ -526,7 +529,7 @@ ModelVolume *GLGizmoEmboss::get_model_volume(const GLVolume * gl_volume,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ModelVolume *GLGizmoEmboss::get_selected_volume(const Selection &selection,
|
ModelVolume *GLGizmoEmboss::get_selected_volume(const Selection &selection,
|
||||||
const ModelObjectPtrs objects)
|
const ModelObjectPtrs& objects)
|
||||||
{
|
{
|
||||||
int object_idx = selection.get_object_idx();
|
int object_idx = selection.get_object_idx();
|
||||||
// is more object selected?
|
// is more object selected?
|
||||||
@ -609,19 +612,6 @@ void GLGizmoEmboss::draw_window()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_imgui->disabled_end();
|
m_imgui->disabled_end();
|
||||||
|
|
||||||
ImGui::SameLine();
|
|
||||||
const Selection &s = m_parent.get_selection();
|
|
||||||
bool dragging = s.is_dragging();
|
|
||||||
ImGui::Checkbox("dragging", &dragging);
|
|
||||||
static bool change_position = true;
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::Checkbox("position", &change_position);
|
|
||||||
if (change_position) {
|
|
||||||
// draw text on coordinate of mouse
|
|
||||||
preview_positon();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform3d GLGizmoEmboss::get_emboss_transformation(const Vec3f &position,
|
Transform3d GLGizmoEmboss::get_emboss_transformation(const Vec3f &position,
|
||||||
@ -710,127 +700,6 @@ std::optional<Transform3d> GLGizmoEmboss::transform_on_surface(
|
|||||||
return get_emboss_transformation(closest->position, closest->normal);
|
return get_emboss_transformation(closest->position, closest->normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoEmboss::preview_positon() {
|
|
||||||
Vec2d mouse_pos = m_parent.get_local_mouse_position();
|
|
||||||
|
|
||||||
|
|
||||||
auto rc = m_c->raycaster();
|
|
||||||
//auto rc2 = rc->raycaster();
|
|
||||||
|
|
||||||
static std::unique_ptr<MeshRaycaster> mrc;
|
|
||||||
if (m_volume == nullptr) return;
|
|
||||||
|
|
||||||
// TODO: select hovered volume
|
|
||||||
static ModelVolume *volume = nullptr;
|
|
||||||
ModelVolume *prev_volume = volume;
|
|
||||||
volume = nullptr;
|
|
||||||
for (ModelVolume *mv : m_volume->get_object()->volumes) {
|
|
||||||
if (!mv->is_model_part()) continue;
|
|
||||||
if (mv->text_configuration.has_value()) continue;
|
|
||||||
volume = mv;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prev_volume != nullptr && prev_volume != volume) {
|
|
||||||
// change volume
|
|
||||||
mrc = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no volume for raycast
|
|
||||||
if (volume == nullptr) return;
|
|
||||||
|
|
||||||
if (mrc == nullptr) {
|
|
||||||
mrc = std::make_unique<MeshRaycaster>(volume->mesh());
|
|
||||||
}
|
|
||||||
|
|
||||||
// find glvolume for transformation
|
|
||||||
const GLVolume *gl_volume = nullptr;
|
|
||||||
for (const GLVolume *v : m_parent.get_volumes().volumes) {
|
|
||||||
auto &cid = v->composite_id;
|
|
||||||
ObjectID oid = m_parent.get_model()->objects[cid.object_id]->volumes[cid.volume_id]->id();
|
|
||||||
if (oid != volume->id()) continue;
|
|
||||||
gl_volume = v;
|
|
||||||
}
|
|
||||||
if (gl_volume == nullptr) return;
|
|
||||||
|
|
||||||
Transform3d trafo = gl_volume->world_matrix();
|
|
||||||
const Camera &camera = wxGetApp().plater()->get_camera();
|
|
||||||
|
|
||||||
Vec3f position;
|
|
||||||
Vec3f normal;
|
|
||||||
size_t face_id;
|
|
||||||
if (mrc->unproject_on_mesh(mouse_pos, trafo, camera, position, normal, nullptr, &face_id)) {
|
|
||||||
// draw triangle
|
|
||||||
auto &its =volume->mesh().its;
|
|
||||||
auto &triangle = its.indices[face_id];
|
|
||||||
Points pts;
|
|
||||||
for (const auto &t : triangle) {
|
|
||||||
auto &v = its.vertices[t];
|
|
||||||
Points p = CameraUtils::project(camera,
|
|
||||||
{trafo * v.cast<double>()});
|
|
||||||
pts.push_back(p.front());
|
|
||||||
}
|
|
||||||
ImGuiWrapper::draw(Polygon(pts));
|
|
||||||
|
|
||||||
m_preview.init_from(m_volume->mesh().its);
|
|
||||||
|
|
||||||
// up and emboss direction for generated model
|
|
||||||
Vec3d text_up = Vec3d::UnitY();
|
|
||||||
Vec3d text_view = Vec3d::UnitZ();
|
|
||||||
|
|
||||||
// wanted up direction of result
|
|
||||||
Vec3d normal_up_dir = Vec3d::UnitZ();
|
|
||||||
if (abs(normal.z()) > 0.9) normal_up_dir = Vec3d::UnitY();
|
|
||||||
|
|
||||||
Vec3d normal3d = normal.cast<double>();
|
|
||||||
normal3d.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 normal_up = normal3d.cross(normal_up_dir).cross(normal3d);
|
|
||||||
normal_up.normalize(); // normal3d is NOT perpendicular to normal_up_dir
|
|
||||||
|
|
||||||
// perpendicular to emboss vector of text and normal
|
|
||||||
Vec3d axis_view = text_view.cross(normal3d);
|
|
||||||
double angle_view = std::acos(text_view.dot(normal3d)); // in rad
|
|
||||||
axis_view.normalize();
|
|
||||||
Eigen::AngleAxis view_rot(angle_view, axis_view);
|
|
||||||
Vec3d normal_up_rot = view_rot.matrix().inverse() * normal_up;
|
|
||||||
normal_up_rot.normalize();
|
|
||||||
double angle_up = std::acos(text_up.dot(normal_up_rot));
|
|
||||||
|
|
||||||
// text_view and text_view2 should have same direction
|
|
||||||
Vec3d text_view2 = text_up.cross(normal_up_rot);
|
|
||||||
Vec3d diff_view = text_view - 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_view);
|
|
||||||
|
|
||||||
Transform3d transform = Transform3d::Identity();
|
|
||||||
transform.translate(position.cast<double>());
|
|
||||||
transform.rotate(view_rot);
|
|
||||||
transform.rotate(up_rot);
|
|
||||||
|
|
||||||
transform = get_emboss_transformation(position, normal);
|
|
||||||
|
|
||||||
//Transform3d rot = Transform3d::Identity();
|
|
||||||
//rot.rotate(Eigen::AngleAxis(angle, axis));
|
|
||||||
|
|
||||||
m_preview_trmat = trafo * transform;
|
|
||||||
} else {
|
|
||||||
m_preview.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// draw mouse position
|
|
||||||
Point mouse_point = mouse_pos.cast<int>();
|
|
||||||
Slic3r::Polygon mouse_triangle({mouse_point, mouse_point + Point(55, 0),
|
|
||||||
mouse_point + Point(0, 55)});
|
|
||||||
ImGuiWrapper::draw(mouse_triangle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLGizmoEmboss::draw_font_list()
|
void GLGizmoEmboss::draw_font_list()
|
||||||
{
|
{
|
||||||
const float & max_width = m_gui_cfg->max_font_name_width;
|
const float & max_width = m_gui_cfg->max_font_name_width;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "GLGizmoBase.hpp"
|
#include "GLGizmoBase.hpp"
|
||||||
#include "GLGizmoRotate.hpp"
|
#include "GLGizmoRotate.hpp"
|
||||||
#include "slic3r/GUI/GLTexture.hpp"
|
#include "slic3r/GUI/GLTexture.hpp"
|
||||||
|
#include "slic3r/Utils/RaycastManager.hpp"
|
||||||
|
|
||||||
#include "admesh/stl.h" // indexed_triangle_set
|
#include "admesh/stl.h" // indexed_triangle_set
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@ -69,13 +70,12 @@ private:
|
|||||||
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();
|
||||||
static ModelVolume *get_model_volume(const GLVolume *gl_volume, const ModelObjectPtrs objects);
|
static ModelVolume *get_model_volume(const GLVolume *gl_volume, const ModelObjectPtrs& objects);
|
||||||
static ModelVolume *get_selected_volume(const Selection &selection, const ModelObjectPtrs objects);
|
static ModelVolume *get_selected_volume(const Selection &selection, const ModelObjectPtrs& objects);
|
||||||
// create volume from text - main functionality
|
// create volume from text - main functionality
|
||||||
bool process();
|
bool process();
|
||||||
void close();
|
void close();
|
||||||
void draw_window();
|
void draw_window();
|
||||||
void preview_positon();
|
|
||||||
void draw_font_list();
|
void draw_font_list();
|
||||||
void draw_text_input();
|
void draw_text_input();
|
||||||
void draw_advanced();
|
void draw_advanced();
|
||||||
@ -159,9 +159,10 @@ private:
|
|||||||
// Rotation gizmo
|
// Rotation gizmo
|
||||||
GLGizmoRotate m_rotate_gizmo;
|
GLGizmoRotate m_rotate_gizmo;
|
||||||
|
|
||||||
// preview position
|
// TODO: it should be accessible by other gizmo too.
|
||||||
GLModel m_preview;
|
// May be move to plater?
|
||||||
Transform3d m_preview_trmat;
|
RaycastManager m_raycast_manager;
|
||||||
|
std::optional<Transform3d> m_temp_transformation;
|
||||||
|
|
||||||
// initialize when GL is accessible
|
// initialize when GL is accessible
|
||||||
bool m_is_initialized;
|
bool m_is_initialized;
|
||||||
|
122
src/slic3r/Utils/RaycastManager.cpp
Normal file
122
src/slic3r/Utils/RaycastManager.cpp
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
#include "RaycastManager.hpp"
|
||||||
|
|
||||||
|
// include for earn camera
|
||||||
|
#include "slic3r/GUI/GUI_App.hpp"
|
||||||
|
#include "slic3r/GUI/Plater.hpp"
|
||||||
|
#include "slic3r/GUI/Camera.hpp"
|
||||||
|
|
||||||
|
using namespace Slic3r::GUI;
|
||||||
|
|
||||||
|
void RaycastManager::actualize(const ModelObjectPtrs &objects,
|
||||||
|
const ISkip * skip)
|
||||||
|
{
|
||||||
|
// check if volume was removed
|
||||||
|
std::set<size_t> removed_casters;
|
||||||
|
for (const auto &raycaster_item : raycasters)
|
||||||
|
removed_casters.insert(raycaster_item.first);
|
||||||
|
|
||||||
|
// check if inscance was removed
|
||||||
|
std::set<TrKey> removed_transformation;
|
||||||
|
for (const auto &item : transformations)
|
||||||
|
removed_transformation.insert(item.first);
|
||||||
|
|
||||||
|
for (const ModelObject *object : objects) {
|
||||||
|
// actualize MeshRaycaster
|
||||||
|
for (const ModelVolume *volume : object->volumes) {
|
||||||
|
size_t oid = volume->id().id;
|
||||||
|
if (skip != nullptr && skip->skip(oid)) {
|
||||||
|
removed_casters.erase(oid);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto item = raycasters.find(oid);
|
||||||
|
if (item != raycasters.end()) {
|
||||||
|
removed_casters.erase(oid);
|
||||||
|
// alredy in list only actualize
|
||||||
|
// TODO: check triangles when change than actualize MeshRaycaster
|
||||||
|
} else {
|
||||||
|
// add new raycaster
|
||||||
|
auto raycaster = std::make_unique<MeshRaycaster>(
|
||||||
|
volume->mesh());
|
||||||
|
raycasters.insert(std::make_pair(oid, std::move(raycaster)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// actualize transformation matrices
|
||||||
|
for (const ModelVolume *volume : object->volumes) {
|
||||||
|
if (skip != nullptr && skip->skip(volume->id().id)) continue;
|
||||||
|
const Transform3d &volume_tr = volume->get_matrix();
|
||||||
|
for (const ModelInstance *instance : object->instances) {
|
||||||
|
const Transform3d& instrance_tr = instance->get_matrix();
|
||||||
|
Transform3d transformation = instrance_tr * volume_tr;
|
||||||
|
// TODO: add SLA shift Z
|
||||||
|
// transformation.translation()(2) += m_sla_shift_z;
|
||||||
|
|
||||||
|
TrKey tr_key = std::make_pair(instance->id().id, volume->id().id);
|
||||||
|
auto item = transformations.find(tr_key);
|
||||||
|
if (item != transformations.end()) {
|
||||||
|
// actualize transformation all the time
|
||||||
|
item->second = transformation;
|
||||||
|
removed_transformation.erase(tr_key);
|
||||||
|
} else {
|
||||||
|
// add new transformation
|
||||||
|
transformations.insert(
|
||||||
|
std::make_pair(tr_key, transformation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove non existing volumes
|
||||||
|
for (size_t volume_oid : removed_casters) raycasters.erase(volume_oid);
|
||||||
|
// remove non existing transformations
|
||||||
|
for (const TrKey& transformation_key : removed_transformation)
|
||||||
|
transformations.erase(transformation_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<RaycastManager::Hit> RaycastManager::unproject(
|
||||||
|
const Vec2d &mouse_pos, const ISkip *skip) const
|
||||||
|
{
|
||||||
|
struct HitWithDistance: public Hit
|
||||||
|
{
|
||||||
|
double squared_distance;
|
||||||
|
HitWithDistance(double squared_distance,
|
||||||
|
const TrKey & key,
|
||||||
|
const SurfacePoint &surface_point)
|
||||||
|
: Hit(key, surface_point.position, surface_point.normal)
|
||||||
|
, squared_distance(squared_distance)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
std::optional<HitWithDistance> closest;
|
||||||
|
|
||||||
|
const Camera &camera = wxGetApp().plater()->get_camera();
|
||||||
|
for (const auto &item : transformations) {
|
||||||
|
const TrKey &key = item.first;
|
||||||
|
size_t volume_id = key.second;
|
||||||
|
if (skip != nullptr && skip->skip(volume_id)) continue;
|
||||||
|
const Transform3d &transformation = item.second;
|
||||||
|
auto raycaster_it = raycasters.find(volume_id);
|
||||||
|
if (raycaster_it == raycasters.end()) continue;
|
||||||
|
const MeshRaycaster &raycaster = *(raycaster_it->second);
|
||||||
|
SurfacePoint surface_point;
|
||||||
|
bool success = raycaster.unproject_on_mesh(
|
||||||
|
mouse_pos, transformation, camera,
|
||||||
|
surface_point.position, surface_point.normal);
|
||||||
|
if (!success) continue;
|
||||||
|
|
||||||
|
Vec3d act_hit_tr = transformation * surface_point.position.cast<double>();
|
||||||
|
double squared_distance = (camera.get_position() - act_hit_tr).squaredNorm();
|
||||||
|
if (closest.has_value() &&
|
||||||
|
closest->squared_distance < squared_distance)
|
||||||
|
continue;
|
||||||
|
closest = HitWithDistance(squared_distance, key, surface_point);
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (!closest.has_value()) return {};
|
||||||
|
return closest;
|
||||||
|
}
|
||||||
|
|
||||||
|
Slic3r::Transform3d RaycastManager::get_transformation(const TrKey &tr_key) const {
|
||||||
|
auto item = transformations.find(tr_key);
|
||||||
|
if (item == transformations.end()) return Transform3d::Identity();
|
||||||
|
return item->second;
|
||||||
|
}
|
103
src/slic3r/Utils/RaycastManager.hpp
Normal file
103
src/slic3r/Utils/RaycastManager.hpp
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#ifndef slic3r_RaycastManager_hpp_
|
||||||
|
#define slic3r_RaycastManager_hpp_
|
||||||
|
|
||||||
|
#include <memory> // unique_ptr
|
||||||
|
#include <optional> // unique_ptr
|
||||||
|
#include <map>
|
||||||
|
#include "slic3r/GUI/MeshUtils.hpp" // MeshRaycaster
|
||||||
|
#include "libslic3r/Point.hpp" // Transform3d
|
||||||
|
#include "libslic3r/ObjectID.hpp"
|
||||||
|
#include "libslic3r/Model.hpp" // ModelObjectPtrs, ModelObject, ModelInstance, ModelVolume
|
||||||
|
|
||||||
|
namespace Slic3r::GUI{
|
||||||
|
|
||||||
|
class RaycastManager
|
||||||
|
{
|
||||||
|
// ModelVolume
|
||||||
|
std::map<size_t, std::unique_ptr<MeshRaycaster>> raycasters;
|
||||||
|
|
||||||
|
// Key for transformation consist of unique volume and instance
|
||||||
|
// ModelInstance, ModelVolume
|
||||||
|
using TrKey = std::pair<size_t, size_t>;
|
||||||
|
std::map<TrKey, Transform3d> transformations;
|
||||||
|
|
||||||
|
// should contain shared pointer to camera but it is not shared pointer so it need it every time when casts rays
|
||||||
|
|
||||||
|
public:
|
||||||
|
class ISkip{
|
||||||
|
public:
|
||||||
|
virtual ~ISkip() = default;
|
||||||
|
/// <summary>
|
||||||
|
/// Condition to not process specific transformation
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">Transformation key</param>
|
||||||
|
/// <returns>True on skip otherwise false</returns>
|
||||||
|
//virtual bool skip(const TrKey &key) const { return false; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Condition to not process model volume
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model_volume_id">ObjectID of model volume to not process</param>
|
||||||
|
/// <returns>True on skip otherwise false</returns>
|
||||||
|
virtual bool skip(const size_t &model_volume_id) const { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Actualize raycasters + transformation
|
||||||
|
/// Detection of removed object
|
||||||
|
/// Detection of removed instance
|
||||||
|
/// Detection of removed volume
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="skip">Condifiton for skip actualization</param>
|
||||||
|
/// <param name="objects">Model representation</param>
|
||||||
|
void actualize(const ModelObjectPtrs &objects,
|
||||||
|
const ISkip * skip = nullptr);
|
||||||
|
|
||||||
|
// TODO: it is more general object move outside of this class
|
||||||
|
struct SurfacePoint
|
||||||
|
{
|
||||||
|
Vec3f position = Vec3f::Zero();
|
||||||
|
Vec3f normal = Vec3f::UnitZ();
|
||||||
|
SurfacePoint() = default;
|
||||||
|
SurfacePoint(Vec3f position, Vec3f normal)
|
||||||
|
: position(position), normal(normal)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Hit: public SurfacePoint
|
||||||
|
{
|
||||||
|
TrKey tr_key;
|
||||||
|
Hit(TrKey tr_key, Vec3f position, Vec3f normal)
|
||||||
|
: SurfacePoint(position, normal), tr_key(tr_key)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SkipVolume: public ISkip
|
||||||
|
{
|
||||||
|
size_t volume_id;
|
||||||
|
public:
|
||||||
|
SkipVolume(size_t volume_id) : volume_id(volume_id) {}
|
||||||
|
bool skip(const size_t &model_volume_id) const override { return model_volume_id == volume_id; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unproject on mesh by Mesh raycasters
|
||||||
|
/// Note: Function use current camera position from wxGetApp()
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mouse_pos">Position of mouse on screen</param>
|
||||||
|
/// <param name="skip">Define which caster will be skipped, null mean no skip</param>
|
||||||
|
/// <returns>Position on surface, normal direction and transformation key, which define hitted object instance</returns>
|
||||||
|
std::optional<Hit> unproject(const Vec2d &mouse_pos,
|
||||||
|
const ISkip *skip = nullptr) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Getter on transformation
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tr_key">Define transformation</param>
|
||||||
|
/// <returns>Transformation for key</returns>
|
||||||
|
Transform3d get_transformation(const TrKey &tr_key) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Slic3r::GUI
|
||||||
|
|
||||||
|
#endif // slic3r_RaycastManager_hpp_
|
Loading…
x
Reference in New Issue
Block a user