mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-15 09:35:52 +08:00
CutGizmo: Implemented validation of groove size/position
This commit is contained in:
parent
ba25da571a
commit
4e74e4ecc0
@ -509,10 +509,8 @@ bool GLGizmoCut3D::render_cut_mode_combo()
|
|||||||
m_contour_width = CutMode(m_mode) == CutMode::cutTongueAndGroove ? 0.f : 0.4f;
|
m_contour_width = CutMode(m_mode) == CutMode::cutTongueAndGroove ? 0.f : 0.4f;
|
||||||
oc->set_behavior(m_connectors_editing, m_connectors_editing, double(m_contour_width));
|
oc->set_behavior(m_connectors_editing, m_connectors_editing, double(m_contour_width));
|
||||||
}
|
}
|
||||||
if (m_use_TAG_mesh) {
|
if (m_use_TAG_mesh)
|
||||||
m_plane.reset();
|
update_plane_model();
|
||||||
on_unregister_raycasters_for_picking();
|
|
||||||
}
|
|
||||||
reset_cut_by_contours();
|
reset_cut_by_contours();
|
||||||
update_clipper();
|
update_clipper();
|
||||||
check_and_update_connectors_state();
|
check_and_update_connectors_state();
|
||||||
@ -921,6 +919,23 @@ indexed_triangle_set GLGizmoCut3D::its_make_groove_plane()
|
|||||||
|
|
||||||
const float cut_plane_thiknes = 0.02f;// 0.02f * (float)get_grabber_mean_size(m_bounding_box); // cut_plane_thiknes
|
const float cut_plane_thiknes = 0.02f;// 0.02f * (float)get_grabber_mean_size(m_bounding_box); // cut_plane_thiknes
|
||||||
|
|
||||||
|
// Vertices of the groove used to detection if groove is valid
|
||||||
|
// They are written as:
|
||||||
|
// {left_ext_lower, left_nar_lower, left_ext_upper, left_nar_upper,
|
||||||
|
// right_ext_lower, right_nar_lower, right_ext_upper, right_nar_upper }
|
||||||
|
{
|
||||||
|
m_groove_vertices.clear();
|
||||||
|
m_groove_vertices.reserve(8);
|
||||||
|
|
||||||
|
m_groove_vertices.emplace_back(Vec3f(-ext_lower_x, -y, z_lower).cast<double>());
|
||||||
|
m_groove_vertices.emplace_back(Vec3f(-nar_lower_x, y, z_lower).cast<double>());
|
||||||
|
m_groove_vertices.emplace_back(Vec3f(-ext_upper_x, -y, z_upper).cast<double>());
|
||||||
|
m_groove_vertices.emplace_back(Vec3f(-nar_upper_x, y, z_upper).cast<double>());
|
||||||
|
m_groove_vertices.emplace_back(Vec3f( ext_lower_x, -y, z_lower).cast<double>());
|
||||||
|
m_groove_vertices.emplace_back(Vec3f( nar_lower_x, y, z_lower).cast<double>());
|
||||||
|
m_groove_vertices.emplace_back(Vec3f( ext_upper_x, -y, z_upper).cast<double>());
|
||||||
|
m_groove_vertices.emplace_back(Vec3f( nar_upper_x, y, z_upper).cast<double>());
|
||||||
|
}
|
||||||
|
|
||||||
// Different cases of groove plane:
|
// Different cases of groove plane:
|
||||||
|
|
||||||
@ -1211,7 +1226,7 @@ void GLGizmoCut3D::render_cut_plane()
|
|||||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||||
|
|
||||||
if (m_use_TAG_mesh) {
|
if (m_use_TAG_mesh) {
|
||||||
ColorRGBA cp_clr = can_perform_cut() && has_valid_contour() ? CUT_PLANE_DEF_COLOR : CUT_PLANE_ERR_COLOR;
|
ColorRGBA cp_clr = can_perform_cut() && has_valid_groove() ? CUT_PLANE_DEF_COLOR : CUT_PLANE_ERR_COLOR;
|
||||||
if (m_mode == size_t(CutMode::cutTongueAndGroove))
|
if (m_mode == size_t(CutMode::cutTongueAndGroove))
|
||||||
cp_clr.a(cp_clr.a() - 0.1f);
|
cp_clr.a(cp_clr.a() - 0.1f);
|
||||||
m_plane.model.set_color(cp_clr);
|
m_plane.model.set_color(cp_clr);
|
||||||
@ -1718,6 +1733,14 @@ void GLGizmoCut3D::update_raycasters_for_picking_transform()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLGizmoCut3D::update_plane_model()
|
||||||
|
{
|
||||||
|
m_plane.reset();
|
||||||
|
on_unregister_raycasters_for_picking();
|
||||||
|
|
||||||
|
init_picking_models();
|
||||||
|
}
|
||||||
|
|
||||||
void GLGizmoCut3D::on_set_hover_id()
|
void GLGizmoCut3D::on_set_hover_id()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -2415,10 +2438,7 @@ void GLGizmoCut3D::render_debug_input_window(float x)
|
|||||||
is_changed |= m_imgui->checkbox(("Render Cut plane as a full mesh"), m_use_TAG_mesh_full);
|
is_changed |= m_imgui->checkbox(("Render Cut plane as a full mesh"), m_use_TAG_mesh_full);
|
||||||
|
|
||||||
if (is_changed)
|
if (is_changed)
|
||||||
{
|
update_plane_model();
|
||||||
m_plane.reset();
|
|
||||||
on_unregister_raycasters_for_picking();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_imgui->end();
|
m_imgui->end();
|
||||||
return;
|
return;
|
||||||
@ -2710,14 +2730,12 @@ void GLGizmoCut3D::reset_cut_by_contours()
|
|||||||
m_part_selection = PartSelection();
|
m_part_selection = PartSelection();
|
||||||
|
|
||||||
if (CutMode(m_mode) == CutMode::cutTongueAndGroove) {
|
if (CutMode(m_mode) == CutMode::cutTongueAndGroove) {
|
||||||
if (m_optimaze_groove_rendering && m_dragging)
|
if (m_optimaze_groove_rendering && m_dragging || !has_valid_groove())
|
||||||
return;
|
return;
|
||||||
process_contours();
|
process_contours();
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
m_invalid_groove = false;
|
|
||||||
toggle_model_objects_visibility();
|
toggle_model_objects_visibility();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoCut3D::process_contours()
|
void GLGizmoCut3D::process_contours()
|
||||||
@ -2734,10 +2752,8 @@ void GLGizmoCut3D::process_contours()
|
|||||||
|
|
||||||
if (CutMode(m_mode) == CutMode::cutTongueAndGroove) {
|
if (CutMode(m_mode) == CutMode::cutTongueAndGroove) {
|
||||||
ModelObjectPtrs cut_objects = perform_cut_with_groove(model_objects[object_idx], true);
|
ModelObjectPtrs cut_objects = perform_cut_with_groove(model_objects[object_idx], true);
|
||||||
if (!cut_objects.empty() && !m_invalid_groove)
|
if (!cut_objects.empty())
|
||||||
m_part_selection = PartSelection(cut_objects.front(), instance_idx);
|
m_part_selection = PartSelection(cut_objects.front(), instance_idx);
|
||||||
else
|
|
||||||
m_invalid_groove = true;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
reset_cut_by_contours();
|
reset_cut_by_contours();
|
||||||
@ -2808,10 +2824,8 @@ void GLGizmoCut3D::render_groove_float_input(const std::string& label, float& in
|
|||||||
m_imgui->disabled_end();
|
m_imgui->disabled_end();
|
||||||
|
|
||||||
if (is_changed) {
|
if (is_changed) {
|
||||||
if (m_use_TAG_mesh) {
|
if (m_use_TAG_mesh)
|
||||||
m_plane.reset();
|
update_plane_model();
|
||||||
on_unregister_raycasters_for_picking();
|
|
||||||
}
|
|
||||||
reset_cut_by_contours();
|
reset_cut_by_contours();
|
||||||
// Plater::TakeSnapshot snapshot(wxGetApp().plater(), format_wxstr("%1%: %2%", _L("Groove change"), label), UndoRedo::SnapshotType::GizmoAction);
|
// Plater::TakeSnapshot snapshot(wxGetApp().plater(), format_wxstr("%1%: %2%", _L("Groove change"), label), UndoRedo::SnapshotType::GizmoAction);
|
||||||
}
|
}
|
||||||
@ -2848,10 +2862,8 @@ void GLGizmoCut3D::render_groove_angle_input(const std::string& label, float& in
|
|||||||
m_imgui->disabled_end();
|
m_imgui->disabled_end();
|
||||||
|
|
||||||
if (is_changed) {
|
if (is_changed) {
|
||||||
if (m_use_TAG_mesh) {
|
if (m_use_TAG_mesh)
|
||||||
m_plane.reset();
|
update_plane_model();
|
||||||
on_unregister_raycasters_for_picking();
|
|
||||||
}
|
|
||||||
reset_cut_by_contours();
|
reset_cut_by_contours();
|
||||||
// Plater::TakeSnapshot snapshot(wxGetApp().plater(), format_wxstr("%1%: %2%", _L("Groove change"), label), UndoRedo::SnapshotType::GizmoAction);
|
// Plater::TakeSnapshot snapshot(wxGetApp().plater(), format_wxstr("%1%: %2%", _L("Groove change"), label), UndoRedo::SnapshotType::GizmoAction);
|
||||||
}
|
}
|
||||||
@ -3129,7 +3141,7 @@ void GLGizmoCut3D::render_input_window_warning() const
|
|||||||
m_imgui->text(wxString(ImGui::WarningMarkerSmall) + _L("Select at least one object to keep after cutting."));
|
m_imgui->text(wxString(ImGui::WarningMarkerSmall) + _L("Select at least one object to keep after cutting."));
|
||||||
if (!has_valid_contour())
|
if (!has_valid_contour())
|
||||||
m_imgui->text(wxString(ImGui::WarningMarkerSmall) + _L("Cut plane is placed out of object"));
|
m_imgui->text(wxString(ImGui::WarningMarkerSmall) + _L("Cut plane is placed out of object"));
|
||||||
if (m_invalid_groove)
|
else if (!has_valid_groove())
|
||||||
m_imgui->text(wxString(ImGui::WarningMarkerSmall) + _L("Cut plane with groove is invalid"));
|
m_imgui->text(wxString(ImGui::WarningMarkerSmall) + _L("Cut plane with groove is invalid"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3362,7 +3374,7 @@ bool GLGizmoCut3D::can_perform_cut() const
|
|||||||
|
|
||||||
if (CutMode(m_mode) == CutMode::cutTongueAndGroove) {
|
if (CutMode(m_mode) == CutMode::cutTongueAndGroove) {
|
||||||
const float flaps_width = -2.f * m_groove_depth / tan(m_groove_flaps_angle);
|
const float flaps_width = -2.f * m_groove_depth / tan(m_groove_flaps_angle);
|
||||||
return flaps_width < m_groove_width && !m_invalid_groove && has_valid_contour();
|
return flaps_width < m_groove_width && has_valid_groove();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_part_selection.valid())
|
if (m_part_selection.valid())
|
||||||
@ -3371,6 +3383,39 @@ bool GLGizmoCut3D::can_perform_cut() const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GLGizmoCut3D::has_valid_groove() const
|
||||||
|
{
|
||||||
|
if (CutMode(m_mode) != CutMode::cutTongueAndGroove)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const Selection& selection = m_parent.get_selection();
|
||||||
|
const auto&list = selection.get_volume_idxs();
|
||||||
|
// is more volumes selected?
|
||||||
|
if (list.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const Transform3d cp_matrix = translation_transform(m_plane_center) * m_rotation_m;
|
||||||
|
|
||||||
|
for (size_t id = 0; id < m_groove_vertices.size(); id += 2) {
|
||||||
|
const Vec3d beg = cp_matrix * m_groove_vertices[id];
|
||||||
|
const Vec3d end = cp_matrix * m_groove_vertices[id + 1];
|
||||||
|
|
||||||
|
bool intersection = false;
|
||||||
|
for (const unsigned int volume_idx : list) {
|
||||||
|
const GLVolume* glvol = selection.get_volume(volume_idx);
|
||||||
|
if (!glvol->is_modifier &&
|
||||||
|
glvol->mesh_raycaster->intersects_line(beg, end - beg, glvol->world_matrix())) {
|
||||||
|
intersection = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!intersection)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool GLGizmoCut3D::has_valid_contour() const
|
bool GLGizmoCut3D::has_valid_contour() const
|
||||||
{
|
{
|
||||||
const auto clipper = m_c->object_clipper();
|
const auto clipper = m_c->object_clipper();
|
||||||
@ -3569,7 +3614,8 @@ ModelObjectPtrs GLGizmoCut3D::perform_cut_by_contour(ModelObject* cut_mo, const
|
|||||||
|
|
||||||
ModelObjectPtrs GLGizmoCut3D::perform_cut_with_groove(ModelObject* cut_mo, bool keep_as_parts/* = false*/)
|
ModelObjectPtrs GLGizmoCut3D::perform_cut_with_groove(ModelObject* cut_mo, bool keep_as_parts/* = false*/)
|
||||||
{
|
{
|
||||||
m_invalid_groove = false;
|
if (!has_valid_groove())
|
||||||
|
return {};
|
||||||
|
|
||||||
const Selection& selection = m_parent.get_selection();
|
const Selection& selection = m_parent.get_selection();
|
||||||
const int instance_idx = selection.get_instance_idx();
|
const int instance_idx = selection.get_instance_idx();
|
||||||
@ -3684,9 +3730,6 @@ ModelObjectPtrs GLGizmoCut3D::perform_cut_with_groove(ModelObject* cut_mo, bool
|
|||||||
invalid_added_volumes |= !add_volumes_from_cut(upper, ModelObjectCutAttribute::KeepLower, cut_part_ptrs);
|
invalid_added_volumes |= !add_volumes_from_cut(upper, ModelObjectCutAttribute::KeepLower, cut_part_ptrs);
|
||||||
|
|
||||||
if (keep_as_parts) {
|
if (keep_as_parts) {
|
||||||
if (!m_invalid_groove)
|
|
||||||
m_invalid_groove = upper->volumes.empty() || lower->volumes.empty() || invalid_added_volumes;
|
|
||||||
|
|
||||||
// add volumes from lower object to the upper, but mark them as a lower
|
// add volumes from lower object to the upper, but mark them as a lower
|
||||||
const auto& volumes = lower->volumes;
|
const auto& volumes = lower->volumes;
|
||||||
for (const ModelVolume* volume : volumes) {
|
for (const ModelVolume* volume : volumes) {
|
||||||
|
@ -109,8 +109,6 @@ class GLGizmoCut3D : public GLGizmoBase
|
|||||||
}
|
}
|
||||||
} m_info_stats;
|
} m_info_stats;
|
||||||
|
|
||||||
bool m_invalid_groove{ false };
|
|
||||||
|
|
||||||
bool m_keep_upper{ true };
|
bool m_keep_upper{ true };
|
||||||
bool m_keep_lower{ true };
|
bool m_keep_lower{ true };
|
||||||
bool m_keep_as_parts{ false };
|
bool m_keep_as_parts{ false };
|
||||||
@ -163,6 +161,9 @@ class GLGizmoCut3D : public GLGizmoBase
|
|||||||
bool m_was_cut_plane_dragged { false };
|
bool m_was_cut_plane_dragged { false };
|
||||||
bool m_was_contour_selected { false };
|
bool m_was_contour_selected { false };
|
||||||
|
|
||||||
|
// Vertices of the groove used to detection if groove is valid
|
||||||
|
std::vector<Vec3d> m_groove_vertices;
|
||||||
|
|
||||||
class PartSelection {
|
class PartSelection {
|
||||||
public:
|
public:
|
||||||
PartSelection() = default;
|
PartSelection() = default;
|
||||||
@ -323,6 +324,8 @@ protected:
|
|||||||
void set_volumes_picking_state(bool state);
|
void set_volumes_picking_state(bool state);
|
||||||
void update_raycasters_for_picking_transform();
|
void update_raycasters_for_picking_transform();
|
||||||
|
|
||||||
|
void update_plane_model();
|
||||||
|
|
||||||
void on_render_input_window(float x, float y, float bottom_limit) override;
|
void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||||
|
|
||||||
bool wants_enter_leave_snapshots() const override { return true; }
|
bool wants_enter_leave_snapshots() const override { return true; }
|
||||||
@ -348,6 +351,7 @@ private:
|
|||||||
void render_connectors();
|
void render_connectors();
|
||||||
|
|
||||||
bool can_perform_cut() const;
|
bool can_perform_cut() const;
|
||||||
|
bool has_valid_groove() const;
|
||||||
bool has_valid_contour() const;
|
bool has_valid_contour() const;
|
||||||
void apply_connectors_in_model(ModelObject* mo, int &dowels_count);
|
void apply_connectors_in_model(ModelObject* mo, int &dowels_count);
|
||||||
bool cut_line_processing() const;
|
bool cut_line_processing() const;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user