mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-16 08:55:57 +08:00
Measuring: allow to select single parts of a multipart object while Gizmo Measure is active
This commit is contained in:
parent
474624f89e
commit
9d81568bf9
@ -64,12 +64,14 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event)
|
|||||||
void GLGizmoMeasure::data_changed()
|
void GLGizmoMeasure::data_changed()
|
||||||
{
|
{
|
||||||
const Selection & selection = m_parent.get_selection();
|
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() ||
|
if (selection.is_single_full_instance() ||
|
||||||
selection.is_from_single_object() ) {
|
selection.is_from_single_object() ) {
|
||||||
model_object = selection.get_model()->objects[selection.get_object_idx()];
|
model_object = selection.get_model()->objects[selection.get_object_idx()];
|
||||||
}
|
model_volume = model_object->volumes[selection.get_first_volume()->volume_idx()];
|
||||||
if (model_object != m_old_model_object)
|
}
|
||||||
|
if (model_object != m_old_model_object || model_volume != m_old_model_volume)
|
||||||
update_if_needed();
|
update_if_needed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,6 +111,10 @@ bool GLGizmoMeasure::on_is_activable() const
|
|||||||
|
|
||||||
void GLGizmoMeasure::on_render()
|
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();
|
const Selection& selection = m_parent.get_selection();
|
||||||
|
|
||||||
GLShaderProgram* shader = wxGetApp().get_shader("flat");
|
GLShaderProgram* shader = wxGetApp().get_shader("flat");
|
||||||
@ -126,33 +132,34 @@ void GLGizmoMeasure::on_render()
|
|||||||
#endif // ENABLE_GL_CORE_PROFILE
|
#endif // ENABLE_GL_CORE_PROFILE
|
||||||
glsafe(::glLineWidth(2.f));
|
glsafe(::glLineWidth(2.f));
|
||||||
|
|
||||||
if (selection.is_single_full_instance()) {
|
if (selection.is_single_volume() || selection.is_single_volume_instance()) {
|
||||||
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
|
const Transform3d& model_matrix = selection.get_first_volume()->world_matrix();
|
||||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||||
const Transform3d view_model_matrix = camera.get_view_matrix() *
|
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("view_model_matrix", view_model_matrix);
|
||||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||||
|
|
||||||
update_if_needed();
|
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 pos;
|
||||||
Vec3f normal;
|
Vec3f normal;
|
||||||
size_t facet_idx;
|
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();
|
ImGui::Separator();
|
||||||
m_imgui->text(std::string("face_idx: ") + std::to_string(facet_idx));
|
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_x: ") + std::to_string(pos.x()));
|
||||||
m_imgui->text(std::string("pos_y: ") + std::to_string(pos.y()));
|
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->text(std::string("pos_z: ") + std::to_string(pos.z()));
|
||||||
|
m_imgui->end();
|
||||||
|
#endif // ENABLE_DEBUG_DIALOG
|
||||||
|
|
||||||
std::vector<Measure::SurfaceFeature> features;
|
std::vector<Measure::SurfaceFeature> features;
|
||||||
if (m_show_all) {
|
if (m_show_all) {
|
||||||
@ -230,8 +237,6 @@ void GLGizmoMeasure::on_render()
|
|||||||
if (m_show_planes)
|
if (m_show_planes)
|
||||||
for (const auto& glmodel : m_plane_models)
|
for (const auto& glmodel : m_plane_models)
|
||||||
glmodel->render();
|
glmodel->render();
|
||||||
|
|
||||||
m_imgui->end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glsafe(::glEnable(GL_CULL_FACE));
|
glsafe(::glEnable(GL_CULL_FACE));
|
||||||
@ -251,57 +256,70 @@ void GLGizmoMeasure::on_render()
|
|||||||
|
|
||||||
void GLGizmoMeasure::update_if_needed()
|
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();
|
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;
|
return;
|
||||||
|
|
||||||
if (! m_measuring || mo != m_old_model_object
|
if (mo == nullptr)
|
||||||
|| mo->volumes.size() != m_volumes_matrices.size())
|
mo = mv->get_object();
|
||||||
goto UPDATE;
|
|
||||||
|
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.
|
// 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)
|
if (!mo->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale) ||
|
||||||
|| ! mo->instances.front()->get_mirror().isApprox(m_first_instance_mirror))
|
!mo->instances.front()->get_mirror().isApprox(m_first_instance_mirror))
|
||||||
goto UPDATE;
|
do_update(mo, mv);
|
||||||
|
|
||||||
for (unsigned int i=0; i < mo->volumes.size(); ++i)
|
for (unsigned int i = 0; i < mo->volumes.size(); ++i) {
|
||||||
if (! mo->volumes[i]->get_matrix().isApprox(m_volumes_matrices[i])
|
if (!mo->volumes[i]->get_matrix().isApprox(m_volumes_matrices[i]) ||
|
||||||
|| mo->volumes[i]->type() != m_volumes_types[i])
|
mo->volumes[i]->type() != m_volumes_types[i]) {
|
||||||
goto UPDATE;
|
do_update(mo, mv);
|
||||||
|
break;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
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
|
} // namespace GUI
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
class ModelVolume;
|
||||||
|
|
||||||
enum class ModelVolumeType : int;
|
enum class ModelVolumeType : int;
|
||||||
|
|
||||||
namespace Measure { class Measuring; }
|
namespace Measure { class Measuring; }
|
||||||
@ -35,12 +37,13 @@ private:
|
|||||||
// This holds information to decide whether recalculation is necessary:
|
// This holds information to decide whether recalculation is necessary:
|
||||||
std::vector<Transform3d> m_volumes_matrices;
|
std::vector<Transform3d> m_volumes_matrices;
|
||||||
std::vector<ModelVolumeType> m_volumes_types;
|
std::vector<ModelVolumeType> m_volumes_types;
|
||||||
Vec3d m_first_instance_scale;
|
Vec3d m_first_instance_scale{ Vec3d::Ones() };
|
||||||
Vec3d m_first_instance_mirror;
|
Vec3d m_first_instance_mirror{ Vec3d::Ones() };
|
||||||
|
|
||||||
bool m_mouse_left_down = false; // for detection left_up of this gizmo
|
bool m_mouse_left_down = false; // for detection left_up of this gizmo
|
||||||
bool m_planes_valid = false;
|
bool m_planes_valid = false;
|
||||||
const ModelObject* m_old_model_object = nullptr;
|
const ModelObject* m_old_model_object = nullptr;
|
||||||
|
const ModelVolume* m_old_model_volume = nullptr;
|
||||||
std::vector<const Transform3d*> instances_matrices;
|
std::vector<const Transform3d*> instances_matrices;
|
||||||
|
|
||||||
int m_mouse_pos_x;
|
int m_mouse_pos_x;
|
||||||
|
@ -119,21 +119,25 @@ void SelectionInfo::on_update()
|
|||||||
const Selection& selection = get_pool()->get_canvas()->get_selection();
|
const Selection& selection = get_pool()->get_canvas()->get_selection();
|
||||||
if (selection.is_single_full_instance()) {
|
if (selection.is_single_full_instance()) {
|
||||||
m_model_object = selection.get_model()->objects[selection.get_object_idx()];
|
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();
|
m_z_shift = selection.get_first_volume()->get_sla_shift_z();
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
m_model_object = nullptr;
|
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()
|
void SelectionInfo::on_release()
|
||||||
{
|
{
|
||||||
m_model_object = nullptr;
|
m_model_object = nullptr;
|
||||||
|
m_model_volume = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SelectionInfo::get_active_instance() const
|
int SelectionInfo::get_active_instance() const
|
||||||
{
|
{
|
||||||
const Selection& selection = get_pool()->get_canvas()->get_selection();
|
return get_pool()->get_canvas()->get_selection().get_instance_idx();
|
||||||
return selection.get_instance_idx();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -329,12 +333,18 @@ void Raycaster::on_update()
|
|||||||
{
|
{
|
||||||
wxBusyCursor wait;
|
wxBusyCursor wait;
|
||||||
const ModelObject* mo = get_pool()->selection_info()->model_object();
|
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;
|
return;
|
||||||
|
|
||||||
|
std::vector<ModelVolume*> mvs;
|
||||||
|
if (mv != nullptr)
|
||||||
|
mvs.push_back(const_cast<ModelVolume*>(mv));
|
||||||
|
else
|
||||||
|
mvs = mo->volumes;
|
||||||
|
|
||||||
std::vector<const TriangleMesh*> meshes;
|
std::vector<const TriangleMesh*> meshes;
|
||||||
const std::vector<ModelVolume*>& mvs = mo->volumes;
|
|
||||||
if (mvs.size() == 1) {
|
if (mvs.size() == 1) {
|
||||||
assert(mvs.front()->is_model_part());
|
assert(mvs.front()->is_model_part());
|
||||||
const HollowedMesh* hollowed_mesh_tracker = get_pool()->hollowed_mesh();
|
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());
|
meshes.push_back(hollowed_mesh_tracker->get_hollowed_mesh());
|
||||||
}
|
}
|
||||||
if (meshes.empty()) {
|
if (meshes.empty()) {
|
||||||
for (const ModelVolume* mv : mvs) {
|
for (const ModelVolume* v : mvs) {
|
||||||
if (mv->is_model_part())
|
if (v->is_model_part())
|
||||||
meshes.push_back(&mv->mesh());
|
meshes.push_back(&v->mesh());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
class ModelObject;
|
class ModelObject;
|
||||||
|
class ModelVolume;
|
||||||
|
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
@ -153,7 +153,10 @@ public:
|
|||||||
explicit SelectionInfo(CommonGizmosDataPool* cgdp)
|
explicit SelectionInfo(CommonGizmosDataPool* cgdp)
|
||||||
: CommonGizmosDataBase(cgdp) {}
|
: CommonGizmosDataBase(cgdp) {}
|
||||||
|
|
||||||
|
// Returns a non-null pointer if the selection is a single full instance
|
||||||
ModelObject* model_object() const { return m_model_object; }
|
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;
|
int get_active_instance() const;
|
||||||
float get_sla_shift() const { return m_z_shift; }
|
float get_sla_shift() const { return m_z_shift; }
|
||||||
|
|
||||||
@ -163,6 +166,7 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
ModelObject* m_model_object = nullptr;
|
ModelObject* m_model_object = nullptr;
|
||||||
|
ModelVolume* m_model_volume = nullptr;
|
||||||
// int m_active_inst = -1;
|
// int m_active_inst = -1;
|
||||||
float m_z_shift = 0.f;
|
float m_z_shift = 0.f;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user