From f702ad9fd296a3f7c71dead58b44918171f23653 Mon Sep 17 00:00:00 2001 From: "lane.wei" Date: Fri, 30 Aug 2024 21:13:16 +0800 Subject: [PATCH] ENH: dual_extruder: add logic to process extruder_printable_area JIRA: STUDIO-7498 Change-Id: I1cf53db93acf41b06cb1b9569a0679487c9f1e41 (cherry picked from commit e5be69dedd1ba6dc289a14b89598c9a6101dacb3) --- src/OrcaSlicer.cpp | 8 +- src/libslic3r/BuildVolume.cpp | 169 ++++++++++++++++++++++-- src/libslic3r/BuildVolume.hpp | 26 +++- src/libslic3r/GCode/GCodeProcessor.hpp | 1 + src/libslic3r/Model.cpp | 19 ++- src/libslic3r/Model.hpp | 1 + src/libslic3r/Support/TreeSupport3D.cpp | 2 +- src/slic3r/GUI/3DBed.cpp | 20 ++- src/slic3r/GUI/3DBed.hpp | 3 +- src/slic3r/GUI/3DScene.cpp | 46 ++++--- src/slic3r/GUI/BedShapeDialog.cpp | 8 +- src/slic3r/GUI/GCodeViewer.cpp | 6 +- src/slic3r/GUI/GLCanvas3D.cpp | 14 +- src/slic3r/GUI/GLCanvas3D.hpp | 1 + src/slic3r/GUI/MainFrame.cpp | 2 +- src/slic3r/GUI/PartPlate.cpp | 35 +++-- src/slic3r/GUI/PartPlate.hpp | 7 +- src/slic3r/GUI/Plater.cpp | 42 +++--- src/slic3r/GUI/Plater.hpp | 2 +- src/slic3r/Utils/CalibUtils.cpp | 3 +- 20 files changed, 339 insertions(+), 76 deletions(-) diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index 2e03970973..1d77aa4716 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -3027,6 +3027,7 @@ int CLI::run(int argc, char **argv) //use Pointfs insteadof Points Pointfs current_printable_area = m_print_config.opt("printable_area")->values; Pointfs current_exclude_area = m_print_config.opt("bed_exclude_area")->values; + std::vector current_extruder_areas; //update part plate's size double print_height = m_print_config.opt_float("printable_height"); double height_to_lid = m_print_config.opt_float("extruder_clearance_height_to_lid"); @@ -3035,6 +3036,9 @@ int CLI::run(int argc, char **argv) //double plate_stride; std::string bed_texture; + if (m_print_config.opt("extruder_printable_area")) { + current_extruder_areas = m_print_config.opt("extruder_printable_area")->values; + } current_printable_width = current_printable_area[2].x() - current_printable_area[0].x(); current_printable_depth = current_printable_area[2].y() - current_printable_area[0].y(); current_printable_height = print_height; @@ -3085,7 +3089,7 @@ int CLI::run(int argc, char **argv) else { partplate_list.reset_size(old_printable_width, old_printable_depth, old_printable_height, false); } - partplate_list.set_shapes(make_counter_clockwise(current_printable_area), current_exclude_area, bed_texture, height_to_lid, height_to_rod); + partplate_list.set_shapes(make_counter_clockwise(current_printable_area), current_exclude_areas, bed_texture, height_to_lid, height_to_rod); //plate_stride = partplate_list.plate_stride_x(); } @@ -4805,7 +4809,7 @@ int CLI::run(int argc, char **argv) BOOST_LOG_TRIVIAL(info) << boost::format("print_volume {%1%,%2%,%3%}->{%4%, %5%, %6%}") % print_volume.min(0) % print_volume.min(1) % print_volume.min(2) % print_volume.max(0) % print_volume.max(1) % print_volume.max(2) << std::endl; #else - BuildVolume build_volume(part_plate->get_shape(), print_height); + BuildVolume build_volume(part_plate->get_shape(), print_height, part_plate->get_extruder_areas()); //model.update_print_volume_state(build_volume); unsigned int count = model.update_print_volume_state(build_volume); diff --git a/src/libslic3r/BuildVolume.cpp b/src/libslic3r/BuildVolume.cpp index f73330827c..a7db3a8b50 100644 --- a/src/libslic3r/BuildVolume.cpp +++ b/src/libslic3r/BuildVolume.cpp @@ -9,7 +9,7 @@ namespace Slic3r { -BuildVolume::BuildVolume(const std::vector &printable_area, const double printable_height) : m_bed_shape(printable_area), m_max_print_height(printable_height) +BuildVolume::BuildVolume(const std::vector &printable_area, const double printable_height, const std::vector> &extruder_areas) : m_bed_shape(printable_area), m_max_print_height(printable_height), m_extruder_shapes(extruder_areas) { assert(printable_height >= 0); @@ -77,6 +77,69 @@ BuildVolume::BuildVolume(const std::vector &printable_area, const double m_top_bottom_convex_hull_decomposition_bed = convex_decomposition(m_convex_hull, BedEpsilon); } + if (m_extruder_shapes.size() > 0) + { + for (unsigned int index = 0; index < m_extruder_shapes.size(); index++) + { + std::vector& extruder_shape = m_extruder_shapes[index]; + BuildExtruderVolume extruder_volume; + + if (extruder_shape == printable_area) { + extruder_volume.same_with_bed = true; + extruder_volume.type = m_type; + extruder_volume.bbox = m_bbox; + extruder_volume.bboxf = m_bboxf; + extruder_volume.circle = m_circle; + } + else { + Polygon poly = Polygon::new_scale(extruder_shape); + + double poly_area = poly.area(); + extruder_volume.bbox = get_extents(poly); + BoundingBoxf temp_bboxf = get_extents(extruder_shape); + extruder_volume.bboxf = BoundingBoxf3{ to_3d(temp_bboxf.min, 0.), to_3d(temp_bboxf.max, printable_height) }; + + if (extruder_shape.size() >= 4 && std::abs((poly_area - double(extruder_volume.bbox.size().x()) * double(extruder_volume.bbox.size().y()))) < sqr(SCALED_EPSILON)) + { + extruder_volume.type = Type::Rectangle; + extruder_volume.circle.center = 0.5 * (extruder_volume.bbox.min.cast() + extruder_volume.bbox.max.cast()); + extruder_volume.circle.radius = 0.5 * extruder_volume.bbox.size().cast().norm(); + } + else if (extruder_shape.size() > 3) { + extruder_volume.circle = Geometry::circle_ransac(extruder_shape); + bool is_circle = true; + + Vec2d prev = extruder_shape.back(); + for (const Vec2d &p : extruder_shape) { + if (// Polygon vertices must lie very close the circle. + std::abs((p - extruder_volume.circle.center).norm() - extruder_volume.circle.radius) > 0.005 || + // Midpoints of polygon edges must not undercat more than 3mm. This corresponds to 72 edges per circle generated by BedShapePanel::update_shape(). + extruder_volume.circle.radius - (0.5 * (prev + p) -extruder_volume.circle.center).norm() > 3.) { + is_circle = false; + break; + } + prev = p; + } + if (is_circle) { + extruder_volume.type = Type::Circle; + extruder_volume.circle.center = scaled(extruder_volume.circle.center); + extruder_volume.circle.radius = scaled(extruder_volume.circle.radius); + } + } + + if (m_type == Type::Invalid) { + //not supported currently, use the same as bed + extruder_volume.same_with_bed = true; + extruder_volume.type = m_type; + extruder_volume.bbox = m_bbox; + extruder_volume.bboxf = m_bboxf; + extruder_volume.circle = m_circle; + } + m_extruder_volumes.push_back(std::move(extruder_volume)); + } + } + } + BOOST_LOG_TRIVIAL(debug) << "BuildVolume printable_area clasified as: " << this->type_name(); } @@ -197,7 +260,7 @@ BuildVolume::ObjectState object_state_templ(const indexed_triangle_set &its, con bool outside = false; static constexpr const auto world_min_z = float(-BuildVolume::SceneEpsilon); - if (may_be_below_bed) + if (may_be_below_bed) { // Slower test, needs to clip the object edges with the print bed plane. // 1) Allocate transformed vertices with their position with respect to print bed surface. @@ -260,7 +323,7 @@ BuildVolume::ObjectState object_state_templ(const indexed_triangle_set &its, con } } } - else + else { // Much simpler and faster code, not clipping the object with the print bed. assert(! may_be_below_bed); @@ -297,14 +360,14 @@ BuildVolume::ObjectState BuildVolume::object_state(const indexed_triangle_set& i case BuildVolume_Type::Circle: { Geometry::Circlef circle { unscaled(m_circle.center), unscaled(m_circle.radius + SceneEpsilon) }; - return m_max_print_height == 0.0 ? + return m_max_print_height == 0.0 ? object_state_templ(its, trafo, may_be_below_bed, true, [circle](const Vec3f& pt) { return circle.contains(to_2d(pt)); }) : object_state_templ(its, trafo, may_be_below_bed, true, [circle, z = m_max_print_height + SceneEpsilon](const Vec3f &pt) { return pt.z() < z && circle.contains(to_2d(pt)); }); } case BuildVolume_Type::Convex: //FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently. case BuildVolume_Type::Custom: - return m_max_print_height == 0.0 ? + return m_max_print_height == 0.0 ? object_state_templ(its, trafo, may_be_below_bed, m_type == BuildVolume_Type::Convex, [this](const Vec3f &pt) { return Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_scene, to_2d(pt).cast()); }) : object_state_templ(its, trafo, may_be_below_bed, m_type == BuildVolume_Type::Convex, [this, z = m_max_print_height + SceneEpsilon](const Vec3f &pt) { return pt.z() < z && Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_scene, to_2d(pt).cast()); }); case BuildVolume_Type::Invalid: @@ -322,10 +385,100 @@ BuildVolume::ObjectState BuildVolume::volume_state_bbox(const BoundingBoxf3& vol if (ignore_bottom) build_volume.min.z() = -std::numeric_limits::max(); return build_volume.max.z() <= - SceneEpsilon ? ObjectState::Below : - build_volume.contains(volume_bbox) ? ObjectState::Inside : + build_volume.contains(volume_bbox) ? ObjectState::Inside : build_volume.intersects(volume_bbox) ? ObjectState::Colliding : ObjectState::Outside; } +const BuildVolume::BuildExtruderVolume& BuildVolume::get_extruder_area_volume(int index) const +{ + assert(index >= 0 && index < m_extruder_volumes.size()); + return m_extruder_volumes[index]; +} + +BuildVolume::ObjectState BuildVolume::check_object_state_with_extruder_area(const indexed_triangle_set &its, const Transform3f &trafo, int index) const +{ + const BuildExtruderVolume& extruder_volume = get_extruder_area_volume(index); + ObjectState return_state = ObjectState::Inside; + + if (!extruder_volume.same_with_bed) { + switch (extruder_volume.type) { + case Type::Rectangle: + { + BoundingBox3Base build_volume = extruder_volume.bboxf.inflated(SceneEpsilon); + if (m_max_print_height == 0.0) + build_volume.max.z() = std::numeric_limits::max(); + BoundingBox3Base build_volumef(build_volume.min.cast(), build_volume.max.cast()); + + return_state = object_state_templ(its, trafo, false, [build_volumef](const Vec3f &pt) { return build_volumef.contains(pt); }); + break; + } + case Type::Circle: + { + Geometry::Circlef circle { unscaled(extruder_volume.circle.center), unscaled(extruder_volume.circle.radius + SceneEpsilon) }; + return_state = (m_max_print_height == 0.0) ? + object_state_templ(its, trafo, false, [circle](const Vec3f &pt) { return circle.contains(to_2d(pt)); }) : + object_state_templ(its, trafo, false, [circle, z = m_max_print_height + SceneEpsilon](const Vec3f &pt) { return pt.z() < z && circle.contains(to_2d(pt)); }); + break; + } + case Type::Invalid: + default: + break; + } + } + + if (return_state != ObjectState::Inside) + return_state = ObjectState::Limited; + + return return_state; +} + +BuildVolume::ObjectState BuildVolume::check_object_state_with_extruder_areas(const indexed_triangle_set &its, const Transform3f &trafo, std::vector& inside_extruders) const +{ + ObjectState result = ObjectState::Inside; + int extruder_area_count = get_extruder_area_count(); + inside_extruders.resize(extruder_area_count, true); + for (int index = 0; index < extruder_area_count; index++) + { + ObjectState state = check_object_state_with_extruder_area(its, trafo, index); + + if (state == ObjectState::Limited) { + inside_extruders[index] = false; + result = ObjectState::Limited; + } + } + + return result; +} + +BuildVolume::ObjectState BuildVolume::check_volume_bbox_state_with_extruder_area(const BoundingBoxf3& volume_bbox, int index) const +{ + const BuildExtruderVolume& extruder_volume = get_extruder_area_volume(index); + + if (extruder_volume.same_with_bed || extruder_volume.bboxf.contains(volume_bbox)) + return ObjectState::Inside; + else + return ObjectState::Limited; +} + +BuildVolume::ObjectState BuildVolume::check_volume_bbox_state_with_extruder_areas(const BoundingBoxf3& volume_bbox, std::vector& inside_extruders) const +{ + ObjectState result = ObjectState::Inside; + int extruder_area_count = get_extruder_area_count(); + inside_extruders.resize(extruder_area_count, true); + for (int index = 0; index < extruder_area_count; index++) + { + ObjectState state = check_volume_bbox_state_with_extruder_area(volume_bbox, index); + + if (state == ObjectState::Limited) { + inside_extruders[index] = false; + result = ObjectState::Limited; + } + } + + return result; +} + + bool BuildVolume::all_paths_inside(const GCodeProcessorResult& paths, const BoundingBoxf3& paths_bbox, bool ignore_bottom) const { auto move_valid = [](const GCodeProcessorResult::MoveVertex &move) { @@ -348,7 +501,7 @@ bool BuildVolume::all_paths_inside(const GCodeProcessorResult& paths, const Boun const Vec2f c = unscaled(m_circle.center); const float r = unscaled(m_circle.radius) + epsilon; const float r2 = sqr(r); - return m_max_print_height == 0.0 ? + return m_max_print_height == 0.0 ? std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, c, r2](const GCodeProcessorResult::MoveVertex &move) { return ! move_valid(move) || (to_2d(move.position) - c).squaredNorm() <= r2; }) : std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, c, r2, z = m_max_print_height + epsilon](const GCodeProcessorResult::MoveVertex& move) @@ -358,7 +511,7 @@ bool BuildVolume::all_paths_inside(const GCodeProcessorResult& paths, const Boun //FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently. case BuildVolume_Type::Custom: return m_max_print_height == 0.0 ? - std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, this](const GCodeProcessorResult::MoveVertex &move) + std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, this](const GCodeProcessorResult::MoveVertex &move) { return ! move_valid(move) || Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_bed, to_2d(move.position).cast()); }) : std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, this, z = m_max_print_height + epsilon](const GCodeProcessorResult::MoveVertex &move) { return ! move_valid(move) || (Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_bed, to_2d(move.position).cast()) && move.position.z() <= z); }); diff --git a/src/libslic3r/BuildVolume.hpp b/src/libslic3r/BuildVolume.hpp index f513356002..6bd39ceb6e 100644 --- a/src/libslic3r/BuildVolume.hpp +++ b/src/libslic3r/BuildVolume.hpp @@ -29,16 +29,24 @@ class BuildVolume { public: + struct BuildExtruderVolume { + bool same_with_bed{false}; + Type type{Type::Invalid}; + BoundingBox bbox; + BoundingBoxf3 bboxf; + Geometry::Circled circle; + }; // Initialized to empty, all zeros, Invalid. BuildVolume() {} // Initialize from PrintConfig::printable_area and PrintConfig::printable_height - BuildVolume(const std::vector &printable_area, const double printable_height); + BuildVolume(const std::vector &printable_area, const double printable_height, const std::vector> &extruder_areas); // Source data, unscaled coordinates. const std::vector& printable_area() const { return m_bed_shape; } double printable_height() const { return m_max_print_height; } - + const std::vector>& extruder_areas() const { return m_extruder_shapes; } + // Derived data BuildVolume_Type type() const { return m_type; } // Format the type for console output. @@ -69,9 +77,11 @@ public: Colliding, // Outside of the build volume means the object is ignored: Not printed and no error is shown. Outside, - // Completely below the print bed. The same as Outside, but an object with one printable part below the print bed + // Completely below the print bed. The same as Outside, but an object with one printable part below the print bed // and at least one part above the print bed is still printable. Below, + //in Limited area + Limited }; // 1) Tests called on the plater. @@ -94,12 +104,22 @@ public: // Called on initial G-code preview on OpenGL vertex buffer interleaved normals and vertices. bool all_paths_inside_vertices_and_normals_interleaved(const std::vector& paths, const Eigen::AlignedBox& bbox, bool ignore_bottom = true) const; + int get_extruder_area_count() const { return m_extruder_volumes.size(); } + const BuildExtruderVolume& get_extruder_area_volume(int index) const; + ObjectState check_object_state_with_extruder_area(const indexed_triangle_set &its, const Transform3f &trafo, int index) const; + ObjectState check_object_state_with_extruder_areas(const indexed_triangle_set &its, const Transform3f &trafo, std::vector& inside_extruders) const; + ObjectState check_volume_bbox_state_with_extruder_area(const BoundingBoxf3& volume_bbox, int index) const; + ObjectState check_volume_bbox_state_with_extruder_areas(const BoundingBoxf3& volume_bbox, std::vector& inside_extruders) const; + const std::pair, std::vector>& top_bottom_convex_hull_decomposition_scene() const { return m_top_bottom_convex_hull_decomposition_scene; } const std::pair, std::vector>& top_bottom_convex_hull_decomposition_bed() const { return m_top_bottom_convex_hull_decomposition_bed; } private: // Source definition of the print bed geometry (PrintConfig::printable_area) std::vector m_bed_shape; + //BBS: extruder shapes + std::vector> m_extruder_shapes; + std::vector m_extruder_volumes; // Source definition of the print volume height (PrintConfig::printable_height) double m_max_print_height { 0.f }; diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index 3da88e0e61..7c8d55341f 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -201,6 +201,7 @@ class Print; Pointfs printable_area; //BBS: add bed exclude area Pointfs bed_exclude_area; + std::vector extruder_areas; //BBS: add toolpath_outside bool toolpath_outside; //BBS: add object_label_enabled diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index f4e3a8133d..8f1653d5f4 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -3349,8 +3349,23 @@ ModelInstanceEPrintVolumeState ModelInstance::calc_print_volume_state(const Buil BuildVolume::ObjectState state; if (!build_volume.bounding_volume2d().inflated(BuildVolume::SceneEpsilon).overlap(bbox2d)) state = BuildVolume::ObjectState::Outside; - else - state = build_volume.object_state(vol->mesh().its, matrix.cast(), true /* may be below print bed */); + else { + switch(build_volume.type()) + { + case BuildVolume_Type::Rectangle: + { + state = build_volume.volume_state_bbox(bboxt); + break; + } + case BuildVolume_Type::Circle: + case BuildVolume_Type::Convex: + case BuildVolume_Type::Custom: + default: + state = build_volume.object_state(vol->mesh().its, matrix.cast(), true /* may be below print bed */); + break; + } + } + if (state == BuildVolume::ObjectState::Inside) // Volume is completely inside. inside_outside |= INSIDE; diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index e6acb9259b..9e99431e53 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -1227,6 +1227,7 @@ inline const ModelVolume* model_volume_find_by_id(const ModelVolumePtrs &model_v enum ModelInstanceEPrintVolumeState : unsigned char { ModelInstancePVS_Inside, + ModelInstancePVS_Limited, ModelInstancePVS_Partly_Outside, ModelInstancePVS_Fully_Outside, ModelInstanceNum_BedStates diff --git a/src/libslic3r/Support/TreeSupport3D.cpp b/src/libslic3r/Support/TreeSupport3D.cpp index 4301b0ac0c..266c274807 100644 --- a/src/libslic3r/Support/TreeSupport3D.cpp +++ b/src/libslic3r/Support/TreeSupport3D.cpp @@ -4020,7 +4020,7 @@ void generate_tree_support_3D(PrintObject &print_object, TreeSupport* tree_suppo Points bedpts = tree_support->m_machine_border.contour.points; Pointfs bedptsf; std::transform(bedpts.begin(), bedpts.end(), std::back_inserter(bedptsf), [](const Point &p) { return unscale(p); }); - BuildVolume build_volume{ bedptsf, tree_support->m_print_config->printable_height }; + BuildVolume build_volume{ bedptsf, tree_support->m_print_config->printable_height, {}}; TreeSupport3D::generate_support_areas(*print_object.print(), tree_support, build_volume, { idx }, throw_on_cancel); } diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index c50f2461b3..ad4ddda68c 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -251,7 +251,7 @@ void Bed3D::Axes::render() } //BBS: add part plate logic -bool Bed3D::set_shape(const Pointfs& printable_area, const double printable_height, const std::string& custom_model, bool force_as_custom, +bool Bed3D::set_shape(const Pointfs& printable_area, const double printable_height, std::vector extruder_areas, const std::string& custom_model, bool force_as_custom, const Vec2d& position, bool with_reset) { /*auto check_texture = [](const std::string& texture) { @@ -289,7 +289,7 @@ bool Bed3D::set_shape(const Pointfs& printable_area, const double printable_heig } //BBS: add position related logic - if (m_bed_shape == printable_area && m_build_volume.printable_height() == printable_height && m_type == type && m_model_filename == model_filename && position == m_position) + if (m_bed_shape == printable_area && m_build_volume.printable_height() == printable_height && m_type == type && m_model_filename == model_filename && position == m_position && m_extruder_shapes == extruder_areas) // No change, no need to update the UI. return false; @@ -297,16 +297,26 @@ bool Bed3D::set_shape(const Pointfs& printable_area, const double printable_heig BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(":current position {%1%,%2%}, new position {%3%, %4%}") % m_position.x() % m_position.y() % position.x() % position.y(); m_position = position; m_bed_shape = printable_area; + m_extruder_shapes = extruder_areas; if ((position(0) != 0) || (position(1) != 0)) { Pointfs new_bed_shape; for (const Vec2d& p : m_bed_shape) { Vec2d point(p(0) + m_position.x(), p(1) + m_position.y()); new_bed_shape.push_back(point); } - m_build_volume = BuildVolume { new_bed_shape, printable_height }; + std::vector new_extruder_shapes; + for (const std::vector& shape : m_extruder_shapes) { + std::vector new_extruder_shape; + for (const Vec2d& p : shape) { + Vec2d point(p(0) + m_position.x(), p(1) + m_position.y()); + new_extruder_shape.push_back(point); + } + new_extruder_shapes.push_back(new_extruder_shape); + } + m_build_volume = BuildVolume { new_bed_shape, printable_height, new_extruder_shapes }; } else - m_build_volume = BuildVolume { printable_area, printable_height }; + m_build_volume = BuildVolume { printable_area, printable_height, m_extruder_shapes }; m_type = type; //m_texture_filename = texture_filename; m_model_filename = model_filename; @@ -342,7 +352,7 @@ bool Bed3D::set_shape(const Pointfs& printable_area, const double printable_heig //BBS: add api to set position for partplate related bed void Bed3D::set_position(Vec2d& position) { - set_shape(m_bed_shape, m_build_volume.printable_height(), m_model_filename, false, position, false); + set_shape(m_bed_shape, m_build_volume.printable_height(), m_extruder_shapes, m_model_filename, false, position, false); } void Bed3D::set_axes_mode(bool origin) diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index fc4560ae72..ac9b10497e 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -115,6 +115,7 @@ private: //BBS: add part plate related logic Vec2d m_position{ Vec2d::Zero() }; std::vector m_bed_shape; + std::vector> m_extruder_shapes; bool m_is_dark = false; public: @@ -126,7 +127,7 @@ public: //FIXME if the build volume max print height is updated, this function still returns zero // as this class does not use it, thus there is no need to update the UI. // BBS - bool set_shape(const Pointfs& printable_area, const double printable_height, const std::string& custom_model, bool force_as_custom = false, + bool set_shape(const Pointfs& printable_area, const double printable_height, std::vector extruder_areas, const std::string& custom_model, bool force_as_custom = false, const Vec2d& position = Vec2d::Zero(), bool with_reset = true); void set_position(Vec2d& position); diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 6c74b837c5..df4c3ca53f 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -1067,15 +1067,15 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo auto volume_convex_mesh = [volume_sinking, &model](GLVolume& volume) -> const TriangleMesh& { return volume_sinking(volume) ? model.objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh() : *volume.convex_hull(); }; - ModelInstanceEPrintVolumeState overall_state = ModelInstancePVS_Inside; + ModelInstanceEPrintVolumeState overall_state = ModelInstancePVS_Fully_Outside; bool contained_min_one = false; //BBS: add instance judge logic, besides to original volume judge logic - std::map model_state; + //std::map model_state; GUI::PartPlate* curr_plate = GUI::wxGetApp().plater()->get_partplate_list().get_selected_plate(); const Pointfs& pp_bed_shape = curr_plate->get_shape(); - BuildVolume plate_build_volume(pp_bed_shape, build_volume.printable_height()); + BuildVolume plate_build_volume(pp_bed_shape, build_volume.printable_height(), build_volume.extruder_areas()); const std::vector& exclude_areas = curr_plate->get_exclude_areas(); for (GLVolume* volume : this->volumes) @@ -1090,14 +1090,27 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo //FIXME this test does not evaluate collision of a build volume bounding box with non-convex objects. const BoundingBoxf3& bb = volume_bbox(*volume); state = plate_build_volume.volume_state_bbox(bb); + if ((state == BuildVolume::ObjectState::Inside) && (build_volume.get_extruder_area_count() > 0)) + { + std::vector inside_extruders; + state = plate_build_volume.check_volume_bbox_state_with_extruder_areas(bb, inside_extruders); } break; case BuildVolume_Type::Circle: case BuildVolume_Type::Convex: //FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently. case BuildVolume_Type::Custom: - state = plate_build_volume.object_state(volume_convex_mesh(*volume).its, volume->world_matrix().cast(), volume_sinking(*volume)); + { + const indexed_triangle_set& convex_mesh_it = volume_convex_mesh(*volume).its; + const Transform3f trafo = volume->world_matrix().cast(); + state = plate_build_volume.object_state(convex_mesh_it, trafo, volume_sinking(*volume)); + if ((state == BuildVolume::ObjectState::Inside) && (build_volume.get_extruder_area_count() > 0)) + { + std::vector inside_extruders; + state = plate_build_volume.check_object_state_with_extruder_areas(convex_mesh_it, trafo, inside_extruders); + } break; + } default: // Ignore, don't produce any collision. state = BuildVolume::ObjectState::Inside; @@ -1106,22 +1119,23 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo assert(state != BuildVolume::ObjectState::Below); } - int64_t comp_id = ((int64_t)volume->composite_id.object_id << 32) | ((int64_t)volume->composite_id.instance_id); - volume->is_outside = state != BuildVolume::ObjectState::Inside; - //volume->partly_inside = (state == BuildVolume::ObjectState::Colliding); + //int64_t comp_id = ((int64_t)volume->composite_id.object_id << 32) | ((int64_t)volume->composite_id.instance_id); + volume->is_outside = (state != BuildVolume::ObjectState::Inside && state != BuildVolume::ObjectState::Limited); + volume->partly_inside = (state == BuildVolume::ObjectState::Colliding); if (volume->printable) { - if (overall_state == ModelInstancePVS_Inside && volume->is_outside) { - overall_state = ModelInstancePVS_Fully_Outside; - } - - if (overall_state == ModelInstancePVS_Fully_Outside && volume->is_outside && (state == BuildVolume::ObjectState::Colliding)) + if (state == BuildVolume::ObjectState::Colliding) { overall_state = ModelInstancePVS_Partly_Outside; } + else if ((state == BuildVolume::ObjectState::Limited) && (overall_state != ModelInstancePVS_Partly_Outside)) + overall_state = ModelInstancePVS_Limited; + else if ((state == BuildVolume::ObjectState::Inside) && (overall_state == ModelInstancePVS_Fully_Outside)) { + overall_state = ModelInstancePVS_Fully_Outside; + } contained_min_one |= !volume->is_outside; } - ModelInstanceEPrintVolumeState volume_state; + /*ModelInstanceEPrintVolumeState volume_state; //if (volume->is_outside && (plate_build_volume.bounding_volume().intersects(volume->bounding_box()))) if (volume->is_outside && (state == BuildVolume::ObjectState::Colliding)) volume_state = ModelInstancePVS_Partly_Outside; @@ -1150,11 +1164,11 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo if (model_state[comp_id] == ModelInstancePVS_Partly_Outside) { overall_state = ModelInstancePVS_Partly_Outside; BOOST_LOG_TRIVIAL(debug) << "instance includes " << volume->name << " is partially outside of bed"; - } + }*/ } } - for (GLVolume* volume : this->volumes) + /*for (GLVolume* volume : this->volumes) { if (! volume->is_modifier && (volume->shader_outside_printer_detection_enabled || (! volume->is_wipe_tower && volume->composite_id.volume_id >= 0))) { @@ -1168,7 +1182,7 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo volume->partly_inside = false; } } - } + }*/ if (out_state != nullptr) *out_state = overall_state; diff --git a/src/slic3r/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp index 50e8a548e0..4cc13f3c0a 100644 --- a/src/slic3r/GUI/BedShapeDialog.cpp +++ b/src/slic3r/GUI/BedShapeDialog.cpp @@ -2,7 +2,7 @@ #include "GUI_App.hpp" #include "OptionsGroup.hpp" -#include +#include #include #include #include @@ -25,7 +25,7 @@ namespace GUI { BedShape::BedShape(const Pointfs& points) { - m_build_volume = { points, 0. }; + m_build_volume = { points, 0.f, {} }; } static std::string get_option_label(BedShape::Parameter param) @@ -283,7 +283,7 @@ ConfigOptionsGroupShp BedShapePanel::init_shape_options_page(const wxString& tit optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) { update_shape(); }; - + m_optgroups.push_back(optgroup); // panel->SetSizerAndFit(optgroup->sizer); m_shape_options_book->AddPage(panel, title); @@ -522,7 +522,7 @@ void BedShapePanel::update_shape() { double diameter; try { diameter = boost::any_cast(opt_group->get_value("diameter")); } - catch (const std::exception & /* e */) { return; } + catch (const std::exception & /* e */) { return; } if (diameter == 0.0) return ; auto r = diameter / 2; diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 8f52d59220..412bb101db 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -1008,6 +1008,7 @@ void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& pr Pointfs printable_area; //BBS: add bed exclude area Pointfs bed_exclude_area = Pointfs(); + std::vector extruder_areas; std::string texture; std::string model; @@ -1027,7 +1028,10 @@ void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& pr if (!gcode_result.bed_exclude_area.empty()) bed_exclude_area = gcode_result.bed_exclude_area; - wxGetApp().plater()->set_bed_shape(printable_area, bed_exclude_area, gcode_result.printable_height, texture, model, gcode_result.printable_area.empty()); + if (!gcode_result.extruder_areas.empty()) + extruder_areas = gcode_result.extruder_areas; + + wxGetApp().plater()->set_bed_shape(printable_area, bed_exclude_area, gcode_result.printable_height, extruder_areas, texture, model, gcode_result.printable_area.empty()); } /*else { // adjust printbed size in dependence of toolpaths bbox diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 90678a58f0..d49159f781 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2810,8 +2810,10 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re const bool contained_min_one = m_volumes.check_outside_state(m_bed.build_volume(), &state); const bool partlyOut = (state == ModelInstanceEPrintVolumeState::ModelInstancePVS_Partly_Outside); const bool fullyOut = (state == ModelInstanceEPrintVolumeState::ModelInstancePVS_Fully_Outside); + const bool objectLimited = (state == ModelInstanceEPrintVolumeState::ModelInstancePVS_Limited); _set_warning_notification(EWarning::ObjectClashed, partlyOut); + _set_warning_notification(EWarning::ObjectLimited, objectLimited); //BBS: turn off the warning when fully outside //_set_warning_notification(EWarning::ObjectOutside, fullyOut); if (printer_technology != ptSLA || !contained_min_one) @@ -2823,6 +2825,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re else { _set_warning_notification(EWarning::ObjectOutside, false); _set_warning_notification(EWarning::ObjectClashed, false); + _set_warning_notification(EWarning::ObjectLimited, false); _set_warning_notification(EWarning::SlaSupportsOutside, false); post_event(Event(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, false)); } @@ -9650,6 +9653,11 @@ void GLCanvas3D::_set_warning_notification_if_needed(EWarning warning) _set_warning_notification(warning, show); } +std::string object_limited_text = _u8L("An object is laid on the left/right extruder only area.\n" + "Please make sure the filaments used by this object on this area are not mapped to the other extruders."); +std::string object_clashed_text = _u8L("An object is laid over the boundary of plate or exceeds the height limit.\n" + "Please solve the problem by moving it totally on or off the plate, and confirming that the height is within the build volume."); + void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) { enum ErrorType{ @@ -9686,10 +9694,12 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) case EWarning::SlaSupportsOutside: text = ("SLA supports outside the print area were detected."); error = ErrorType::PLATER_ERROR; break; case EWarning::SomethingNotShown: text = _u8L("Only the object being edited is visible."); break; case EWarning::ObjectClashed: - text = _u8L("An object is laid over the plate boundaries or exceeds the height limit.\n" - "Please solve the problem by moving it totally on or off the plate, and confirming that the height is within the build volume."); + text = object_clashed_text; error = ErrorType::PLATER_ERROR; break; + case EWarning::ObjectLimited: + text = object_limited_text; + break; } //BBS: this may happened when exit the app, plater is null if (!wxGetApp().plater()) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 3845ef462c..61fcf7dede 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -380,6 +380,7 @@ class GLCanvas3D SlaSupportsOutside, SomethingNotShown, ObjectClashed, + ObjectLimited, GCodeConflict, ToolHeightOutside }; diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 2672f74376..f0b9565c38 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -846,7 +846,7 @@ void MainFrame::update_layout() { m_main_sizer->Add(m_plater, 1, wxEXPAND); //BBS: add bed exclude area - m_plater->set_bed_shape({ { 0.0, 0.0 }, { 200.0, 0.0 }, { 200.0, 200.0 }, { 0.0, 200.0 } }, {}, 0.0, {}, {}, true); + m_plater->set_bed_shape({ { 0.0, 0.0 }, { 200.0, 0.0 }, { 200.0, 200.0 }, { 0.0, 200.0 } }, {}, 0.0, {}, {}, {}, true); m_plater->get_collapse_toolbar().set_enabled(false); m_plater->enable_sidebar(false); m_plater->Show(); diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index 13b5de6b10..086ee1a6f8 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -2645,7 +2645,7 @@ void PartPlate::generate_exclude_polygon(ExPolygon &exclude_polygon) exclude_polygon.contour.make_counter_clockwise(); } -bool PartPlate::set_shape(const Pointfs& shape, const Pointfs& exclude_areas, Vec2d position, float height_to_lid, float height_to_rod) +bool PartPlate::set_shape(const Pointfs& shape, const Pointfs& exclude_areas, const std::vector& extruder_areas, Vec2d position, float height_to_lid, float height_to_rod) { Pointfs new_shape, new_exclude_areas; for (const Vec2d& p : shape) { @@ -2655,6 +2655,18 @@ bool PartPlate::set_shape(const Pointfs& shape, const Pointfs& exclude_areas, Ve for (const Vec2d& p : exclude_areas) { new_exclude_areas.push_back(Vec2d(p.x() + position.x(), p.y() + position.y())); } + + std::vector new_extruder_areas; + for (const Pointfs& shape : extruder_areas) { + Pointfs new_extruder_area; + for (const Vec2d& p : shape) { + Vec2d point(p(0) + position.x(), p(1) + position.y()); + new_extruder_area.push_back(point); + } + new_extruder_areas.push_back(new_extruder_area); + } + m_extruder_areas = std::move(new_extruder_areas); + if ((m_shape == new_shape)&&(m_exclude_area == new_exclude_areas) &&(m_height_to_lid == height_to_lid)&&(m_height_to_rod == height_to_rod)) { BOOST_LOG_TRIVIAL(info) << "PartPlate same shape, skip directly"; @@ -3629,7 +3641,7 @@ void PartPlateList::reset_size(int width, int depth, int height, bool reload_obj m_plate_height = height; update_all_plates_pos_and_size(false, false, true); if (update_shapes) { - set_shapes(m_shape, m_exclude_areas, m_logo_texture_filename, m_height_to_lid, m_height_to_rod); + set_shapes(m_shape, m_exclude_areas, m_extruder_areas, m_logo_texture_filename, m_height_to_lid, m_height_to_rod); } if (reload_objects) reload_all_objects(); @@ -3714,7 +3726,7 @@ void PartPlateList::reinit() //reset plate 0's position Vec2d pos = compute_shape_position(0, m_plate_cols); - m_plate_list[0]->set_shape(m_shape, m_exclude_areas, pos, m_height_to_lid, m_height_to_rod); + m_plate_list[0]->set_shape(m_shape, m_exclude_areas, m_extruder_areas, pos, m_height_to_lid, m_height_to_rod); //reset unprintable plate's position Vec3d origin2 = compute_origin_for_unprintable(); unprintable_plate.set_pos_and_size(origin2, m_plate_width, m_plate_depth, m_plate_height, false); @@ -3764,7 +3776,7 @@ int PartPlateList::create_plate(bool adjust_position) plate->set_index(new_index); Vec2d pos = compute_shape_position(new_index, cols); - plate->set_shape(m_shape, m_exclude_areas, pos, m_height_to_lid, m_height_to_rod); + plate->set_shape(m_shape, m_exclude_areas, m_extruder_areas, pos, m_height_to_lid, m_height_to_rod); m_plate_list.emplace_back(plate); update_plate_cols(); if (old_cols != cols) @@ -3772,7 +3784,7 @@ int PartPlateList::create_plate(bool adjust_position) BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(":old_cols %1% -> new_cols %2%") % old_cols % cols; //update the origin of each plate update_all_plates_pos_and_size(adjust_position, false); - set_shapes(m_shape, m_exclude_areas, m_logo_texture_filename, m_height_to_lid, m_height_to_rod); + set_shapes(m_shape, m_exclude_areas, m_extruder_areas, m_logo_texture_filename, m_height_to_lid, m_height_to_rod); if (m_plater) { Vec2d pos = compute_shape_position(m_current_plate, cols); @@ -3943,7 +3955,7 @@ int PartPlateList::delete_plate(int index) //update render shapes Vec2d pos = compute_shape_position(i, m_plate_cols); - plate->set_shape(m_shape, m_exclude_areas, pos, m_height_to_lid, m_height_to_rod); + plate->set_shape(m_shape, m_exclude_areas, m_extruder_areas, pos, m_height_to_lid, m_height_to_rod); } //update current_plate if delete current @@ -3966,7 +3978,7 @@ int PartPlateList::delete_plate(int index) { //update the origin of each plate update_all_plates_pos_and_size(); - set_shapes(m_shape, m_exclude_areas, m_logo_texture_filename, m_height_to_lid, m_height_to_rod); + set_shapes(m_shape, m_exclude_areas, m_extruder_areas, m_logo_texture_filename, m_height_to_lid, m_height_to_rod); } else { @@ -5063,11 +5075,12 @@ void PartPlateList::select_plate_view() m_plater->get_camera().select_view("topfront"); } -bool PartPlateList::set_shapes(const Pointfs& shape, const Pointfs& exclude_areas, const std::string& texture_filename, float height_to_lid, float height_to_rod) +bool PartPlateList::set_shapes(const Pointfs& shape, const Pointfs& exclude_areas, const std::vector& extruder_areas, const std::string& texture_filename, float height_to_lid, float height_to_rod) { const std::lock_guard local_lock(m_plates_mutex); m_shape = shape; m_exclude_areas = exclude_areas; + m_extruder_areas = extruder_areas; m_height_to_lid = height_to_lid; m_height_to_rod = height_to_rod; @@ -5081,7 +5094,7 @@ bool PartPlateList::set_shapes(const Pointfs& shape, const Pointfs& exclude_area Vec2d pos; pos = compute_shape_position(i, m_plate_cols); - plate->set_shape(shape, exclude_areas, pos, height_to_lid, height_to_rod); + plate->set_shape(shape, exclude_areas, extruder_areas, pos, height_to_lid, height_to_rod); } is_load_bedtype_textures = false; //reload textures calc_bounding_boxes(); @@ -5260,7 +5273,7 @@ int PartPlateList::rebuild_plates_after_deserialize(std::vector& previous_ } update_plate_cols(); update_all_plates_pos_and_size(false, false, false, false); - set_shapes(m_shape, m_exclude_areas, m_logo_texture_filename, m_height_to_lid, m_height_to_rod); + set_shapes(m_shape, m_exclude_areas, m_extruder_areas, m_logo_texture_filename, m_height_to_lid, m_height_to_rod); for (unsigned int i = 0; i < (unsigned int)m_plate_list.size(); ++i) { bool need_reset_print = false; @@ -5592,7 +5605,7 @@ int PartPlateList::load_gcode_files() //BoundingBoxf3 print_volume = m_plate_list[i]->get_bounding_box(false); //print_volume.max(2) = this->m_plate_height; //print_volume.min(2) = -1e10; - m_model->update_print_volume_state({m_plate_list[i]->get_shape(), (double)this->m_plate_height }); + m_model->update_print_volume_state({m_plate_list[i]->get_shape(), (double)this->m_plate_height, m_plate_list[i]->get_extruder_areas() }); if (!m_plate_list[i]->load_gcode_from_file(m_plate_list[i]->m_gcode_path_from_3mf)) ret ++; diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index 54a5ca6469..dfe1a2f3c4 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -120,6 +120,7 @@ private: Pointfs m_shape; Pointfs m_exclude_area; + std::vector m_extruder_areas; BoundingBoxf3 m_bounding_box; BoundingBoxf3 m_extended_bounding_box; mutable std::vector m_exclude_bounding_box; @@ -363,7 +364,8 @@ public: /*rendering related functions*/ const Pointfs& get_shape() const { return m_shape; } - bool set_shape(const Pointfs& shape, const Pointfs& exclude_areas, Vec2d position, float height_to_lid, float height_to_rod); + bool set_shape(const Pointfs& shape, const Pointfs& exclude_areas, const std::vector& extruder_areas, Vec2d position, float height_to_lid, float height_to_rod); + const std::vector& get_extruder_areas() const { return m_extruder_areas; } bool contains(const Vec3d& point) const; bool contains(const GLVolume& v) const; bool contains(const BoundingBoxf3& bb) const; @@ -562,6 +564,7 @@ class PartPlateList : public ObjectBase PartPlate unprintable_plate; Pointfs m_shape; Pointfs m_exclude_areas; + std::vector m_extruder_areas; BoundingBoxf3 m_bounding_box; bool m_intialized; std::string m_logo_texture_filename; @@ -821,7 +824,7 @@ public: int select_plate_by_obj(int obj_index, int instance_index); void calc_bounding_boxes(); void select_plate_view(); - bool set_shapes(const Pointfs& shape, const Pointfs& exclude_areas, const std::string& custom_texture, float height_to_lid, float height_to_rod); + bool set_shapes(const Pointfs& shape, const Pointfs& exclude_areas, const std::vector& extruder_areas, const std::string& custom_texture, float height_to_lid, float height_to_rod); void set_hover_id(int id); void reset_hover_id(); bool intersects(const BoundingBoxf3 &bb); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index b31bbc4fa4..3a4d40408d 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2880,7 +2880,7 @@ struct Plater::priv // fills the m_bed.m_grid_lines and sets m_bed.m_origin. // Sets m_bed.m_polygon to limit the object placement. //BBS: add bed exclude area - void set_bed_shape(const Pointfs& shape, const Pointfs& exclude_areas, const double printable_height, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom = false); + void set_bed_shape(const Pointfs& shape, const Pointfs& exclude_areas, const double printable_height, std::vector extruder_areas, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom = false); bool can_delete() const; bool can_delete_all() const; @@ -3034,8 +3034,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) , main_frame(main_frame) //BBS: add bed_exclude_area , config(Slic3r::DynamicPrintConfig::new_from_defaults_keys({ - "printable_area", "bed_exclude_area", "bed_custom_texture", "bed_custom_model", "print_sequence", - "extruder_clearance_radius", "extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod", + "printable_area", "bed_exclude_area", "extruder_printable_area", "bed_custom_texture", "bed_custom_model", "print_sequence", + "extruder_clearance_radius", + "extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod", "nozzle_height", "skirt_type", "skirt_loops", "skirt_speed","min_skirt_length", "skirt_distance", "skirt_start_angle", "brim_width", "brim_object_gap", "brim_type", "nozzle_diameter", "single_extruder_multi_material", "preferred_orientation", "enable_prime_tower", "wipe_tower_x", "wipe_tower_y", "prime_tower_width", "prime_tower_brim_width", "prime_volume", @@ -5450,7 +5451,7 @@ void Plater::priv::update_print_volume_state() { //BBS: use the plate's bounding box instead of the bed's PartPlate* pp = partplate_list.get_curr_plate(); - BuildVolume build_volume(pp->get_shape(), this->bed.build_volume().printable_height()); + BuildVolume build_volume(pp->get_shape(), this->bed.build_volume().printable_height(), this->bed.build_volume().extruder_areas()); this->model.update_print_volume_state(build_volume); } @@ -8464,7 +8465,7 @@ bool Plater::priv::show_publish_dlg(bool show) } //BBS: add bed exclude area -void Plater::priv::set_bed_shape(const Pointfs& shape, const Pointfs& exclude_areas, const double printable_height, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom) +void Plater::priv::set_bed_shape(const Pointfs& shape, const Pointfs& exclude_areas, const double printable_height, std::vector extruder_areas, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom) { //Orca: reduce resolution for large bed printer BoundingBoxf bed_size = get_extents(shape); @@ -8475,7 +8476,7 @@ void Plater::priv::set_bed_shape(const Pointfs& shape, const Pointfs& exclude_ar //BBS: add shape position Vec2d shape_position = partplate_list.get_current_shape_position(); - bool new_shape = bed.set_shape(shape, printable_height, custom_model, force_as_custom, shape_position); + bool new_shape = bed.set_shape(shape, printable_height, extruder_areas, custom_model, force_as_custom, shape_position); float prev_height_lid, prev_height_rod; partplate_list.get_height_limits(prev_height_lid, prev_height_rod); @@ -8499,11 +8500,11 @@ void Plater::priv::set_bed_shape(const Pointfs& shape, const Pointfs& exclude_ar //Pointfs& exclude_areas = config->option("bed_exclude_area")->values; partplate_list.reset_size(max.x() - min.x() - Bed3D::Axes::DefaultTipRadius, max.y() - min.y() - Bed3D::Axes::DefaultTipRadius, z); - partplate_list.set_shapes(shape, exclude_areas, custom_texture, height_to_lid, height_to_rod); + partplate_list.set_shapes(shape, exclude_areas, extruder_areas, custom_texture, height_to_lid, height_to_rod); Vec2d new_shape_position = partplate_list.get_current_shape_position(); if (shape_position != new_shape_position) - bed.set_shape(shape, printable_height, custom_model, force_as_custom, new_shape_position); + bed.set_shape(shape, printable_height, extruder_areas, custom_model, force_as_custom, new_shape_position); } } @@ -13602,14 +13603,15 @@ void Plater::set_bed_shape() const //BBS: add bed exclude areas p->config->option("bed_exclude_area")->values, p->config->option("printable_height")->value, + p->config->option("extruder_printable_area")->values, p->config->option("bed_custom_texture")->value.empty() ? texture_filename : p->config->option("bed_custom_texture")->value, p->config->option("bed_custom_model")->value); } //BBS: add bed exclude area -void Plater::set_bed_shape(const Pointfs& shape, const Pointfs& exclude_area, const double printable_height, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom) const +void Plater::set_bed_shape(const Pointfs& shape, const Pointfs& exclude_area, const double printable_height, std::vector extruder_areas, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom) const { - p->set_bed_shape(make_counter_clockwise(shape), exclude_area, printable_height, custom_texture, custom_model, force_as_custom); + p->set_bed_shape(make_counter_clockwise(shape), exclude_area, printable_height, extruder_areas, custom_texture, custom_model, force_as_custom); } void Plater::force_filament_colors_update() @@ -14328,13 +14330,16 @@ int Plater::select_sliced_plate(int plate_index) return ret; } +extern std::string object_limited_text; +extern std::string object_clashed_text; void Plater::validate_current_plate(bool& model_fits, bool& validate_error) { - model_fits = p->view3D->get_canvas3d()->check_volumes_outside_state() != ModelInstancePVS_Partly_Outside; + ModelInstanceEPrintVolumeState state = p->view3D->get_canvas3d()->check_volumes_outside_state(); + model_fits = (state != ModelInstancePVS_Partly_Outside); validate_error = false; if (p->printer_technology == ptFFF) { - std::string plater_text = _u8L("An object is laid over the boundary of plate or exceeds the height limit.\n" - "Please solve the problem by moving it totally on or off the plate, and confirming that the height is within the build volume.");; + //std::string plater_text = _u8L("An object is laid over the boundary of plate or exceeds the height limit.\n" + // "Please solve the problem by moving it totally on or off the plate, and confirming that the height is within the build volume.");; StringObjectException warning; Polygons polygons; std::vector> height_polygons; @@ -14369,10 +14374,17 @@ void Plater::validate_current_plate(bool& model_fits, bool& validate_error) } if (!model_fits) { - p->notification_manager->push_plater_error_notification(plater_text); + p->notification_manager->push_plater_error_notification(object_clashed_text); } else { - p->notification_manager->close_plater_error_notification(plater_text); + p->notification_manager->close_plater_error_notification(object_clashed_text); + } + + if (state == ModelInstancePVS_Limited) { + p->notification_manager->push_plater_warning_notification(object_limited_text); + } + else { + p->notification_manager->close_plater_warning_notification(object_limited_text); } } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 93d32eddb1..ad38164ce7 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -664,7 +664,7 @@ public: void update_flush_volume_matrix(size_t old_nozzle_size, size_t new_nozzle_size); //BBS: add bed exclude area void set_bed_shape() const; - void set_bed_shape(const Pointfs& shape, const Pointfs& exclude_area, const double printable_height, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom = false) const; + void set_bed_shape(const Pointfs& shape, const Pointfs& exclude_area, const double printable_height, std::vector extruder_areas, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom = false) const; const NotificationManager* get_notification_manager() const; NotificationManager* get_notification_manager(); diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index 0b2865e459..5db55471a2 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -987,6 +987,7 @@ bool CalibUtils::get_pa_k_n_value_by_cali_idx(const MachineObject *obj, int cali bool CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &full_config, const Calib_Params ¶ms, wxString &error_message) { Pointfs bedfs = make_counter_clockwise(full_config.opt("printable_area")->values); + std::vector extruder_areas = full_config.option("extruder_printable_area")->values; double print_height = full_config.opt_float("printable_height"); double current_width = bedfs[2].x() - bedfs[0].x(); double current_depth = bedfs[2].y() - bedfs[0].y(); @@ -1033,7 +1034,7 @@ bool CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f int print_index; part_plate->get_print(&print, &gcode_result, &print_index); - BuildVolume build_volume(bedfs, print_height); + BuildVolume build_volume(bedfs, print_height, extruder_areas); unsigned int count = model->update_print_volume_state(build_volume); if (count == 0) { error_message = _L("Unable to calibrate: maybe because the set calibration value range is too large, or the step is too small");