diff --git a/src/libslic3r/Brim.cpp b/src/libslic3r/Brim.cpp index a13d578a3..8f31b0695 100644 --- a/src/libslic3r/Brim.cpp +++ b/src/libslic3r/Brim.cpp @@ -114,6 +114,7 @@ static ConstPrintObjectPtrs get_top_level_objects_with_brim(const Print &print, clipper.AddPaths(islands_clip, ClipperLib_Z::ptSubject, true); // Execute union operation to construct polytree ClipperLib_Z::PolyTree islands_polytree; + //FIXME likely pftNonZero or ptfPositive would be better. Why are we using ptfEvenOdd for Unions? clipper.Execute(ClipperLib_Z::ctUnion, islands_polytree, ClipperLib_Z::pftEvenOdd, ClipperLib_Z::pftEvenOdd); std::unordered_set processed_objects_idx; @@ -486,7 +487,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance clipper.AddPaths(input_subject, ClipperLib_Z::ptSubject, true); clipper.AddPaths(input_clip, ClipperLib_Z::ptClip, true); // perform operation - clipper.Execute(ClipperLib_Z::ctDifference, trimming, ClipperLib_Z::pftEvenOdd, ClipperLib_Z::pftEvenOdd); + clipper.Execute(ClipperLib_Z::ctDifference, trimming, ClipperLib_Z::pftNonZero, ClipperLib_Z::pftNonZero); } // Second, trim the extrusion loops with the trimming regions. @@ -515,7 +516,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance clipper.AddPaths(trimming, ClipperLib_Z::ptClip, true); // perform operation ClipperLib_Z::PolyTree loops_trimmed_tree; - clipper.Execute(ClipperLib_Z::ctDifference, loops_trimmed_tree, ClipperLib_Z::pftEvenOdd, ClipperLib_Z::pftEvenOdd); + clipper.Execute(ClipperLib_Z::ctDifference, loops_trimmed_tree, ClipperLib_Z::pftNonZero, ClipperLib_Z::pftNonZero); ClipperLib_Z::PolyTreeToPaths(loops_trimmed_tree, loops_trimmed); } diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index b34a6cb58..232e724e7 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1244,8 +1244,8 @@ void PrintConfigDef::init_fff_params() def->enum_values.push_back("external"); def->enum_values.push_back("all"); def->enum_labels.push_back(L("None")); - def->enum_labels.push_back(L("External perimeters")); - def->enum_labels.push_back(L("All perimeters")); + def->enum_labels.push_back(L("Outside walls")); + def->enum_labels.push_back(L("All walls")); def->mode = comSimple; def->set_default_value(new ConfigOptionEnum(FuzzySkinType::None)); @@ -3970,10 +3970,16 @@ std::string validate(const FullPrintConfig &cfg) if (em <= 0) return "Invalid value for --extrusion-multiplier"; + // The following test was commented out after 482841b, see also https://github.com/prusa3d/PrusaSlicer/pull/6743. + // The backend should now handle this case correctly. I.e., zero default_acceleration behaves as if all others + // were zero too. This is now consistent with what the UI said would happen. + // The UI already grays the fields out, there is no more reason to reject it here. This function validates the + // config before exporting, leaving this check in would mean that config would be rejected before export + // (although both the UI and the backend handle it). // --default-acceleration - if ((cfg.perimeter_acceleration != 0. || cfg.infill_acceleration != 0. || cfg.bridge_acceleration != 0. || cfg.first_layer_acceleration != 0.) && - cfg.default_acceleration == 0.) - return "Invalid zero value for --default-acceleration when using other acceleration settings"; + //if ((cfg.perimeter_acceleration != 0. || cfg.infill_acceleration != 0. || cfg.bridge_acceleration != 0. || cfg.first_layer_acceleration != 0.) && + // cfg.default_acceleration == 0.) + // return "Invalid zero value for --default-acceleration when using other acceleration settings"; // --spiral-vase if (cfg.spiral_vase) { diff --git a/src/libslic3r/SLA/ConcaveHull.cpp b/src/libslic3r/SLA/ConcaveHull.cpp index cfce36d16..08a2ff676 100644 --- a/src/libslic3r/SLA/ConcaveHull.cpp +++ b/src/libslic3r/SLA/ConcaveHull.cpp @@ -133,7 +133,8 @@ ExPolygons offset_waffle_style_ex(const ConcaveHull &hull, coord_t delta) Polygons offset_waffle_style(const ConcaveHull &hull, coord_t delta) { - Polygons res = closing(hull.polygons(), 2 * delta, delta, ClipperLib::jtRound); + auto arc_tolerance = scaled(0.01); + Polygons res = closing(hull.polygons(), 2 * delta, delta, ClipperLib::jtRound, arc_tolerance); auto it = std::remove_if(res.begin(), res.end(), [](Polygon &p) { return p.is_clockwise(); }); res.erase(it, res.end()); diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index f65292f03..169978688 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -128,13 +128,13 @@ void TriangleSelector::select_patch(const Vec3f& hit, int facet_start, const Vec3f& source, float radius, CursorType cursor_type, EnforcerBlockerType new_state, const Transform3d& trafo, const Transform3d& trafo_no_translate, - bool triangle_splitting, float highlight_by_angle_deg) + bool triangle_splitting, const ClippingPlane &clp, float highlight_by_angle_deg) { assert(facet_start < m_orig_size_indices); // Save current cursor center, squared radius and camera direction, so we don't // have to pass it around. - m_cursor = Cursor(hit, source, radius, cursor_type, trafo); + m_cursor = Cursor(hit, source, radius, cursor_type, trafo, clp); // In case user changed cursor size since last time, update triangle edge limit. // It is necessary to compare the internal radius in m_cursor! radius is in @@ -172,15 +172,23 @@ void TriangleSelector::select_patch(const Vec3f& hit, int facet_start, } } -void TriangleSelector::seed_fill_select_triangles(const Vec3f &hit, int facet_start, - const Transform3d& trafo_no_translate, - float seed_fill_angle, float highlight_by_angle_deg, +bool TriangleSelector::is_facet_clipped(int facet_idx, const ClippingPlane &clp) const +{ + for (int vert_idx : m_triangles[facet_idx].verts_idxs) + if (clp.is_active() && clp.is_mesh_point_clipped(m_vertices[vert_idx].v)) + return true; + + return false; +} + +void TriangleSelector::seed_fill_select_triangles(const Vec3f &hit, int facet_start, const Transform3d& trafo_no_translate, + const ClippingPlane &clp, float seed_fill_angle, float highlight_by_angle_deg, bool force_reselection) { assert(facet_start < m_orig_size_indices); - // Recompute seed fill only if the cursor is pointing on facet unselected by seed fill. - if (int start_facet_idx = select_unsplit_triangle(hit, facet_start); start_facet_idx >= 0 && m_triangles[start_facet_idx].is_selected_by_seed_fill() && !force_reselection) + // Recompute seed fill only if the cursor is pointing on facet unselected by seed fill or a clipping plane is active. + if (int start_facet_idx = select_unsplit_triangle(hit, facet_start); start_facet_idx >= 0 && m_triangles[start_facet_idx].is_selected_by_seed_fill() && !force_reselection && !clp.is_active()) return; this->seed_fill_unselect_all_triangles(); @@ -215,7 +223,7 @@ void TriangleSelector::seed_fill_select_triangles(const Vec3f &hit, int facet_st // Propagate over the original triangles. for (int neighbor_idx : m_neighbors[current_facet]) { assert(neighbor_idx >= -1); - if (neighbor_idx >= 0 && !visited[neighbor_idx]) { + if (neighbor_idx >= 0 && !visited[neighbor_idx] && !is_facet_clipped(neighbor_idx, clp)) { // Check if neighbour_facet_idx is satisfies angle in seed_fill_angle and append it to facet_queue if it do. const Vec3f &n1 = m_face_normals[m_triangles[neighbor_idx].source_triangle]; const Vec3f &n2 = m_face_normals[m_triangles[current_facet].source_triangle]; @@ -331,12 +339,12 @@ void TriangleSelector::append_touching_edges(int itriangle, int vertexi, int ver process_subtriangle(touching.second, Partition::Second); } -void TriangleSelector::bucket_fill_select_triangles(const Vec3f& hit, int facet_start, bool propagate, bool force_reselection) +void TriangleSelector::bucket_fill_select_triangles(const Vec3f& hit, int facet_start, const ClippingPlane &clp, bool propagate, bool force_reselection) { int start_facet_idx = select_unsplit_triangle(hit, facet_start); assert(start_facet_idx != -1); - // Recompute bucket fill only if the cursor is pointing on facet unselected by bucket fill. - if (start_facet_idx == -1 || (m_triangles[start_facet_idx].is_selected_by_seed_fill() && !force_reselection)) + // Recompute bucket fill only if the cursor is pointing on facet unselected by bucket fill or a clipping plane is active. + if (start_facet_idx == -1 || (m_triangles[start_facet_idx].is_selected_by_seed_fill() && !force_reselection && !clp.is_active())) return; assert(!m_triangles[start_facet_idx].is_split()); @@ -379,7 +387,7 @@ void TriangleSelector::bucket_fill_select_triangles(const Vec3f& hit, int facet_ std::vector touching_triangles = get_all_touching_triangles(current_facet, neighbors[current_facet], neighbors_propagated[current_facet]); for(const int tr_idx : touching_triangles) { - if (tr_idx < 0 || visited[tr_idx] || m_triangles[tr_idx].get_state() != start_facet_state) + if (tr_idx < 0 || visited[tr_idx] || m_triangles[tr_idx].get_state() != start_facet_state || is_facet_clipped(tr_idx, clp)) continue; assert(!m_triangles[tr_idx].is_split()); @@ -1687,11 +1695,12 @@ void TriangleSelector::seed_fill_apply_on_triangles(EnforcerBlockerType new_stat TriangleSelector::Cursor::Cursor( const Vec3f& center_, const Vec3f& source_, float radius_world, - CursorType type_, const Transform3d& trafo_) + CursorType type_, const Transform3d& trafo_, const ClippingPlane &clipping_plane_) : center{center_}, source{source_}, type{type_}, - trafo{trafo_.cast()} + trafo{trafo_.cast()}, + clipping_plane(clipping_plane_) { Vec3d sf = Geometry::Transformation(trafo_).get_scaling_factor(); if (is_approx(sf(0), sf(1)) && is_approx(sf(1), sf(2))) { @@ -1714,22 +1723,19 @@ TriangleSelector::Cursor::Cursor( dir = (center - source).normalized(); } - // Is a point (in mesh coords) inside a cursor? -bool TriangleSelector::Cursor::is_mesh_point_inside(Vec3f point) const +bool TriangleSelector::Cursor::is_mesh_point_inside(const Vec3f &point) const { - if (! uniform_scaling) - point = trafo * point; + const Vec3f transformed_point = uniform_scaling ? point : Vec3f(trafo * point); + const Vec3f diff = center - transformed_point; + const bool is_point_inside = (type == CIRCLE ? (diff - diff.dot(dir) * dir).squaredNorm() : diff.squaredNorm()) < radius_sqr; - Vec3f diff = center - point; - return (type == CIRCLE ? - (diff - diff.dot(dir) * dir).squaredNorm() : - diff.squaredNorm()) - < radius_sqr; + if (is_point_inside && clipping_plane.is_active()) + return !clipping_plane.is_mesh_point_clipped(point); + + return is_point_inside; } - - // p1, p2, p3 are in mesh coords! bool TriangleSelector::Cursor::is_pointer_in_triangle(const Vec3f& p1_, const Vec3f& p2_, diff --git a/src/libslic3r/TriangleSelector.hpp b/src/libslic3r/TriangleSelector.hpp index b3c468a6e..b9f136c2e 100644 --- a/src/libslic3r/TriangleSelector.hpp +++ b/src/libslic3r/TriangleSelector.hpp @@ -4,6 +4,7 @@ // #define PRUSASLICER_TRIANGLE_SELECTOR_DEBUG +#include #include "Point.hpp" #include "TriangleMesh.hpp" @@ -22,6 +23,18 @@ public: POINTER }; + struct ClippingPlane + { + Vec3f normal; + float offset; + ClippingPlane() : normal{0.f, 0.f, 1.f}, offset{FLT_MAX} {}; + explicit ClippingPlane(const std::array &clp) : normal{clp[0], clp[1], clp[2]}, offset{clp[3]} {} + + bool is_active() const { return offset != FLT_MAX; } + + bool is_mesh_point_clipped(const Vec3f &point) const { return normal.dot(point) - offset > 0.f; } + }; + std::pair, std::vector> precompute_all_neighbors() const; void precompute_all_neighbors_recursive(int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated, std::vector &neighbors_out, std::vector &neighbors_normal_out) const; @@ -47,19 +60,22 @@ public: const Transform3d &trafo, // matrix to get from mesh to world const Transform3d &trafo_no_translate, // matrix to get from mesh to world without translation bool triangle_splitting, // If triangles will be split base on the cursor or not + const ClippingPlane &clp, // Clipping plane to limit painting to not clipped facets only float highlight_by_angle_deg = 0.f); // The maximal angle of overhang. If it is set to a non-zero value, it is possible to paint only the triangles of overhang defined by this angle in degrees. - void seed_fill_select_triangles(const Vec3f &hit, // point where to start - int facet_start, // facet of the original mesh (unsplit) that the hit point belongs to - const Transform3d &trafo_no_translate, // matrix to get from mesh to world without translation - float seed_fill_angle, // the maximal angle between two facets to be painted by the same color - float highlight_by_angle_deg = 0.f, // The maximal angle of overhang. If it is set to a non-zero value, it is possible to paint only the triangles of overhang defined by this angle in degrees. - bool force_reselection = false); // force reselection of the triangle mesh even in cases that mouse is pointing on the selected triangle + void seed_fill_select_triangles(const Vec3f &hit, // point where to start + int facet_start, // facet of the original mesh (unsplit) that the hit point belongs to + const Transform3d &trafo_no_translate, // matrix to get from mesh to world without translation + const ClippingPlane &clp, // Clipping plane to limit painting to not clipped facets only + float seed_fill_angle, // the maximal angle between two facets to be painted by the same color + float highlight_by_angle_deg = 0.f, // The maximal angle of overhang. If it is set to a non-zero value, it is possible to paint only the triangles of overhang defined by this angle in degrees. + bool force_reselection = false); // force reselection of the triangle mesh even in cases that mouse is pointing on the selected triangle - void bucket_fill_select_triangles(const Vec3f &hit, // point where to start - int facet_start, // facet of the original mesh (unsplit) that the hit point belongs to - bool propagate, // if bucket fill is propagated to neighbor faces or if it fills the only facet of the modified mesh that the hit point belongs to. - bool force_reselection = false); // force reselection of the triangle mesh even in cases that mouse is pointing on the selected triangle + void bucket_fill_select_triangles(const Vec3f &hit, // point where to start + int facet_start, // facet of the original mesh (unsplit) that the hit point belongs to + const ClippingPlane &clp, // Clipping plane to limit painting to not clipped facets only + bool propagate, // if bucket fill is propagated to neighbor faces or if it fills the only facet of the modified mesh that the hit point belongs to. + bool force_reselection = false); // force reselection of the triangle mesh even in cases that mouse is pointing on the selected triangle bool has_facets(EnforcerBlockerType state) const; static bool has_facets(const std::pair>, std::vector> &data, EnforcerBlockerType test_state); @@ -183,8 +199,8 @@ protected: struct Cursor { Cursor() = default; Cursor(const Vec3f& center_, const Vec3f& source_, float radius_world, - CursorType type_, const Transform3d& trafo_); - bool is_mesh_point_inside(Vec3f pt) const; + CursorType type_, const Transform3d& trafo_, const ClippingPlane &clipping_plane_); + bool is_mesh_point_inside(const Vec3f &pt) const; bool is_pointer_in_triangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3) const; Vec3f center; @@ -195,6 +211,7 @@ protected: Transform3f trafo; Transform3f trafo_normal; bool uniform_scaling; + ClippingPlane clipping_plane; }; Cursor m_cursor; @@ -211,6 +228,7 @@ private: void remove_useless_children(int facet_idx); // No hidden meaning. Triangles are meant. bool is_pointer_in_triangle(int facet_idx) const; bool is_edge_inside_cursor(int facet_idx) const; + bool is_facet_clipped(int facet_idx, const ClippingPlane &clp) const; int push_triangle(int a, int b, int c, int source_triangle, EnforcerBlockerType state = EnforcerBlockerType{0}); void perform_split(int facet_idx, const Vec3i &neighbors, EnforcerBlockerType old_state); Vec3i child_neighbors(const Triangle &tr, const Vec3i &neighbors, int child_idx) const; diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index d0b29165c..fc47484b5 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -2080,7 +2080,7 @@ void Control::auto_color_change() } int extruders_cnt = GUI::wxGetApp().extruders_edited_cnt(); - int extruder = 2; +// int extruder = 2; const Print& print = GUI::wxGetApp().plater()->fff_print(); for (auto object : print.objects()) { diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index d399fbac4..69c786b71 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1448,7 +1448,7 @@ void ObjectList::load_subobject(ModelVolumeType type, bool from_galery/* = false selection_changed(); } /* -void ObjectList::load_part(ModelObject& model_object, std::vector& added_volumes, ModelVolumeType type, bool from_galery/* = false* /) +void ObjectList::load_part(ModelObject& model_object, std::vector& added_volumes, ModelVolumeType type, bool from_galery = false) { if (type != ModelVolumeType::MODEL_PART) return; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 8cfb3fbca..2825913d3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -267,7 +267,8 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous const ModelObject *mo = m_c->selection_info()->model_object(); const ModelInstance *mi = mo->instances[selection.get_instance_idx()]; const Transform3d trafo_matrix_not_translate = mi->get_transformation().get_matrix(true) * mo->volumes[m_rr.mesh_id]->get_matrix(true); - m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), trafo_matrix_not_translate, m_smart_fill_angle, + const Transform3d trafo_matrix = mi->get_transformation().get_matrix() * mo->volumes[m_rr.mesh_id]->get_matrix(); + m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), trafo_matrix_not_translate, this->get_clipping_plane_in_volume_coordinates(trafo_matrix), m_smart_fill_angle, m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f, true); m_triangle_selectors[m_rr.mesh_id]->request_update_render_data(); m_seed_fill_last_mesh_id = m_rr.mesh_id; @@ -364,22 +365,22 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous Vec3f camera_pos = (trafo_matrix.inverse() * camera.get_position()).cast(); assert(m_rr.mesh_id < int(m_triangle_selectors.size())); + const TriangleSelector::ClippingPlane &clp = this->get_clipping_plane_in_volume_coordinates(trafo_matrix); if (m_tool_type == ToolType::SMART_FILL || m_tool_type == ToolType::BUCKET_FILL || (m_tool_type == ToolType::BRUSH && m_cursor_type == TriangleSelector::CursorType::POINTER)) { m_triangle_selectors[m_rr.mesh_id]->seed_fill_apply_on_triangles(new_state); if (m_tool_type == ToolType::SMART_FILL) - m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), trafo_matrix_not_translate, m_smart_fill_angle, + m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), trafo_matrix_not_translate, clp, m_smart_fill_angle, m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f, true); else if (m_tool_type == ToolType::BRUSH && m_cursor_type == TriangleSelector::CursorType::POINTER) - m_triangle_selectors[m_rr.mesh_id]->bucket_fill_select_triangles(m_rr.hit, int(m_rr.facet), false, true); + m_triangle_selectors[m_rr.mesh_id]->bucket_fill_select_triangles(m_rr.hit, int(m_rr.facet), clp, false, true); else if (m_tool_type == ToolType::BUCKET_FILL) - m_triangle_selectors[m_rr.mesh_id]->bucket_fill_select_triangles(m_rr.hit, int(m_rr.facet), true, true); + m_triangle_selectors[m_rr.mesh_id]->bucket_fill_select_triangles(m_rr.hit, int(m_rr.facet), clp, true, true); m_seed_fill_last_mesh_id = -1; } else if (m_tool_type == ToolType::BRUSH) m_triangle_selectors[m_rr.mesh_id]->select_patch(m_rr.hit, int(m_rr.facet), camera_pos, m_cursor_radius, m_cursor_type, - new_state, trafo_matrix, trafo_matrix_not_translate, m_triangle_splitting_enabled, + new_state, trafo_matrix, trafo_matrix_not_translate, m_triangle_splitting_enabled, clp, m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f); - m_triangle_selectors[m_rr.mesh_id]->request_update_render_data(); m_last_mouse_click = mouse_position; } @@ -430,16 +431,18 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous if(m_rr.mesh_id != m_seed_fill_last_mesh_id) seed_fill_unselect_all(); + const Transform3d &trafo_matrix = trafo_matrices[m_rr.mesh_id]; const Transform3d &trafo_matrix_not_translate = trafo_matrices_not_translate[m_rr.mesh_id]; assert(m_rr.mesh_id < int(m_triangle_selectors.size())); + const TriangleSelector::ClippingPlane &clp = this->get_clipping_plane_in_volume_coordinates(trafo_matrix); if (m_tool_type == ToolType::SMART_FILL) - m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), trafo_matrix_not_translate, m_smart_fill_angle, + m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), trafo_matrix_not_translate, clp, m_smart_fill_angle, m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f); else if (m_tool_type == ToolType::BRUSH && m_cursor_type == TriangleSelector::CursorType::POINTER) - m_triangle_selectors[m_rr.mesh_id]->bucket_fill_select_triangles(m_rr.hit, int(m_rr.facet), false); + m_triangle_selectors[m_rr.mesh_id]->bucket_fill_select_triangles(m_rr.hit, int(m_rr.facet), clp, false); else if (m_tool_type == ToolType::BUCKET_FILL) - m_triangle_selectors[m_rr.mesh_id]->bucket_fill_select_triangles(m_rr.hit, int(m_rr.facet), true); + m_triangle_selectors[m_rr.mesh_id]->bucket_fill_select_triangles(m_rr.hit, int(m_rr.facet), clp, true); m_triangle_selectors[m_rr.mesh_id]->request_update_render_data(); m_seed_fill_last_mesh_id = m_rr.mesh_id; return true; @@ -569,6 +572,25 @@ void GLGizmoPainterBase::on_load(cereal::BinaryInputArchive&) m_schedule_update = true; } +TriangleSelector::ClippingPlane GLGizmoPainterBase::get_clipping_plane_in_volume_coordinates(const Transform3d &trafo) const { + const ::Slic3r::GUI::ClippingPlane *const clipping_plane = m_c->object_clipper()->get_clipping_plane(); + if (clipping_plane == nullptr || !clipping_plane->is_active()) + return {}; + + const Vec3d clp_normal = clipping_plane->get_normal(); + const double clp_offset = clipping_plane->get_offset(); + + const Transform3d trafo_normal = Transform3d(trafo.linear().transpose()); + const Transform3d trafo_inv = trafo.inverse(); + + Vec3d point_on_plane = clp_normal * clp_offset; + Vec3d point_on_plane_transformed = trafo_inv * point_on_plane; + Vec3d normal_transformed = trafo_normal * clp_normal; + auto offset_transformed = float(point_on_plane_transformed.dot(normal_transformed)); + + return TriangleSelector::ClippingPlane({float(normal_transformed.x()), float(normal_transformed.y()), float(normal_transformed.z()), offset_transformed}); +} + std::array TriangleSelectorGUI::get_seed_fill_color(const std::array &base_color) { return {base_color[0] * 0.75f, base_color[1] * 0.75f, base_color[2] * 0.75f, 1.f}; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index 3093b0bec..eb09715da 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -184,6 +184,8 @@ protected: ClippingPlaneDataWrapper get_clipping_plane_data() const; + TriangleSelector::ClippingPlane get_clipping_plane_in_volume_coordinates(const Transform3d &trafo) const; + private: bool is_mesh_point_clipped(const Vec3d& point, const Transform3d& trafo) const; void update_raycast_cache(const Vec2d& mouse_position, diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index faf87227c..f0c1cc13c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -265,7 +265,7 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi ImGui::NewLine(); ImGui::SameLine(m_gui_cfg->bottom_left_width); - ImGui::Text(_L("%d triangles").c_str(), m_configuration.wanted_count); + ImGui::Text(_u8L("%d triangles").c_str(), m_configuration.wanted_count); m_imgui->disabled_end(); // use_count if (ImGui::Checkbox(_u8L("Show wireframe").c_str(), &m_show_wireframe)) { @@ -275,7 +275,7 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi bool is_canceling = m_state == State::canceling; m_imgui->disabled_begin(is_canceling); - if (m_imgui->button(_L("Cancel"))) { + if (m_imgui->button(_u8L("Cancel"))) { if (m_state == State::settings) { if (m_original_its.has_value()) { set_its(*m_original_its); @@ -294,7 +294,7 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi bool is_processing = m_state != State::settings; m_imgui->disabled_begin(is_processing); - if (m_imgui->button(_L("Apply"))) { + if (m_imgui->button(_u8L("Apply"))) { if (!m_is_valid_result) { m_state = State::close_on_end; process(); @@ -395,7 +395,7 @@ void GLGizmoSimplify::process() // store previous state auto plater = wxGetApp().plater(); - plater->take_snapshot(_L("Simplify ") + m_volume->name); + plater->take_snapshot(_u8L("Simplify ") + m_volume->name); plater->clear_before_change_mesh(m_obj_index); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 5f46ad3b7..3ec58e285 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -717,6 +717,10 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt) } else if (evt.LeftUp() && m_current == Flatten && m_gizmos[m_current]->get_hover_id() != -1) { // to avoid to loose the selection when user clicks an the white faces of a different object while the Flatten gizmo is active +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + selection.stop_dragging(); + wxGetApp().obj_manipul()->set_dirty(); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS processed = true; } else if (evt.RightUp() && (m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation) && !m_parent.is_mouse_dragging()) { diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index d4c93de25..d066ad2a3 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -306,7 +306,7 @@ ImVec2 ImGuiWrapper::get_item_spacing() const { const ImGuiContext &g = *GImGui; const ImGuiStyle &style = g.Style; - return g.Style.ItemSpacing; + return style.ItemSpacing; } float ImGuiWrapper::get_slider_float_height() const diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index 767abd7fd..ccdb83042 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -53,6 +53,7 @@ public: m_data[2] = norm_dir.z(); } void set_offset(double offset) { m_data[3] = offset; } + double get_offset() const { return m_data[3]; } Vec3d get_normal() const { return Vec3d(m_data[0], m_data[1], m_data[2]); } bool is_active() const { return m_data[3] != DBL_MAX; } static ClippingPlane ClipsNothing() { return ClippingPlane(Vec3d(0., 0., 1.), DBL_MAX); } diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index fd9f4b5e8..2e0d8384d 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -201,7 +201,7 @@ void OptionsGroup::activate_line(Line& line) if (line.is_separator()) return; - m_use_custom_ctrl_as_parent = false; + m_use_custom_ctrl_as_parent = false; if (line.full_width && ( line.widget != nullptr || diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e12e55631..83930f818 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -205,7 +205,7 @@ void ObjectInfo::msw_rescale() void ObjectInfo::update_warning_icon(const std::string& warning_icon_name) { - if (showing_manifold_warning_icon = !warning_icon_name.empty()) { + if ((showing_manifold_warning_icon = !warning_icon_name.empty())) { m_warning_icon_name = warning_icon_name; manifold_warning_icon->SetBitmap(create_scaled_bitmap(m_warning_icon_name)); } diff --git a/tests/libslic3r/test_config.cpp b/tests/libslic3r/test_config.cpp index 213105084..8dfda789e 100644 --- a/tests/libslic3r/test_config.cpp +++ b/tests/libslic3r/test_config.cpp @@ -220,7 +220,7 @@ SCENARIO("DynamicPrintConfig serialization", "[Config]") { cereal::BinaryOutputArchive oarchive(ss); oarchive(cfg); serialized = ss.str(); - } catch (std::runtime_error e) { + } catch (std::runtime_error &e) { e.what(); } @@ -230,7 +230,7 @@ SCENARIO("DynamicPrintConfig serialization", "[Config]") { std::stringstream ss(serialized); cereal::BinaryInputArchive iarchive(ss); iarchive(cfg2); - } catch (std::runtime_error e) { + } catch (std::runtime_error &e) { e.what(); } REQUIRE(cfg == cfg2);