diff --git a/include/InsetOrderOptimizer.h b/include/InsetOrderOptimizer.h index e813a134af..a0734c3ea6 100644 --- a/include/InsetOrderOptimizer.h +++ b/include/InsetOrderOptimizer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Ultimaker B.V. +// Copyright (c) 2024 Ultimaker B.V. // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef INSET_ORDER_OPTIMIZER_H @@ -45,6 +45,8 @@ class InsetOrderOptimizer const int extruder_nr, const GCodePathConfig& inset_0_non_bridge_config, const GCodePathConfig& inset_X_non_bridge_config, + const GCodePathConfig& inset_0_roofing_config, + const GCodePathConfig& inset_X_roofing_config, const GCodePathConfig& inset_0_bridge_config, const GCodePathConfig& inset_X_bridge_config, const bool retract_before_outer_wall, @@ -92,6 +94,8 @@ class InsetOrderOptimizer const size_t extruder_nr_; const GCodePathConfig& inset_0_non_bridge_config_; const GCodePathConfig& inset_X_non_bridge_config_; + const GCodePathConfig& inset_0_roofing_config_; + const GCodePathConfig& inset_X_roofing_config_; const GCodePathConfig& inset_0_bridge_config_; const GCodePathConfig& inset_X_bridge_config_; const bool retract_before_outer_wall_; diff --git a/include/LayerPlan.h b/include/LayerPlan.h index 1d3b3628a3..34173ef331 100644 --- a/include/LayerPlan.h +++ b/include/LayerPlan.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef LAYER_PLAN_H @@ -96,6 +96,7 @@ class LayerPlan : public NoCopy coord_t comb_move_inside_distance_; //!< Whenever using the minimum boundary for combing it tries to move the coordinates inside by this distance after calculating the combing. Polygons bridge_wall_mask_; //!< The regions of a layer part that are not supported, used for bridging Polygons overhang_mask_; //!< The regions of a layer part where the walls overhang + Polygons roofing_mask_; //!< The regions of a layer part where the walls are exposed to the air const std::vector fan_speed_layer_time_settings_per_extruder_; @@ -257,6 +258,13 @@ class LayerPlan : public NoCopy */ void setOverhangMask(const Polygons& polys); + /*! + * Set roofing_mask. + * + * \param polys The areas of the part currently being processed that will require roofing. + */ + void setRoofingMask(const Polygons& polys); + /*! * Travel to a certain point, with all of the procedures necessary to do so. * @@ -414,6 +422,7 @@ class LayerPlan : public NoCopy const Point2LL& p1, const Settings& settings, const GCodePathConfig& non_bridge_config, + const GCodePathConfig& roofing_config, const GCodePathConfig& bridge_config, double flow, const Ratio width_factor, @@ -441,6 +450,7 @@ class LayerPlan : public NoCopy int start_idx, const Settings& settings, const GCodePathConfig& non_bridge_config, + const GCodePathConfig& roofing_config, const GCodePathConfig& bridge_config, coord_t wall_0_wipe_dist, double flow_ratio, @@ -470,6 +480,7 @@ class LayerPlan : public NoCopy int start_idx, const Settings& settings, const GCodePathConfig& non_bridge_config, + const GCodePathConfig& roofing_config, const GCodePathConfig& bridge_config, coord_t wall_0_wipe_dist, double flow_ratio, @@ -502,6 +513,7 @@ class LayerPlan : public NoCopy const Polygons& walls, const Settings& settings, const GCodePathConfig& non_bridge_config, + const GCodePathConfig& roofing_config, const GCodePathConfig& bridge_config, const ZSeamConfig& z_seam_config = ZSeamConfig(), coord_t wall_0_wipe_dist = 0, @@ -625,7 +637,7 @@ class LayerPlan : public NoCopy return start_idx; } - Polygons air_below(bridge_wall_mask_.unionPolygons(overhang_mask_)); + const auto air_below = bridge_wall_mask_.unionPolygons(overhang_mask_); unsigned curr_idx = start_idx; diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index bbb4b7c10c..4289026f86 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #include "FffGcodeWriter.h" @@ -690,6 +690,8 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) config, config, config, + config, + config, retract_before_outer_wall, wipe_dist, wipe_dist, @@ -851,6 +853,8 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) config, config, config, + config, + config, retract_before_outer_wall, wipe_dist, wipe_dist, @@ -1043,6 +1047,8 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) config, config, config, + config, + config, retract_before_outer_wall, wipe_dist, wipe_dist, @@ -2239,6 +2245,8 @@ bool FffGcodeWriter::processSingleLayerInfill( mesh_config.infill_config[0], mesh_config.infill_config[0], mesh_config.infill_config[0], + mesh_config.infill_config[0], + mesh_config.infill_config[0], retract_before_outer_wall, wipe_dist, wipe_dist, @@ -2587,6 +2595,28 @@ bool FffGcodeWriter::processInsets( Polygons overhang_region = part.outline.offset(-half_outer_wall_width).difference(outlines_below.offset(10 + overhang_width - half_outer_wall_width)).offset(10); gcode_layer.setOverhangMask(overhang_region); } + + const auto roofing_mask = [&gcode_layer, &mesh, &boundaryBox]() -> Polygons + { + const size_t roofing_layer_count = std::min(mesh.settings.get("roofing_layer_count"), mesh.settings.get("top_layers")); + + if (gcode_layer.getLayerNr() + roofing_layer_count >= mesh.layers.size()) + { + return Polygons(); + } + + auto roofing_mask = Polygons(); + for (const auto& layer_part : mesh.layers[gcode_layer.getLayerNr() + roofing_layer_count].parts) + { + if (boundaryBox.hit(layer_part.boundaryBox)) + { + roofing_mask.add(layer_part.outline); + } + } + return roofing_mask.offset(100); + }(); + + gcode_layer.setRoofingMask(roofing_mask); } else { @@ -2594,6 +2624,8 @@ bool FffGcodeWriter::processInsets( gcode_layer.setBridgeWallMask(Polygons()); // clear to disable overhang detection gcode_layer.setOverhangMask(Polygons()); + // clear to disable use of roofing settings + gcode_layer.setRoofingMask(Polygons()); } if (spiralize && extruder_nr == mesh.settings.get("wall_0_extruder_nr").extruder_nr_ && ! part.spiral_wall.empty()) @@ -2611,16 +2643,11 @@ bool FffGcodeWriter::processInsets( else { // Print the spiral walls of other parts as single walls without Z gradient. - gcode_layer.addWalls(part.spiral_wall, mesh.settings, mesh_config.inset0_config, mesh_config.inset0_config); + gcode_layer.addWalls(part.spiral_wall, mesh.settings, mesh_config.inset0_config, mesh_config.inset0_config, mesh_config.inset0_config); } } else { - // TODO use roofing config for layers-parts that are exposed to air - auto use_roofing_config = false; - const GCodePathConfig& inset0_config = use_roofing_config ? mesh_config.inset0_roofing_config : mesh_config.inset0_config; - const GCodePathConfig& insetX_config = use_roofing_config ? mesh_config.insetX_roofing_config : mesh_config.insetX_config; - // Main case: Optimize the insets with the InsetOrderOptimizer. const coord_t wall_x_wipe_dist = 0; const ZSeamConfig z_seam_config( @@ -2634,8 +2661,10 @@ bool FffGcodeWriter::processInsets( gcode_layer, mesh.settings, extruder_nr, - inset0_config, - insetX_config, + mesh_config.inset0_config, + mesh_config.insetX_config, + mesh_config.inset0_roofing_config, + mesh_config.insetX_roofing_config, mesh_config.bridge_inset0_config, mesh_config.bridge_insetX_config, mesh.settings.get("travel_retract_before_outer_wall"), @@ -3061,6 +3090,8 @@ void FffGcodeWriter::processSkinPrintFeature( config, config, config, + config, + config, retract_before_outer_wall, wipe_dist, wipe_dist, @@ -3324,6 +3355,8 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer config, config, config, + config, + config, retract_before_outer_wall, wipe_dist, wipe_dist, @@ -3500,6 +3533,8 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer config, config, config, + config, + config, retract_before_outer_wall, wipe_dist, wipe_dist, @@ -3636,6 +3671,8 @@ bool FffGcodeWriter::addSupportRoofsToGCode( config, config, config, + config, + config, retract_before_outer_wall, wipe_dist, wipe_dist, @@ -3747,6 +3784,8 @@ bool FffGcodeWriter::addSupportBottomsToGCode(const SliceDataStorage& storage, L config, config, config, + config, + config, retract_before_outer_wall, wipe_dist, wipe_dist, diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index 88a550c11f..976504cd6a 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #include "InsetOrderOptimizer.h" @@ -40,6 +40,8 @@ InsetOrderOptimizer::InsetOrderOptimizer( const int extruder_nr, const GCodePathConfig& inset_0_non_bridge_config, const GCodePathConfig& inset_X_non_bridge_config, + const GCodePathConfig& inset_0_roofing_config, + const GCodePathConfig& inset_X_roofing_config, const GCodePathConfig& inset_0_bridge_config, const GCodePathConfig& inset_X_bridge_config, const bool retract_before_outer_wall, @@ -56,6 +58,8 @@ InsetOrderOptimizer::InsetOrderOptimizer( , extruder_nr_(extruder_nr) , inset_0_non_bridge_config_(inset_0_non_bridge_config) , inset_X_non_bridge_config_(inset_X_non_bridge_config) + , inset_0_roofing_config_(inset_0_roofing_config) + , inset_X_roofing_config_(inset_X_roofing_config) , inset_0_bridge_config_(inset_0_bridge_config) , inset_X_bridge_config_(inset_X_bridge_config) , retract_before_outer_wall_(retract_before_outer_wall) @@ -114,23 +118,26 @@ bool InsetOrderOptimizer::addToLayer() for (const PathOrdering& path : order_optimizer.paths_) { if (path.vertices_->empty()) + { continue; + } const bool is_outer_wall = path.vertices_->inset_idx_ == 0; // or thin wall 'gap filler' const bool is_gap_filler = path.vertices_->is_odd_; const GCodePathConfig& non_bridge_config = is_outer_wall ? inset_0_non_bridge_config_ : inset_X_non_bridge_config_; + const GCodePathConfig& roofing_config = is_outer_wall ? inset_0_roofing_config_ : inset_X_roofing_config_; const GCodePathConfig& bridge_config = is_outer_wall ? inset_0_bridge_config_ : inset_X_bridge_config_; const coord_t wipe_dist = is_outer_wall && ! is_gap_filler ? wall_0_wipe_dist_ : wall_x_wipe_dist_; const bool retract_before = is_outer_wall ? retract_before_outer_wall_ : false; - const bool revert_inset = alternate_walls && (path.vertices_->inset_idx_ % 2); - const bool revert_layer = alternate_walls && (layer_nr_ % 2); + const bool revert_inset = alternate_walls && (path.vertices_->inset_idx_ % 2 != 0); + const bool revert_layer = alternate_walls && (layer_nr_ % 2 != 0); const bool backwards = path.backwards_ != (revert_inset != revert_layer); const size_t start_index = (backwards != path.backwards_) ? path.vertices_->size() - (path.start_vertex_ + 1) : path.start_vertex_; const bool linked_path = ! path.is_closed_; gcode_layer_.setIsInside(true); // Going to print walls, which are always inside. - gcode_layer_.addWall(*path.vertices_, start_index, settings_, non_bridge_config, bridge_config, wipe_dist, flow, retract_before, path.is_closed_, backwards, linked_path); + gcode_layer_.addWall(*path.vertices_, start_index, settings_, non_bridge_config, roofing_config, bridge_config, wipe_dist, flow, retract_before, path.is_closed_, backwards, linked_path); added_something = true; } return added_something; diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 4f498caffd..b80251a715 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -647,6 +647,7 @@ void LayerPlan::addWallLine( const Point2LL& p1, const Settings& settings, const GCodePathConfig& non_bridge_config, + const GCodePathConfig& roofing_config, const GCodePathConfig& bridge_config, double flow, const Ratio width_factor, @@ -760,7 +761,28 @@ void LayerPlan::addWallLine( } }; - if (bridge_wall_mask_.empty()) + const auto use_roofing_config = [&]() -> bool + { + if (roofing_config == non_bridge_config) + { + // if the roofing config and normal config are the same any way there is no need to check what part of the line segment + return false; + } + return roofing_mask_.empty() || PolygonUtils::polygonCollidesWithLineSegment(roofing_mask_, p0, p1) || !roofing_mask_.inside(p1, true); + }(); + + if (use_roofing_config) + { + addExtrusionMove( + p1, + roofing_config, + SpaceFillType::Polygons, + flow, + width_factor, + spiralize, + 1.0_r); + } + else if (bridge_wall_mask_.empty()) { // no bridges required addExtrusionMove( @@ -867,6 +889,7 @@ void LayerPlan::addWall( int start_idx, const Settings& settings, const GCodePathConfig& non_bridge_config, + const GCodePathConfig& roofing_config, const GCodePathConfig& bridge_config, coord_t wall_0_wipe_dist, double flow_ratio, @@ -895,7 +918,7 @@ void LayerPlan::addWall( constexpr bool is_closed = true; constexpr bool is_reversed = false; constexpr bool is_linked_path = false; - addWall(ewall, start_idx, settings, non_bridge_config, bridge_config, wall_0_wipe_dist, flow_ratio, always_retract, is_closed, is_reversed, is_linked_path); + addWall(ewall, start_idx, settings, non_bridge_config, roofing_config, bridge_config, wall_0_wipe_dist, flow_ratio, always_retract, is_closed, is_reversed, is_linked_path); } void LayerPlan::addWall( @@ -903,6 +926,7 @@ void LayerPlan::addWall( int start_idx, const Settings& settings, const GCodePathConfig& non_bridge_config, + const GCodePathConfig& roofing_config, const GCodePathConfig& bridge_config, coord_t wall_0_wipe_dist, double flow_ratio, @@ -1094,6 +1118,7 @@ void LayerPlan::addWall( destination, settings, non_bridge_config, + roofing_config, bridge_config, flow_ratio, line_width * nominal_line_width_multiplier, @@ -1168,6 +1193,7 @@ void LayerPlan::addWalls( const Polygons& walls, const Settings& settings, const GCodePathConfig& non_bridge_config, + const GCodePathConfig& roofing_config, const GCodePathConfig& bridge_config, const ZSeamConfig& z_seam_config, coord_t wall_0_wipe_dist, @@ -1183,7 +1209,7 @@ void LayerPlan::addWalls( orderOptimizer.optimize(); for (const PathOrdering& path : orderOptimizer.paths_) { - addWall(**path.vertices_, path.start_vertex_, settings, non_bridge_config, bridge_config, wall_0_wipe_dist, flow_ratio, always_retract); + addWall(**path.vertices_, path.start_vertex_, settings, non_bridge_config, roofing_config, bridge_config, wall_0_wipe_dist, flow_ratio, always_retract); } } @@ -2489,4 +2515,9 @@ void LayerPlan::setOverhangMask(const Polygons& polys) overhang_mask_ = polys; } +void LayerPlan::setRoofingMask(const Polygons& polys) +{ + roofing_mask_ = polys; +} + } // namespace cura diff --git a/src/TopSurface.cpp b/src/TopSurface.cpp index acbbe94f7d..a717ccb3bb 100644 --- a/src/TopSurface.cpp +++ b/src/TopSurface.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #include "TopSurface.h" @@ -176,6 +176,8 @@ bool TopSurface::ironing(const SliceDataStorage& storage, const SliceMeshStorage line_config, line_config, line_config, + line_config, + line_config, retract_before_outer_wall, wipe_dist, wipe_dist,