Measuring: allow to select single parts of a multipart object while Gizmo Measure is active

This commit is contained in:
enricoturri1966 2022-08-22 08:52:02 +02:00
parent 474624f89e
commit 9d81568bf9
4 changed files with 105 additions and 70 deletions

View File

@ -64,12 +64,14 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event)
void GLGizmoMeasure::data_changed()
{
const Selection & selection = m_parent.get_selection();
const ModelObject *model_object = nullptr;
const ModelObject* model_object = nullptr;
const ModelVolume* model_volume = nullptr;
if (selection.is_single_full_instance() ||
selection.is_from_single_object() ) {
model_object = selection.get_model()->objects[selection.get_object_idx()];
}
if (model_object != m_old_model_object)
model_volume = model_object->volumes[selection.get_first_volume()->volume_idx()];
}
if (model_object != m_old_model_object || model_volume != m_old_model_volume)
update_if_needed();
}
@ -109,6 +111,10 @@ bool GLGizmoMeasure::on_is_activable() const
void GLGizmoMeasure::on_render()
{
// do not render if the user is panning/rotating the 3d scene
if (m_parent.is_mouse_dragging())
return;
const Selection& selection = m_parent.get_selection();
GLShaderProgram* shader = wxGetApp().get_shader("flat");
@ -126,33 +132,34 @@ void GLGizmoMeasure::on_render()
#endif // ENABLE_GL_CORE_PROFILE
glsafe(::glLineWidth(2.f));
if (selection.is_single_full_instance()) {
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
if (selection.is_single_volume() || selection.is_single_volume_instance()) {
const Transform3d& model_matrix = selection.get_first_volume()->world_matrix();
const Camera& camera = wxGetApp().plater()->get_camera();
const Transform3d view_model_matrix = camera.get_view_matrix() *
Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m;
Geometry::assemble_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * model_matrix;
shader->set_uniform("view_model_matrix", view_model_matrix);
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
update_if_needed();
m_imgui->begin(std::string("DEBUG"));
m_imgui->checkbox(wxString("Show all features"), m_show_all);
m_imgui->checkbox(wxString("Show all planes"), m_show_planes);
Vec3f pos;
Vec3f normal;
size_t facet_idx;
m_c->raycaster()->raycasters().front()->unproject_on_mesh(Vec2d(m_mouse_pos_x, m_mouse_pos_y), m, camera, pos, normal, nullptr, &facet_idx);
m_c->raycaster()->raycasters().front()->unproject_on_mesh(Vec2d(m_mouse_pos_x, m_mouse_pos_y), model_matrix, camera, pos, normal, nullptr, &facet_idx);
#define ENABLE_DEBUG_DIALOG 0
#if ENABLE_DEBUG_DIALOG
m_imgui->begin(std::string("DEBUG"));
m_imgui->checkbox(wxString("Show all features"), m_show_all);
m_imgui->checkbox(wxString("Show all planes"), m_show_planes);
ImGui::Separator();
m_imgui->text(std::string("face_idx: ") + std::to_string(facet_idx));
m_imgui->text(std::string("pos_x: ") + std::to_string(pos.x()));
m_imgui->text(std::string("pos_y: ") + std::to_string(pos.y()));
m_imgui->text(std::string("pos_z: ") + std::to_string(pos.z()));
m_imgui->end();
#endif // ENABLE_DEBUG_DIALOG
std::vector<Measure::SurfaceFeature> features;
if (m_show_all) {
@ -230,8 +237,6 @@ void GLGizmoMeasure::on_render()
if (m_show_planes)
for (const auto& glmodel : m_plane_models)
glmodel->render();
m_imgui->end();
}
glsafe(::glEnable(GL_CULL_FACE));
@ -251,57 +256,70 @@ void GLGizmoMeasure::on_render()
void GLGizmoMeasure::update_if_needed()
{
auto do_update = [this](const ModelObject* object, const ModelVolume* volume) {
const indexed_triangle_set& its = (volume != nullptr) ? volume->mesh().its : object->volumes.front()->mesh().its;
m_measuring.reset(new Measure::Measuring(its));
m_plane_models.clear();
const std::vector<std::vector<int>> planes_triangles = m_measuring->get_planes_triangle_indices();
for (const std::vector<int>& triangle_indices : planes_triangles) {
m_plane_models.emplace_back(std::unique_ptr<GLModel>(new GLModel()));
GUI::GLModel::Geometry init_data;
init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GUI::GLModel::Geometry::EVertexLayout::P3 };
init_data.color = ColorRGBA(0.9f, 0.9f, 0.9f, 0.5f);
int i = 0;
for (int idx : triangle_indices) {
init_data.add_vertex(its.vertices[its.indices[idx][0]]);
init_data.add_vertex(its.vertices[its.indices[idx][1]]);
init_data.add_vertex(its.vertices[its.indices[idx][2]]);
init_data.add_triangle(i, i + 1, i + 2);
i += 3;
}
m_plane_models.back()->init_from(std::move(init_data));
}
// Let's save what we calculated it from:
m_volumes_matrices.clear();
m_volumes_types.clear();
m_first_instance_scale = Vec3d::Ones();
m_first_instance_mirror = Vec3d::Ones();
if (object != nullptr) {
for (const ModelVolume* vol : object->volumes) {
m_volumes_matrices.push_back(vol->get_matrix());
m_volumes_types.push_back(vol->type());
}
m_first_instance_scale = object->instances.front()->get_scaling_factor();
m_first_instance_mirror = object->instances.front()->get_mirror();
}
m_old_model_object = object;
m_old_model_volume = volume;
};
const ModelObject* mo = m_c->selection_info()->model_object();
if (m_state != On || ! mo || mo->instances.empty())
const ModelVolume* mv = m_c->selection_info()->model_volume();
if (m_state != On || (mo == nullptr && mv == nullptr))
return;
if (! m_measuring || mo != m_old_model_object
|| mo->volumes.size() != m_volumes_matrices.size())
goto UPDATE;
if (mo == nullptr)
mo = mv->get_object();
if (mo->instances.empty())
return;
if (!m_measuring || mo != m_old_model_object || mv != m_old_model_volume || mo->volumes.size() != m_volumes_matrices.size())
do_update(mo, mv);
// We want to recalculate when the scale changes - some planes could (dis)appear.
if (! mo->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale)
|| ! mo->instances.front()->get_mirror().isApprox(m_first_instance_mirror))
goto UPDATE;
if (!mo->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale) ||
!mo->instances.front()->get_mirror().isApprox(m_first_instance_mirror))
do_update(mo, mv);
for (unsigned int i=0; i < mo->volumes.size(); ++i)
if (! mo->volumes[i]->get_matrix().isApprox(m_volumes_matrices[i])
|| mo->volumes[i]->type() != m_volumes_types[i])
goto UPDATE;
return;
UPDATE:
const indexed_triangle_set& its = mo->volumes.front()->mesh().its;
m_measuring.reset(new Measure::Measuring(its));
m_plane_models.clear();
const std::vector<std::vector<int>> planes_triangles = m_measuring->get_planes_triangle_indices();
for (const std::vector<int>& triangle_indices : planes_triangles) {
m_plane_models.emplace_back(std::unique_ptr<GLModel>(new GLModel()));
GUI::GLModel::Geometry init_data;
init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GUI::GLModel::Geometry::EVertexLayout::P3 };
init_data.color = ColorRGBA(0.9f, 0.9f, 0.9f, 0.5f);
int i = 0;
for (int idx : triangle_indices) {
init_data.add_vertex(its.vertices[its.indices[idx][0]]);
init_data.add_vertex(its.vertices[its.indices[idx][1]]);
init_data.add_vertex(its.vertices[its.indices[idx][2]]);
init_data.add_triangle(i, i+1, i+2);
i+=3;
for (unsigned int i = 0; i < mo->volumes.size(); ++i) {
if (!mo->volumes[i]->get_matrix().isApprox(m_volumes_matrices[i]) ||
mo->volumes[i]->type() != m_volumes_types[i]) {
do_update(mo, mv);
break;
}
m_plane_models.back()->init_from(std::move(init_data));
}
// Let's save what we calculated it from:
m_volumes_matrices.clear();
m_volumes_types.clear();
for (const ModelVolume* vol : mo->volumes) {
m_volumes_matrices.push_back(vol->get_matrix());
m_volumes_types.push_back(vol->type());
}
m_first_instance_scale = mo->instances.front()->get_scaling_factor();
m_first_instance_mirror = mo->instances.front()->get_mirror();
m_old_model_object = mo;
}
} // namespace GUI

View File

@ -14,6 +14,8 @@
namespace Slic3r {
class ModelVolume;
enum class ModelVolumeType : int;
namespace Measure { class Measuring; }
@ -35,12 +37,13 @@ private:
// This holds information to decide whether recalculation is necessary:
std::vector<Transform3d> m_volumes_matrices;
std::vector<ModelVolumeType> m_volumes_types;
Vec3d m_first_instance_scale;
Vec3d m_first_instance_mirror;
Vec3d m_first_instance_scale{ Vec3d::Ones() };
Vec3d m_first_instance_mirror{ Vec3d::Ones() };
bool m_mouse_left_down = false; // for detection left_up of this gizmo
bool m_planes_valid = false;
const ModelObject* m_old_model_object = nullptr;
const ModelVolume* m_old_model_volume = nullptr;
std::vector<const Transform3d*> instances_matrices;
int m_mouse_pos_x;

View File

@ -119,21 +119,25 @@ void SelectionInfo::on_update()
const Selection& selection = get_pool()->get_canvas()->get_selection();
if (selection.is_single_full_instance()) {
m_model_object = selection.get_model()->objects[selection.get_object_idx()];
m_model_volume = nullptr;
m_z_shift = selection.get_first_volume()->get_sla_shift_z();
}
else
else {
m_model_object = nullptr;
if (selection.is_single_volume())
m_model_volume = selection.get_model()->objects[selection.get_object_idx()]->volumes[selection.get_first_volume()->volume_idx()];
}
}
void SelectionInfo::on_release()
{
m_model_object = nullptr;
m_model_volume = nullptr;
}
int SelectionInfo::get_active_instance() const
{
const Selection& selection = get_pool()->get_canvas()->get_selection();
return selection.get_instance_idx();
return get_pool()->get_canvas()->get_selection().get_instance_idx();
}
@ -329,12 +333,18 @@ void Raycaster::on_update()
{
wxBusyCursor wait;
const ModelObject* mo = get_pool()->selection_info()->model_object();
const ModelVolume* mv = get_pool()->selection_info()->model_volume();
if (! mo)
if (mo == nullptr && mv == nullptr)
return;
std::vector<ModelVolume*> mvs;
if (mv != nullptr)
mvs.push_back(const_cast<ModelVolume*>(mv));
else
mvs = mo->volumes;
std::vector<const TriangleMesh*> meshes;
const std::vector<ModelVolume*>& mvs = mo->volumes;
if (mvs.size() == 1) {
assert(mvs.front()->is_model_part());
const HollowedMesh* hollowed_mesh_tracker = get_pool()->hollowed_mesh();
@ -342,9 +352,9 @@ void Raycaster::on_update()
meshes.push_back(hollowed_mesh_tracker->get_hollowed_mesh());
}
if (meshes.empty()) {
for (const ModelVolume* mv : mvs) {
if (mv->is_model_part())
meshes.push_back(&mv->mesh());
for (const ModelVolume* v : mvs) {
if (v->is_model_part())
meshes.push_back(&v->mesh());
}
}

View File

@ -10,7 +10,7 @@
namespace Slic3r {
class ModelObject;
class ModelVolume;
namespace GUI {
@ -153,7 +153,10 @@ public:
explicit SelectionInfo(CommonGizmosDataPool* cgdp)
: CommonGizmosDataBase(cgdp) {}
// Returns a non-null pointer if the selection is a single full instance
ModelObject* model_object() const { return m_model_object; }
// Returns a non-null pointer if the selection is a single volume
ModelVolume* model_volume() const { return m_model_volume; }
int get_active_instance() const;
float get_sla_shift() const { return m_z_shift; }
@ -163,6 +166,7 @@ protected:
private:
ModelObject* m_model_object = nullptr;
ModelVolume* m_model_volume = nullptr;
// int m_active_inst = -1;
float m_z_shift = 0.f;
};