mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-11 16:57:53 -06:00
WIP: Added a circle cursor and naive logic to select triangles inside
Deselection is possible when holding shift Triangles obscured by the mesh are selected nonetheless (so far)
This commit is contained in:
parent
08daddb5de
commit
2e71dcefc3
4 changed files with 141 additions and 23 deletions
|
@ -107,6 +107,7 @@ void GLGizmoFdmSupports::on_render() const
|
|||
|
||||
render_triangles(selection);
|
||||
render_clipping_plane(selection);
|
||||
render_cursor_circle();
|
||||
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
}
|
||||
|
@ -122,7 +123,9 @@ void GLGizmoFdmSupports::render_triangles(const Selection& selection) const
|
|||
|
||||
::glColor3f(0.0f, 0.37f, 1.0f);
|
||||
|
||||
for (size_t facet_idx : m_selected_facets) {
|
||||
for (size_t facet_idx=0; facet_idx<m_selected_facets.size(); ++facet_idx) {
|
||||
if (! m_selected_facets[facet_idx])
|
||||
continue;
|
||||
stl_normal normal = 0.01f * MeshRaycaster::get_triangle_normal(m_mesh->its, facet_idx);
|
||||
::glPushMatrix();
|
||||
::glTranslatef(normal(0), normal(1), normal(2));
|
||||
|
@ -135,9 +138,6 @@ void GLGizmoFdmSupports::render_triangles(const Selection& selection) const
|
|||
::glEnd();
|
||||
::glPopMatrix();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void GLGizmoFdmSupports::render_clipping_plane(const Selection& selection) const
|
||||
|
@ -170,6 +170,53 @@ void GLGizmoFdmSupports::render_clipping_plane(const Selection& selection) const
|
|||
}
|
||||
}
|
||||
|
||||
void GLGizmoFdmSupports::render_cursor_circle() const
|
||||
{
|
||||
const Camera& camera = m_parent.get_camera();
|
||||
float zoom = (float)camera.get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
|
||||
std::cout << zoom << " " << inv_zoom << std::endl;
|
||||
|
||||
Size cnv_size = m_parent.get_canvas_size();
|
||||
float cnv_half_width = 0.5f * (float)cnv_size.get_width();
|
||||
float cnv_half_height = 0.5f * (float)cnv_size.get_height();
|
||||
if ((cnv_half_width == 0.0f) || (cnv_half_height == 0.0f))
|
||||
return;
|
||||
Vec2d mouse_pos(m_parent.get_local_mouse_position()(0), m_parent.get_local_mouse_position()(1));
|
||||
Vec2d center(mouse_pos(0) - cnv_half_width, cnv_half_height - mouse_pos(1));
|
||||
center = center * inv_zoom;
|
||||
|
||||
glsafe(::glLineWidth(1.5f));
|
||||
float color[3];
|
||||
color[2] = 0.3f;
|
||||
glsafe(::glColor3fv(color));
|
||||
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glLoadIdentity());
|
||||
// ensure that the circle is renderered inside the frustrum
|
||||
glsafe(::glTranslated(0.0, 0.0, -(camera.get_near_z() + 0.5)));
|
||||
// ensure that the overlay fits the frustrum near z plane
|
||||
double gui_scale = camera.get_gui_scale();
|
||||
glsafe(::glScaled(gui_scale, gui_scale, 1.0));
|
||||
|
||||
glsafe(::glPushAttrib(GL_ENABLE_BIT));
|
||||
glsafe(::glLineStipple(4, 0xAAAA));
|
||||
glsafe(::glEnable(GL_LINE_STIPPLE));
|
||||
|
||||
::glBegin(GL_LINE_LOOP);
|
||||
for (double angle=0; angle<2*M_PI; angle+=M_PI/20.)
|
||||
::glVertex2f(GLfloat(center.x()+m_cursor_radius*cos(angle)), GLfloat(center.y()+m_cursor_radius*sin(angle)));
|
||||
glsafe(::glEnd());
|
||||
|
||||
glsafe(::glPopAttrib());
|
||||
|
||||
glsafe(::glPopMatrix());
|
||||
|
||||
}
|
||||
|
||||
|
||||
void GLGizmoFdmSupports::on_render_for_picking() const
|
||||
{
|
||||
|
@ -209,6 +256,20 @@ void GLGizmoFdmSupports::update_mesh()
|
|||
m_mesh = &m_model_object->volumes.front()->mesh();
|
||||
m_its = &m_mesh->its;
|
||||
|
||||
m_selected_facets.clear();
|
||||
m_selected_facets.resize(m_mesh->its.indices.size());
|
||||
|
||||
// Prepare vector of vertex_index - facet_index pairs to quickly find adjacent facets
|
||||
m_neighbors.clear();
|
||||
m_neighbors.resize(3 * m_mesh->its.indices.size());
|
||||
for (size_t i=0; i<m_mesh->its.indices.size(); ++i) {
|
||||
const stl_triangle_vertex_indices& ind = m_mesh->its.indices[i];
|
||||
m_neighbors.emplace_back(ind(0), i);
|
||||
m_neighbors.emplace_back(ind(1), i);
|
||||
m_neighbors.emplace_back(ind(2), i);
|
||||
}
|
||||
std::sort(m_neighbors.begin(), m_neighbors.end());
|
||||
|
||||
// If this is different mesh than last time or if the AABB tree is uninitialized, recalculate it.
|
||||
if (m_model_object_id != m_model_object->id() || ! m_mesh_raycaster)
|
||||
m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh));
|
||||
|
@ -218,9 +279,10 @@ void GLGizmoFdmSupports::update_mesh()
|
|||
|
||||
|
||||
|
||||
// Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal
|
||||
// Return false if no intersection was found, true otherwise.
|
||||
bool GLGizmoFdmSupports::unproject_on_mesh(const Vec2d& mouse_pos, size_t& facet_idx)
|
||||
// Unprojects the mouse position on the mesh and saves hit facet index into facet_idx
|
||||
// Position of the hit in mesh coords is copied into *position, if provided.
|
||||
// Returns false if no intersection was found, true otherwise.
|
||||
bool GLGizmoFdmSupports::unproject_on_mesh(const Vec2d& mouse_pos, size_t& facet_idx, Vec3f* position)
|
||||
{
|
||||
// if the gizmo doesn't have the V, F structures for igl, calculate them first:
|
||||
if (! m_mesh_raycaster)
|
||||
|
@ -235,12 +297,21 @@ bool GLGizmoFdmSupports::unproject_on_mesh(const Vec2d& mouse_pos, size_t& facet
|
|||
// The raycaster query
|
||||
Vec3f hit;
|
||||
Vec3f normal;
|
||||
if (m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_clipping_plane.get(), &facet_idx))
|
||||
if (m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_clipping_plane.get(), &facet_idx)) {
|
||||
if (position)
|
||||
*position = hit;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator<(const GLGizmoFdmSupports::NeighborData& a, const GLGizmoFdmSupports::NeighborData& b) {
|
||||
return a.first < b.first;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Following function is called from GLCanvas3D to inform the gizmo about a mouse/keyboard event.
|
||||
// The gizmo has an opportunity to react - if it does, it should return true so that the Canvas3D is
|
||||
// aware that the event was reacted to and stops trying to make different sense of it. If the gizmo
|
||||
|
@ -266,9 +337,51 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||
|
||||
if (action == SLAGizmoEventType::LeftDown || (action == SLAGizmoEventType::Dragging && m_wait_for_up_event)) {
|
||||
size_t facet_idx = 0;
|
||||
if (unproject_on_mesh(mouse_position, facet_idx)) {
|
||||
m_selected_facets.push_back(facet_idx);
|
||||
Vec3f hit_pos;
|
||||
if (unproject_on_mesh(mouse_position, facet_idx, &hit_pos)) {
|
||||
bool select = ! shift_down;
|
||||
|
||||
// Calculate direction from camera to the hit (in mesh coords):
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
Geometry::Transformation trafo = volume->get_instance_transformation();
|
||||
trafo.set_offset(trafo.get_offset());
|
||||
Vec3f dir = ((trafo.get_matrix().inverse() * m_parent.get_camera().get_position()).cast<float>() - hit_pos).normalized();
|
||||
|
||||
// Calculate how far can a point be from the line (in mesh coords).
|
||||
// FIXME: This should account for (possibly non-uniform) scaling of the mesh.
|
||||
float limit = pow(m_cursor_radius, 2.f);
|
||||
|
||||
|
||||
// A lambda to calculate distance from the line:
|
||||
auto squared_distance_from_line = [&hit_pos, &dir](const Vec3f point) -> float {
|
||||
Vec3f diff = hit_pos - point;
|
||||
return (diff - diff.dot(dir) * dir).squaredNorm();
|
||||
};
|
||||
|
||||
// Now go through the facets and de/select those close enough to the line (FIXME: efficiency)
|
||||
for (size_t i=0; i<m_selected_facets.size(); ++i) {
|
||||
float dist = squared_distance_from_line(m_mesh->its.vertices[m_mesh->its.indices[i](0)]);
|
||||
if (dist < limit)
|
||||
m_selected_facets[i] = select;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//size_t vertex_idx = m_mesh->its.indices[facet_idx](0);
|
||||
//auto it = m_neighbors.begin();
|
||||
//std::vector<bool> visited(m_mesh->its.indices.size(), false);
|
||||
|
||||
//while (it != m_neighbors.end() && it->second == facet_idx)
|
||||
// it = std::lower_bound(it, m_neighbors.end(), std::make_pair(vertex_idx, size_t(0)));
|
||||
|
||||
//facet_idx = it->second;
|
||||
//vertex_idx = m_mesh->its.indices[facet_idx](0);
|
||||
|
||||
|
||||
|
||||
m_wait_for_up_event = true;
|
||||
m_parent.set_as_dirty();
|
||||
return true;
|
||||
}
|
||||
if (action == SLAGizmoEventType::Dragging && m_wait_for_up_event)
|
||||
|
@ -294,8 +407,6 @@ ClippingPlane GLGizmoFdmSupports::get_fdm_clipping_plane() const
|
|||
return ClippingPlane(-m_clipping_plane->get_normal(), m_clipping_plane->get_data()[3]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
if (!m_model_object)
|
||||
|
@ -337,6 +448,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
|||
if (ImGui::SliderFloat(" ", &m_clipping_plane_distance, 0.f, 1.f, "%.2f"))
|
||||
update_clipping_plane(true);
|
||||
|
||||
ImGui::SliderFloat(" ", &m_cursor_radius, 0.f, 8.f, "%.2f");
|
||||
|
||||
m_imgui->end();
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ private:
|
|||
ObjectID m_model_object_id = 0;
|
||||
int m_active_instance = -1;
|
||||
float m_active_instance_bb_radius; // to cache the bb
|
||||
bool unproject_on_mesh(const Vec2d& mouse_pos, size_t& facet_idx);
|
||||
bool unproject_on_mesh(const Vec2d& mouse_pos, size_t& facet_idx, Vec3f* position = nullptr);
|
||||
|
||||
|
||||
GLUquadricObj* m_quadric;
|
||||
|
@ -30,9 +30,9 @@ private:
|
|||
const TriangleMesh* m_mesh;
|
||||
const indexed_triangle_set* m_its;
|
||||
mutable std::vector<Vec2f> m_triangles;
|
||||
float m_cursor_radius = 2.f;
|
||||
|
||||
std::vector<size_t> m_selected_facets;
|
||||
|
||||
std::vector<bool> m_selected_facets;
|
||||
|
||||
public:
|
||||
GLGizmoFdmSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
|
@ -40,6 +40,7 @@ public:
|
|||
void set_fdm_support_data(ModelObject* model_object, const Selection& selection);
|
||||
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
|
||||
ClippingPlane get_fdm_clipping_plane() const;
|
||||
using NeighborData = std::pair<size_t, size_t>;
|
||||
|
||||
|
||||
private:
|
||||
|
@ -49,6 +50,7 @@ private:
|
|||
|
||||
void render_triangles(const Selection& selection) const;
|
||||
void render_clipping_plane(const Selection& selection) const;
|
||||
void render_cursor_circle() const;
|
||||
bool is_mesh_update_necessary() const;
|
||||
void update_mesh();
|
||||
|
||||
|
@ -64,6 +66,8 @@ private:
|
|||
|
||||
mutable std::unique_ptr<MeshClipper> m_object_clipper;
|
||||
|
||||
std::vector<NeighborData> m_neighbors; // pairs of vertex_index - facet_index
|
||||
|
||||
|
||||
bool is_point_clipped(const Vec3d& point) const;
|
||||
void update_clipping_plane(bool keep_normal = false) const;
|
||||
|
|
|
@ -102,9 +102,8 @@ Vec3f MeshRaycaster::get_triangle_normal(const indexed_triangle_set& its, size_t
|
|||
return Vec3f(a.cross(b)).normalized();
|
||||
}
|
||||
|
||||
bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
|
||||
Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane,
|
||||
size_t* facet_idx) const
|
||||
void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
|
||||
Vec3d& point, Vec3d& direction) const
|
||||
{
|
||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||
const Transform3d& model_mat = camera.get_view_matrix();
|
||||
|
|
|
@ -113,6 +113,9 @@ public:
|
|||
: m_emesh(mesh)
|
||||
{}
|
||||
|
||||
void line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
|
||||
Vec3d& point, Vec3d& direction) const;
|
||||
|
||||
// Given a mouse position, this returns true in case it is on the mesh.
|
||||
bool unproject_on_mesh(
|
||||
const Vec2d& mouse_pos,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue