Sphere selection added as an option for painting gizmos

This commit is contained in:
Lukas Matena 2020-09-30 17:01:51 +02:00
parent c696e6ec19
commit 1ca8120398
6 changed files with 103 additions and 10 deletions

View File

@ -35,14 +35,15 @@ void TriangleSelector::Triangle::set_division(int sides_to_split, int special_si
void TriangleSelector::select_patch(const Vec3f& hit, int facet_start, void TriangleSelector::select_patch(const Vec3f& hit, int facet_start,
const Vec3f& source, const Vec3f& dir, const Vec3f& source, const Vec3f& dir,
float radius, EnforcerBlockerType new_state) float radius, CursorType cursor_type,
EnforcerBlockerType new_state)
{ {
assert(facet_start < m_orig_size_indices); assert(facet_start < m_orig_size_indices);
assert(is_approx(dir.norm(), 1.f)); assert(is_approx(dir.norm(), 1.f));
// Save current cursor center, squared radius and camera direction, // Save current cursor center, squared radius and camera direction,
// so we don't have to pass it around. // so we don't have to pass it around.
m_cursor = {hit, source, dir, radius*radius}; m_cursor = {hit, source, dir, radius*radius, cursor_type};
// In case user changed cursor size since last time, update triangle edge limit. // In case user changed cursor size since last time, update triangle edge limit.
if (m_old_cursor_radius != radius) { if (m_old_cursor_radius != radius) {
@ -61,7 +62,7 @@ void TriangleSelector::select_patch(const Vec3f& hit, int facet_start,
// add neighboring facets to list to be proccessed later // add neighboring facets to list to be proccessed later
for (int n=0; n<3; ++n) { for (int n=0; n<3; ++n) {
int neighbor_idx = m_mesh->stl.neighbors_start[facet].neighbor[n]; int neighbor_idx = m_mesh->stl.neighbors_start[facet].neighbor[n];
if (neighbor_idx >=0 && true/*faces_camera(neighbor_idx)*/) if (neighbor_idx >=0 && (m_cursor.type == SPHERE || faces_camera(neighbor_idx)))
facets_to_check.push_back(neighbor_idx); facets_to_check.push_back(neighbor_idx);
} }
} }
@ -207,9 +208,11 @@ void TriangleSelector::split_triangle(int facet_idx)
bool TriangleSelector::is_point_inside_cursor(const Vec3f& point) const bool TriangleSelector::is_point_inside_cursor(const Vec3f& point) const
{ {
Vec3f diff = m_cursor.center - point; Vec3f diff = m_cursor.center - point;
// return (diff - diff.dot(m_cursor.dir) * m_cursor.dir).squaredNorm() < m_cursor.radius_sqr;
return diff.squaredNorm() < m_cursor.radius_sqr; if (m_cursor.type == CIRCLE)
return (diff - diff.dot(m_cursor.dir) * m_cursor.dir).squaredNorm() < m_cursor.radius_sqr;
else // SPHERE
return diff.squaredNorm() < m_cursor.radius_sqr;
} }

View File

@ -17,6 +17,11 @@ enum class EnforcerBlockerType : int8_t;
// to recursively subdivide the triangles and make the selection finer. // to recursively subdivide the triangles and make the selection finer.
class TriangleSelector { class TriangleSelector {
public: public:
enum CursorType {
CIRCLE,
SPHERE
};
void set_edge_limit(float edge_limit); void set_edge_limit(float edge_limit);
// Create new object on a TriangleMesh. The referenced mesh must // Create new object on a TriangleMesh. The referenced mesh must
@ -29,6 +34,7 @@ public:
const Vec3f& source, // camera position (mesh coords) const Vec3f& source, // camera position (mesh coords)
const Vec3f& dir, // direction of the ray (mesh coords) const Vec3f& dir, // direction of the ray (mesh coords)
float radius, // radius of the cursor float radius, // radius of the cursor
CursorType type, // current type of cursor
EnforcerBlockerType new_state); // enforcer or blocker? EnforcerBlockerType new_state); // enforcer or blocker?
// Get facets currently in the given state. // Get facets currently in the given state.
@ -127,6 +133,7 @@ protected:
Vec3f source; Vec3f source;
Vec3f dir; Vec3f dir;
float radius_sqr; float radius_sqr;
CursorType type;
}; };
Cursor m_cursor; Cursor m_cursor;

View File

@ -66,7 +66,7 @@ void GLGizmoFdmSupports::on_render() const
render_triangles(selection); render_triangles(selection);
m_c->object_clipper()->render_cut(); m_c->object_clipper()->render_cut();
render_cursor_circle(); render_cursor();
glsafe(::glDisable(GL_BLEND)); glsafe(::glDisable(GL_BLEND));
} }

View File

@ -21,6 +21,14 @@ GLGizmoPainterBase::GLGizmoPainterBase(GLCanvas3D& parent, const std::string& ic
: GLGizmoBase(parent, icon_filename, sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id)
{ {
m_clipping_plane.reset(new ClippingPlane()); m_clipping_plane.reset(new ClippingPlane());
// Make sphere and save it into a vertex buffer.
const TriangleMesh sphere_mesh = make_sphere(1., (2*M_PI)/24.);
for (size_t i=0; i<sphere_mesh.its.vertices.size(); ++i)
m_vbo_sphere.push_geometry(sphere_mesh.its.vertices[i].cast<double>(),
sphere_mesh.stl.facet_start[i].normal.cast<double>());
for (const stl_triangle_vertex_indices& indices : sphere_mesh.its.indices)
m_vbo_sphere.push_triangle(indices(0), indices(1), indices(2));
m_vbo_sphere.finalize_geometry(true);
} }
@ -117,10 +125,18 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection) const
} }
void GLGizmoPainterBase::render_cursor() const
{
if (m_cursor_type == TriangleSelector::SPHERE)
render_cursor_sphere();
else
render_cursor_circle();
}
void GLGizmoPainterBase::render_cursor_circle() const void GLGizmoPainterBase::render_cursor_circle() const
{ {
return;
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
float zoom = (float)camera.get_zoom(); float zoom = (float)camera.get_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
@ -164,6 +180,46 @@ void GLGizmoPainterBase::render_cursor_circle() const
} }
void GLGizmoPainterBase::render_cursor_sphere() const
{
int mesh_id = m_last_mesh_idx_and_hit.first;
if (mesh_id == -1)
return;
const Vec3f hit_pos = m_last_mesh_idx_and_hit.second;
const Selection& selection = m_parent.get_selection();
const ModelObject* mo = m_c->selection_info()->model_object();
const ModelVolume* mv = mo->volumes[mesh_id];
const ModelInstance* mi = mo->instances[selection.get_instance_idx()];
const Transform3d instance_matrix = mi->get_transformation().get_matrix() * mv->get_matrix();
const Transform3d instance_scaling_matrix_inverse = Geometry::Transformation(instance_matrix).get_matrix(true, true, false, true).inverse();
const bool is_left_handed = Geometry::Transformation(instance_matrix).is_left_handed();
glsafe(::glPushMatrix());
glsafe(::glMultMatrixd(instance_matrix.data()));
// Inverse matrix of the instance scaling is applied so that the mark does not scale with the object.
glsafe(::glTranslatef(hit_pos(0), hit_pos(1), hit_pos(2)));
glsafe(::glMultMatrixd(instance_scaling_matrix_inverse.data()));
glsafe(::glScaled(m_cursor_radius, m_cursor_radius, m_cursor_radius));
if (is_left_handed)
glFrontFace(GL_CW);
float render_color[4] = { 0.f, 0.f, 0.f, 0.15f };
if (m_button_down == Button::Left)
render_color[2] = 1.f;
else // right
render_color[0] = 1.f;
glsafe(::glColor4fv(render_color));
m_vbo_sphere.render();
if (is_left_handed)
glFrontFace(GL_CCW);
glsafe(::glPopMatrix());
}
bool GLGizmoPainterBase::is_mesh_point_clipped(const Vec3d& point) const bool GLGizmoPainterBase::is_mesh_point_clipped(const Vec3d& point) const
{ {
@ -354,8 +410,9 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
assert(mesh_id < int(m_triangle_selectors.size())); assert(mesh_id < int(m_triangle_selectors.size()));
m_triangle_selectors[mesh_id]->select_patch(closest_hit, closest_facet, camera_pos, m_triangle_selectors[mesh_id]->select_patch(closest_hit, closest_facet, camera_pos,
dir, limit, new_state); dir, limit, m_cursor_type, new_state);
m_last_mouse_position = mouse_position; m_last_mouse_position = mouse_position;
m_last_mesh_idx_and_hit = {mesh_id, closest_hit};
} }
return true; return true;
@ -392,6 +449,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
m_button_down = Button::None; m_button_down = Button::None;
m_last_mouse_position = Vec2d::Zero(); m_last_mouse_position = Vec2d::Zero();
m_last_mesh_idx_and_hit = {-1, Vec3f::Zero()};
return true; return true;
} }

View File

@ -67,10 +67,13 @@ public:
protected: protected:
void render_triangles(const Selection& selection) const; void render_triangles(const Selection& selection) const;
void render_cursor() const;
void render_cursor_circle() const; void render_cursor_circle() const;
void render_cursor_sphere() const;
virtual void update_model_object() const = 0; virtual void update_model_object() const = 0;
virtual void update_from_model_object() = 0; virtual void update_from_model_object() = 0;
void activate_internal_undo_redo_stack(bool activate); void activate_internal_undo_redo_stack(bool activate);
void set_cursor_type(TriangleSelector::CursorType);
float m_cursor_radius = 2.f; float m_cursor_radius = 2.f;
static constexpr float CursorRadiusMin = 0.4f; // cannot be zero static constexpr float CursorRadiusMin = 0.4f; // cannot be zero
@ -80,16 +83,20 @@ protected:
// For each model-part volume, store status and division of the triangles. // For each model-part volume, store status and division of the triangles.
std::vector<std::unique_ptr<TriangleSelectorGUI>> m_triangle_selectors; std::vector<std::unique_ptr<TriangleSelectorGUI>> m_triangle_selectors;
TriangleSelector::CursorType m_cursor_type = TriangleSelector::SPHERE;
private: private:
bool is_mesh_point_clipped(const Vec3d& point) const; bool is_mesh_point_clipped(const Vec3d& point) const;
float m_clipping_plane_distance = 0.f; float m_clipping_plane_distance = 0.f;
std::unique_ptr<ClippingPlane> m_clipping_plane; std::unique_ptr<ClippingPlane> m_clipping_plane;
GLIndexedVertexArray m_vbo_sphere;
bool m_internal_stack_active = false; bool m_internal_stack_active = false;
bool m_schedule_update = false; bool m_schedule_update = false;
Vec2d m_last_mouse_position = Vec2d::Zero(); Vec2d m_last_mouse_position = Vec2d::Zero();
std::pair<int, Vec3f> m_last_mesh_idx_and_hit = {-1, Vec3f::Zero()};
enum class Button { enum class Button {
None, None,

View File

@ -25,6 +25,7 @@ bool GLGizmoSeam::on_init()
m_desc["clipping_of_view"] = _L("Clipping of view") + ": "; m_desc["clipping_of_view"] = _L("Clipping of view") + ": ";
m_desc["reset_direction"] = _L("Reset direction"); m_desc["reset_direction"] = _L("Reset direction");
m_desc["cursor_size"] = _L("Cursor size") + ": "; m_desc["cursor_size"] = _L("Cursor size") + ": ";
m_desc["cursor_type"] = _L("Cursor size") + ": ";
m_desc["enforce_caption"] = _L("Left mouse button") + ": "; m_desc["enforce_caption"] = _L("Left mouse button") + ": ";
m_desc["enforce"] = _L("Enforce seam"); m_desc["enforce"] = _L("Enforce seam");
m_desc["block_caption"] = _L("Right mouse button") + " "; m_desc["block_caption"] = _L("Right mouse button") + " ";
@ -55,7 +56,7 @@ void GLGizmoSeam::on_render() const
render_triangles(selection); render_triangles(selection);
m_c->object_clipper()->render_cut(); m_c->object_clipper()->render_cut();
render_cursor_circle(); render_cursor();
glsafe(::glDisable(GL_BLEND)); glsafe(::glDisable(GL_BLEND));
} }
@ -134,6 +135,23 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
ImGui::EndTooltip(); ImGui::EndTooltip();
} }
m_imgui->text(m_desc.at("cursor_type"));
ImGui::SameLine(/*clipping_slider_left*/);
//ImGui::PushItemWidth(window_width - clipping_slider_left);
int selection = int(m_cursor_type);
m_imgui->combo(" ", {"Circle", "Sphere"}, selection);
m_cursor_type = TriangleSelector::CursorType(selection);
/*if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted(_L("Alt + Mouse wheel").ToUTF8().data());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}*/
ImGui::Separator(); ImGui::Separator();
if (m_c->object_clipper()->get_position() == 0.f) if (m_c->object_clipper()->get_position() == 0.f)
m_imgui->text(m_desc.at("clipping_of_view")); m_imgui->text(m_desc.at("clipping_of_view"));