Cut: experiment with selecting parts:
Instead of clicking on contours, the user would click on the object itself. Right mouse button is used currently. Many loose ends ! Really just an experiment.
This commit is contained in:
parent
1c4d43b3a4
commit
e5b66f125f
@ -299,8 +299,8 @@ bool GLGizmoCut3D::on_mouse(const wxMouseEvent &mouse_event)
|
||||
if (m_was_contour_selected) {
|
||||
// Following would inform the clipper about the mouse click, so it can
|
||||
// toggle the respective contour as disabled.
|
||||
m_c->object_clipper()->pass_mouse_click(pos_world);
|
||||
process_contours();
|
||||
//m_c->object_clipper()->pass_mouse_click(pos_world);
|
||||
//process_contours();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -309,7 +309,7 @@ bool GLGizmoCut3D::on_mouse(const wxMouseEvent &mouse_event)
|
||||
flip_cut_plane();
|
||||
}
|
||||
|
||||
if (!m_cut_by_contour_glmodels.empty())
|
||||
if (m_part_selection.valid)
|
||||
m_parent.toggle_model_objects_visibility(false);
|
||||
return true;
|
||||
}
|
||||
@ -351,6 +351,14 @@ bool GLGizmoCut3D::on_mouse(const wxMouseEvent &mouse_event)
|
||||
return true;
|
||||
}
|
||||
else if (mouse_event.RightDown()) {
|
||||
if (! m_connectors_editing) {
|
||||
// Check the internal part raycasters.
|
||||
if (! m_part_selection.valid)
|
||||
process_contours();
|
||||
m_part_selection.toggle_selection(mouse_pos);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_parent.get_selection().get_object_idx() != -1 &&
|
||||
gizmo_event(SLAGizmoEventType::RightDown, mouse_pos, false, false, false)) {
|
||||
// we need to set the following right up as processed to avoid showing
|
||||
@ -446,9 +454,6 @@ void GLGizmoCut3D::update_clipper()
|
||||
on_register_raycasters_for_picking();
|
||||
else
|
||||
update_raycasters_for_picking_transform();
|
||||
|
||||
if (!m_c->object_clipper()->has_disable_contour())
|
||||
reset_cut_by_contours();
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::set_center(const Vec3d& center, bool update_tbb /*=false*/)
|
||||
@ -1384,11 +1389,10 @@ void GLGizmoCut3D::render_clipper_cut()
|
||||
::glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::render_colored_parts()
|
||||
void GLGizmoCut3D::PartSelection::render(const Vec3d* normal)
|
||||
{
|
||||
if (m_cut_by_contour_glmodels.empty())
|
||||
if (! valid)
|
||||
return;
|
||||
assert(m_cut_by_contour_objects[0]->volumes.size() == m_cut_by_contour_glmodels.size());
|
||||
|
||||
if (GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light")) {
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
@ -1396,19 +1400,44 @@ void GLGizmoCut3D::render_colored_parts()
|
||||
shader->start_using();
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
|
||||
const Vec3d inst_offset = m_cut_by_contour_objects[0]->instances[0]->get_offset();
|
||||
// FIXME: Cache the transforms.
|
||||
|
||||
const Vec3d inst_offset = model_object->instances[0]->get_offset();
|
||||
const Transform3d view_inst_matrix= camera.get_view_matrix() * translation_transform(inst_offset);
|
||||
|
||||
for (size_t id = 0; id < m_cut_by_contour_glmodels.size(); id++) {
|
||||
const Vec3d volume_offset = m_cut_by_contour_objects[0]->volumes[id]->get_offset();
|
||||
for (size_t id=0; id<parts.size(); ++id) {
|
||||
if (normal && camera.get_dir_forward().dot(*normal) < 0 && parts[id].selected)
|
||||
continue;
|
||||
const Vec3d volume_offset = model_object->volumes[id]->get_offset();
|
||||
shader->set_uniform("view_model_matrix", view_inst_matrix * translation_transform(volume_offset));
|
||||
m_cut_by_contour_glmodels[id].render();
|
||||
//parts[id].glmodel.set_color(parts[id].selected ? ColorRGBA(1.f, 0.f, 0.f, 1.f) : ColorRGBA(0.f, 1.f, 0.f, 1.f));
|
||||
parts[id].glmodel.set_color(parts[id].selected ? UPPER_PART_COLOR : LOWER_PART_COLOR);
|
||||
parts[id].glmodel.render();
|
||||
}
|
||||
|
||||
shader->stop_using();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLGizmoCut3D::PartSelection::toggle_selection(const Vec2d& mouse_pos)
|
||||
{
|
||||
// FIXME: Cache the transforms.
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
|
||||
Vec3f pos;
|
||||
Vec3f normal;
|
||||
|
||||
for (size_t id=0; id<parts.size(); ++id) {
|
||||
const Vec3d volume_offset = model_object->volumes[id]->get_offset();
|
||||
Transform3d tr = model_object->instances.front()->get_matrix() * model_object->volumes[id]->get_matrix();
|
||||
if (parts[id].raycaster.unproject_on_mesh(mouse_pos, tr, camera, pos, normal)) {
|
||||
parts[id].selected = ! parts[id].selected;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::on_render()
|
||||
{
|
||||
if (m_state == On) {
|
||||
@ -1426,7 +1455,9 @@ void GLGizmoCut3D::on_render()
|
||||
render_connectors();
|
||||
|
||||
if (!m_connectors_editing)
|
||||
render_colored_parts();
|
||||
m_part_selection.render();
|
||||
else
|
||||
m_part_selection.render(&m_cut_normal);
|
||||
|
||||
render_clipper_cut();
|
||||
|
||||
@ -1679,60 +1710,68 @@ void GLGizmoCut3D::flip_cut_plane()
|
||||
update_clipper();
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::reset_cut_by_contours()
|
||||
|
||||
GLGizmoCut3D::PartSelection::PartSelection(ModelObject* mo, const Vec3d& center, const Vec3d& normal)
|
||||
{
|
||||
if (!m_cut_by_contour_objects.empty()) {
|
||||
m_cut_by_contour_objects.clear();
|
||||
m_cut_by_contour_glmodels.clear();
|
||||
m_disabled_contours.clear();
|
||||
model_object = mo; // FIXME: Ownership.
|
||||
|
||||
m_parent.toggle_model_objects_visibility(true);
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::process_contours()
|
||||
{
|
||||
reset_cut_by_contours();
|
||||
|
||||
if (!m_c->object_clipper()->has_disable_contour())
|
||||
return;
|
||||
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const ModelObjectPtrs& model_objects = selection.get_model()->objects;
|
||||
|
||||
wxBusyCursor wait;
|
||||
|
||||
const int instance_idx = selection.get_instance_idx();
|
||||
const int object_idx = selection.get_object_idx();
|
||||
|
||||
m_cut_by_contour_objects = model_objects[object_idx]->cut(instance_idx, get_cut_matrix(selection),
|
||||
ModelObjectCutAttribute::KeepUpper |
|
||||
ModelObjectCutAttribute::KeepLower |
|
||||
ModelObjectCutAttribute::KeepAsParts |
|
||||
ModelObjectCutAttribute::InvalidateCutInfo);
|
||||
|
||||
assert(m_cut_by_contour_objects.size() == 1);
|
||||
|
||||
const ModelVolumePtrs& volumes = m_cut_by_contour_objects[0]->volumes;
|
||||
const ModelVolumePtrs& volumes = mo->volumes;
|
||||
|
||||
// split to parts
|
||||
for (int id = int(volumes.size())-1; id >= 0; id--)
|
||||
if (volumes[id]->is_splittable())
|
||||
volumes[id]->split(1);
|
||||
|
||||
m_cut_by_contour_glmodels.reserve(volumes.size());
|
||||
parts.clear();
|
||||
for (const ModelVolume* volume : volumes) {
|
||||
assert(volume != nullptr);
|
||||
parts.emplace_back(Part{GLModel(), MeshRaycaster(volume->mesh()), true});
|
||||
parts.back().glmodel.set_color({ 0.f, 0.f, 1.f, 1.f });
|
||||
parts.back().glmodel.init_from(volume->mesh());
|
||||
|
||||
GLModel glmodel;
|
||||
// any condition to test
|
||||
if (volume->name.find("_A") != std::string::npos)
|
||||
glmodel.set_color({ 0.5f, 0.9f, 0.9f, 0.5f }); // glmodel.set_color(UPPER_PART_COLOR);
|
||||
else
|
||||
glmodel.set_color({ 0.9f, 0.5f, 0.9f, 0.5f }); // glmodel.set_color(LOWER_PART_COLOR);
|
||||
|
||||
m_cut_by_contour_glmodels.push_back(glmodel);
|
||||
// Now check whether this part is below or above the plane.
|
||||
Transform3d tr = (model_object->instances.front()->get_matrix() * volume->get_matrix()).inverse();
|
||||
Vec3f pos = (tr * center).cast<float>();
|
||||
Vec3f norm = (tr.linear().inverse().transpose() * normal).cast<float>();
|
||||
for (const Vec3f& v : volume->mesh().its.vertices) {
|
||||
double p = (v - pos).dot(norm);
|
||||
if (std::abs(p) > EPSILON) {
|
||||
parts.back().selected = p > 0.;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
valid = true;
|
||||
}
|
||||
|
||||
|
||||
void GLGizmoCut3D::reset_cut_by_contours()
|
||||
{
|
||||
m_part_selection = PartSelection();
|
||||
m_parent.toggle_model_objects_visibility(true);
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::process_contours()
|
||||
{
|
||||
reset_cut_by_contours();
|
||||
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const ModelObjectPtrs& model_objects = selection.get_model()->objects;
|
||||
|
||||
wxBusyCursor wait;
|
||||
const int instance_idx = selection.get_instance_idx();
|
||||
const int object_idx = selection.get_object_idx();
|
||||
|
||||
ModelObjectPtrs moptrs = model_objects[object_idx]->cut(instance_idx, get_cut_matrix(selection),
|
||||
ModelObjectCutAttribute::KeepUpper |
|
||||
ModelObjectCutAttribute::KeepLower |
|
||||
ModelObjectCutAttribute::KeepAsParts |
|
||||
ModelObjectCutAttribute::InvalidateCutInfo);
|
||||
|
||||
assert(moptrs.size() == 1);
|
||||
m_part_selection = PartSelection(moptrs.front(), m_plane_center, m_cut_normal);
|
||||
m_parent.toggle_model_objects_visibility(false);
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::render_flip_plane_button(bool disable_pred /*=false*/)
|
||||
@ -2061,7 +2100,7 @@ void GLGizmoCut3D::on_render_input_window(float x, float y, float bottom_limit)
|
||||
bool GLGizmoCut3D::is_outside_of_cut_contour(size_t idx, const CutConnectors& connectors, const Vec3d cur_pos)
|
||||
{
|
||||
// check if connector pos is out of clipping plane
|
||||
if (m_c->object_clipper() && !m_c->object_clipper()->is_projection_inside_cut(cur_pos, true)) {
|
||||
if (m_c->object_clipper() && m_c->object_clipper()->is_projection_inside_cut(cur_pos) == -1) {
|
||||
m_info_stats.outside_cut_contour++;
|
||||
return true;
|
||||
}
|
||||
@ -2087,7 +2126,7 @@ bool GLGizmoCut3D::is_outside_of_cut_contour(size_t idx, const CutConnectors& co
|
||||
its_transform(mesh, translation_transform(cur_pos) * m_rotation_m);
|
||||
|
||||
for (auto vertex : vertices) {
|
||||
if (m_c->object_clipper() && !m_c->object_clipper()->is_projection_inside_cut(vertex.cast<double>(), true)) {
|
||||
if (m_c->object_clipper() && m_c->object_clipper()->is_projection_inside_cut(vertex.cast<double>()) == -1) {
|
||||
m_info_stats.outside_cut_contour++;
|
||||
return true;
|
||||
}
|
||||
@ -2327,7 +2366,7 @@ bool GLGizmoCut3D::unproject_on_cut_plane(const Vec2d& mouse_position, Vec3d& po
|
||||
} else
|
||||
return false;
|
||||
|
||||
if (! m_c->object_clipper()->is_projection_inside_cut(hit, respect_disabled_contour))
|
||||
if (m_c->object_clipper()->is_projection_inside_cut(hit) == -1)
|
||||
return false;
|
||||
|
||||
// recalculate hit to object's local position
|
||||
@ -2555,20 +2594,8 @@ bool GLGizmoCut3D::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_posi
|
||||
if (!m_keep_upper || !m_keep_lower)
|
||||
return false;
|
||||
|
||||
if (!m_connectors_editing) {
|
||||
if (0 && action == SLAGizmoEventType::LeftDown) {
|
||||
// disable / enable current contour
|
||||
Vec3d pos;
|
||||
Vec3d pos_world;
|
||||
if (unproject_on_cut_plane(mouse_position.cast<double>(), pos, pos_world)) {
|
||||
// Following would inform the clipper about the mouse click, so it can
|
||||
// toggle the respective contour as disabled.
|
||||
m_c->object_clipper()->pass_mouse_click(pos_world);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!m_connectors_editing)
|
||||
return false;
|
||||
}
|
||||
|
||||
CutConnectors& connectors = m_c->selection_info()->model_object()->cut_connectors;
|
||||
|
||||
|
@ -137,10 +137,25 @@ class GLGizmoCut3D : public GLGizmoBase
|
||||
bool m_was_cut_plane_dragged { false };
|
||||
bool m_was_contour_selected { false };
|
||||
|
||||
std::vector<GLModel> m_cut_by_contour_glmodels;
|
||||
ModelObjectPtrs m_cut_by_contour_objects;
|
||||
// attributes for disabled contours <pos, norm>
|
||||
std::vector<std::pair<Vec3d, Vec3d>> m_disabled_contours;
|
||||
struct PartSelection {
|
||||
PartSelection() = default;
|
||||
PartSelection(ModelObject* mo, const Vec3d& center, const Vec3d& normal);
|
||||
|
||||
void render(const Vec3d* normal = nullptr);
|
||||
void toggle_selection(const Vec2d& mouse_pos);
|
||||
|
||||
struct Part {
|
||||
GLModel glmodel;
|
||||
MeshRaycaster raycaster;
|
||||
bool selected;
|
||||
bool upper;
|
||||
};
|
||||
ModelObject* model_object; // FIXME: Ownership !
|
||||
std::vector<Part> parts;
|
||||
bool valid = false;
|
||||
};
|
||||
|
||||
PartSelection m_part_selection;
|
||||
|
||||
bool m_show_shortcuts{ false };
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts;
|
||||
@ -299,7 +314,6 @@ private:
|
||||
void init_picking_models();
|
||||
void init_rendering_items();
|
||||
void render_clipper_cut();
|
||||
void render_colored_parts();
|
||||
void clear_selection();
|
||||
void reset_connectors();
|
||||
void init_connector_shapes();
|
||||
|
@ -388,10 +388,26 @@ void ObjectClipper::render_cut() const
|
||||
}
|
||||
}
|
||||
|
||||
bool ObjectClipper::is_projection_inside_cut(const Vec3d& point, bool respect_disabled_contour) const
|
||||
|
||||
int ObjectClipper::get_number_of_contours() const
|
||||
{
|
||||
return m_clp_ratio != 0. && std::any_of(m_clippers.begin(), m_clippers.end(),
|
||||
[point, respect_disabled_contour](const auto& cl) { return cl.first->is_projection_inside_cut(point, respect_disabled_contour); });
|
||||
int sum = 0;
|
||||
for (const auto& [clipper, trafo] : m_clippers)
|
||||
sum += clipper->get_number_of_contours();
|
||||
return sum;
|
||||
}
|
||||
|
||||
int ObjectClipper::is_projection_inside_cut(const Vec3d& point) const
|
||||
{
|
||||
if (m_clp_ratio == 0.)
|
||||
return -1;
|
||||
int idx_offset = 0;
|
||||
for (const auto& [clipper, trafo] : m_clippers) {
|
||||
if (int idx = clipper->is_projection_inside_cut(point); idx != -1)
|
||||
return idx_offset + idx;
|
||||
idx_offset += clipper->get_number_of_contours();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool ObjectClipper::has_valid_contour() const
|
||||
@ -399,10 +415,6 @@ bool ObjectClipper::has_valid_contour() const
|
||||
return m_clp_ratio != 0. && std::any_of(m_clippers.begin(), m_clippers.end(), [](const auto& cl) { return cl.first->has_valid_contour(); });
|
||||
}
|
||||
|
||||
bool ObjectClipper::has_disable_contour() const
|
||||
{
|
||||
return m_clp_ratio != 0. && std::any_of(m_clippers.begin(), m_clippers.end(), [](const auto& cl) { return cl.first->has_disable_contour(); });
|
||||
}
|
||||
|
||||
void ObjectClipper::set_position_by_ratio(double pos, bool keep_normal)
|
||||
{
|
||||
@ -442,16 +454,6 @@ void ObjectClipper::set_behavior(bool hide_clipped, bool fill_cut, double contou
|
||||
clipper.first->set_behaviour(fill_cut, contour_width);
|
||||
}
|
||||
|
||||
void ObjectClipper::pass_mouse_click(const Vec3d& pt)
|
||||
{
|
||||
for (auto& clipper : m_clippers)
|
||||
clipper.first->pass_mouse_click(pt);
|
||||
}
|
||||
|
||||
std::vector<Vec3d> ObjectClipper::get_disabled_contours() const
|
||||
{
|
||||
return std::vector<Vec3d>();
|
||||
}
|
||||
|
||||
void SupportsClipper::on_update()
|
||||
{
|
||||
|
@ -247,12 +247,10 @@ public:
|
||||
void set_range_and_pos(const Vec3d& cpl_normal, double cpl_offset, double pos);
|
||||
void set_behavior(bool hide_clipped, bool fill_cut, double contour_width);
|
||||
|
||||
void pass_mouse_click(const Vec3d& pt);
|
||||
std::vector<Vec3d> get_disabled_contours() const;
|
||||
int get_number_of_contours() const;
|
||||
|
||||
bool is_projection_inside_cut(const Vec3d& point_in, bool respect_disabled_contour) const;
|
||||
int is_projection_inside_cut(const Vec3d& point_in) const;
|
||||
bool has_valid_contour() const;
|
||||
bool has_disable_contour() const;
|
||||
|
||||
|
||||
protected:
|
||||
|
@ -146,18 +146,19 @@ void MeshClipper::render_contour(const ColorRGBA& color)
|
||||
curr_shader->start_using();
|
||||
}
|
||||
|
||||
bool MeshClipper::is_projection_inside_cut(const Vec3d& point_in, bool respect_disabled_contour) const
|
||||
int MeshClipper::is_projection_inside_cut(const Vec3d& point_in) const
|
||||
{
|
||||
if (!m_result || m_result->cut_islands.empty())
|
||||
return false;
|
||||
return -1;
|
||||
Vec3d point = m_result->trafo.inverse() * point_in;
|
||||
Point pt_2d = Point::new_scale(Vec2d(point.x(), point.y()));
|
||||
|
||||
for (const CutIsland& isl : m_result->cut_islands) {
|
||||
for (int i=0; i<int(m_result->cut_islands.size()); ++i) {
|
||||
const CutIsland& isl = m_result->cut_islands[i];
|
||||
if (isl.expoly_bb.contains(pt_2d) && isl.expoly.contains(pt_2d))
|
||||
return respect_disabled_contour ? !isl.disabled : true;
|
||||
return i; // TODO: handle intersecting contours
|
||||
}
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool MeshClipper::has_valid_contour() const
|
||||
@ -165,23 +166,6 @@ bool MeshClipper::has_valid_contour() const
|
||||
return m_result && std::any_of(m_result->cut_islands.begin(), m_result->cut_islands.end(), [](const CutIsland& isl) { return !isl.expoly.empty(); });
|
||||
}
|
||||
|
||||
bool MeshClipper::has_disable_contour() const
|
||||
{
|
||||
return m_result && std::any_of(m_result->cut_islands.begin(), m_result->cut_islands.end(), [](const CutIsland& isl) { return isl.disabled; });
|
||||
}
|
||||
|
||||
void MeshClipper::pass_mouse_click(const Vec3d& point_in)
|
||||
{
|
||||
if (! m_result || m_result->cut_islands.empty())
|
||||
return;
|
||||
Vec3d point = m_result->trafo.inverse() * point_in;
|
||||
Point pt_2d = Point::new_scale(Vec2d(point.x(), point.y()));
|
||||
|
||||
for (CutIsland& isl : m_result->cut_islands) {
|
||||
if (isl.expoly_bb.contains(pt_2d) && isl.expoly.contains(pt_2d))
|
||||
isl.disabled = ! isl.disabled;
|
||||
}
|
||||
}
|
||||
|
||||
void MeshClipper::recalculate_triangles()
|
||||
{
|
||||
|
@ -118,11 +118,10 @@ public:
|
||||
void render_cut(const ColorRGBA& color);
|
||||
void render_contour(const ColorRGBA& color);
|
||||
|
||||
void pass_mouse_click(const Vec3d& pt);
|
||||
|
||||
bool is_projection_inside_cut(const Vec3d& point, bool respect_disabled_contour) const;
|
||||
// Returns index of the contour which was clicked, -1 otherwise.
|
||||
int is_projection_inside_cut(const Vec3d& point) const;
|
||||
bool has_valid_contour() const;
|
||||
bool has_disable_contour() const;
|
||||
int get_number_of_contours() const { return m_result ? m_result->cut_islands.size() : 0; }
|
||||
|
||||
private:
|
||||
void recalculate_triangles();
|
||||
|
Loading…
Reference in New Issue
Block a user