From b621644d96d4334f246c0475ef65cedf499fdf74 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Thu, 21 Sep 2023 15:38:05 +0200 Subject: [PATCH 01/56] Proof-of-concept 'true' support z-offset: half-layer heights. First see if the part of the support (interface only for now) that should (perhaps) be a bit lower if the support z gap is not a multiple of the layer height, can actually be lowered at all without upending the code too much. This turns out to be possible. Next is actually setting the proper gap height (or what's left of the gap after already dropping down to the layer that needs to be a fractional height.) Proof of concept mostly in the sense that the quality of the code added may not reflect our standards, and would also be missing functionality (for instance; what if we print without support-interface). part of CURA-11041, which is the proof-of-concept for CURA-10407 --- include/GCodePathConfig.h | 1 + include/LayerPlan.h | 19 ++-- include/pathPlanning/GCodePath.h | 1 + include/sliceDataStorage.h | 2 + src/FffGcodeWriter.cpp | 169 ++++++++++++++++--------------- src/LayerPlan.cpp | 41 ++++---- src/support.cpp | 3 +- 7 files changed, 130 insertions(+), 106 deletions(-) diff --git a/include/GCodePathConfig.h b/include/GCodePathConfig.h index 1ee2003195..1f0da38d60 100644 --- a/include/GCodePathConfig.h +++ b/include/GCodePathConfig.h @@ -18,6 +18,7 @@ namespace cura */ struct GCodePathConfig { + coord_t z_offset{}; PrintFeatureType type{}; //!< name of the feature type coord_t line_width{}; //!< width of the line extruded coord_t layer_thickness{}; //!< current layer height in micron diff --git a/include/LayerPlan.h b/include/LayerPlan.h index bd30920a04..24fc141b82 100644 --- a/include/LayerPlan.h +++ b/include/LayerPlan.h @@ -117,10 +117,11 @@ class LayerPlan : public NoCopy */ GCodePath* getLatestPathWithConfig( const GCodePathConfig& config, - SpaceFillType space_fill_type, + const coord_t z_offset, + const SpaceFillType space_fill_type, const Ratio flow = 1.0_r, const Ratio width_factor = 1.0_r, - bool spiralize = false, + const bool spiralize = false, const Ratio speed_factor = 1.0_r); public: @@ -281,7 +282,7 @@ class LayerPlan : public NoCopy * \param p The point to travel to. * \param force_retract Whether to force a retraction to occur. */ - GCodePath& addTravel(const Point p, const bool force_retract = false); + GCodePath& addTravel(const Point p, const bool force_retract = false, const coord_t z_offset = 0); /*! * Add a travel path to a certain point and retract if needed. @@ -291,7 +292,7 @@ class LayerPlan : public NoCopy * \param p The point to travel to * \param path (optional) The travel path to which to add the point \p p */ - GCodePath& addTravel_simple(Point p, GCodePath* path = nullptr); + GCodePath& addTravel_simple(const Point p, GCodePath* path = nullptr); /*! * Plan a prime blob at the current location. @@ -317,14 +318,14 @@ class LayerPlan : public NoCopy * \param fan_speed Fan speed override for this path. */ void addExtrusionMove( - Point p, + const Point p, const GCodePathConfig& config, - SpaceFillType space_fill_type, + const SpaceFillType space_fill_type, const Ratio& flow = 1.0_r, const Ratio width_factor = 1.0_r, - bool spiralize = false, - Ratio speed_factor = 1.0_r, - double fan_speed = GCodePathConfig::FAN_SPEED_DEFAULT); + const bool spiralize = false, + const Ratio speed_factor = 1.0_r, + const double fan_speed = GCodePathConfig::FAN_SPEED_DEFAULT); /*! * Add polygon to the gcode starting at vertex \p startIdx diff --git a/include/pathPlanning/GCodePath.h b/include/pathPlanning/GCodePath.h index 7bbd56c709..ef59a8747d 100644 --- a/include/pathPlanning/GCodePath.h +++ b/include/pathPlanning/GCodePath.h @@ -29,6 +29,7 @@ namespace cura */ struct GCodePath { + coord_t z_offset{}; GCodePathConfig config{}; //!< The configuration settings of the path. std::shared_ptr mesh; //!< Which mesh this path belongs to, if any. If it's not part of any mesh, the mesh should be nullptr; SpaceFillType space_fill_type{}; //!< The type of space filling of which this path is a part diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 9b0661ed36..067a0a60a3 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -212,6 +212,8 @@ class SupportLayer std::vector support_infill_parts; //!< a list of support infill parts Polygons support_bottom; //!< Piece of support below the support and above the model. This must not overlap with any of the support_infill_parts or support_roof. Polygons support_roof; //!< Piece of support above the support and below the model. This must not overlap with any of the support_infill_parts or support_bottom. + Polygons support_fractional_roof_top; //!< If the support distance is less than a multiple of the layer height, + // the first part of support just underneath the model needs to be printed at a fracional layer height. Polygons support_mesh_drop_down; //!< Areas from support meshes which should be supported by more support Polygons support_mesh; //!< Areas from support meshes which should NOT be supported by more support Polygons anti_overhang; //!< Areas where no overhang should be detected. diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 235f6f587e..359ea4fdf9 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3327,89 +3327,100 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay support_roof_line_distance *= roof_extruder.settings.get("initial_layer_line_width_factor"); } - Polygons infill_outline = support_layer.support_roof; - Polygons wall; - // make sure there is a wall if this is on the first layer - if (gcode_layer.getLayerNr() == 0) - { - wall = support_layer.support_roof.offset(-support_roof_line_width / 2); - infill_outline = wall.offset(-support_roof_line_width / 2); - } + const auto half_layer_height = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("layer_height") / 2; - Infill roof_computation( - pattern, - zig_zaggify_infill, - connect_polygons, - infill_outline, - gcode_layer.configs_storage.support_roof_config.getLineWidth(), - support_roof_line_distance, - support_roof_overlap, - infill_multiplier, - fill_angle, - gcode_layer.z, - extra_infill_shift, - max_resolution, - max_deviation, - wall_line_count, - small_area_width, - infill_origin, - skip_stitching, - fill_gaps, - connected_zigzags, - use_endpieces, - skip_some_zags, - zag_skip_count, - pocket_size); - Polygons roof_polygons; - std::vector roof_paths; - Polygons roof_lines; - roof_computation.generate(roof_paths, roof_polygons, roof_lines, roof_extruder.settings, gcode_layer.getLayerNr(), SectionType::SUPPORT); - if ((gcode_layer.getLayerNr() == 0 && wall.empty()) || (gcode_layer.getLayerNr() > 0 && roof_paths.empty() && roof_polygons.empty() && roof_lines.empty())) - { - return false; // We didn't create any support roof. - } - gcode_layer.setIsInside(false); // going to print stuff outside print object, i.e. support - if (gcode_layer.getLayerNr() == 0) - { - gcode_layer.addPolygonsByOptimizer(wall, gcode_layer.configs_storage.support_roof_config); - } - if (! roof_polygons.empty()) - { - constexpr bool force_comb_retract = false; - gcode_layer.addTravel(roof_polygons[0][0], force_comb_retract); - gcode_layer.addPolygonsByOptimizer(roof_polygons, gcode_layer.configs_storage.support_roof_config); - } - if (! roof_paths.empty()) + auto infill_outlines = { support_layer.support_roof.difference(support_layer.support_fractional_roof_top), support_layer.support_fractional_roof_top }; + auto current_roof_config = gcode_layer.configs_storage.support_roof_config; // copy! + bool generated_something = false; + for (auto infill_outline : infill_outlines) { - const GCodePathConfig& config = gcode_layer.configs_storage.support_roof_config; - constexpr bool retract_before_outer_wall = false; - constexpr coord_t wipe_dist = 0; - const ZSeamConfig z_seam_config(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); + Polygons wall; + // make sure there is a wall if this is on the first layer + if (gcode_layer.getLayerNr() == 0) + { + wall = support_layer.support_roof.offset(-support_roof_line_width / 2); + infill_outline = wall.offset(-support_roof_line_width / 2); + } - InsetOrderOptimizer wall_orderer( - *this, - storage, - gcode_layer, - roof_extruder.settings, - roof_extruder_nr, - config, - config, - config, - config, - retract_before_outer_wall, - wipe_dist, - wipe_dist, - roof_extruder_nr, - roof_extruder_nr, - z_seam_config, - roof_paths); - wall_orderer.addToLayer(); + Infill roof_computation( + pattern, + zig_zaggify_infill, + connect_polygons, + infill_outline, + current_roof_config.getLineWidth(), + support_roof_line_distance, + support_roof_overlap, + infill_multiplier, + fill_angle, + gcode_layer.z + current_roof_config.z_offset, + extra_infill_shift, + max_resolution, + max_deviation, + wall_line_count, + small_area_width, + infill_origin, + skip_stitching, + fill_gaps, + connected_zigzags, + use_endpieces, + skip_some_zags, + zag_skip_count, + pocket_size); + Polygons roof_polygons; + std::vector roof_paths; + Polygons roof_lines; + roof_computation.generate(roof_paths, roof_polygons, roof_lines, roof_extruder.settings, gcode_layer.getLayerNr(), SectionType::SUPPORT); + if ((gcode_layer.getLayerNr() == 0 && wall.empty()) || (gcode_layer.getLayerNr() > 0 && roof_paths.empty() && roof_polygons.empty() && roof_lines.empty())) + { + continue; // We didn't create any support roof. + } + generated_something = true; // We _did_ create at least some support roof. + gcode_layer.setIsInside(false); // going to print stuff outside print object, i.e. support + if (gcode_layer.getLayerNr() == 0) + { + gcode_layer.addPolygonsByOptimizer(wall, current_roof_config); + } + if (!roof_polygons.empty()) + { + constexpr bool force_comb_retract = false; + gcode_layer.addTravel(roof_polygons[0][0], force_comb_retract); + gcode_layer.addPolygonsByOptimizer(roof_polygons, current_roof_config); + } + if (!roof_paths.empty()) + { + const GCodePathConfig& config = current_roof_config; + constexpr bool retract_before_outer_wall = false; + constexpr coord_t wipe_dist = 0; + const ZSeamConfig z_seam_config(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); + + InsetOrderOptimizer wall_orderer( + *this, + storage, + gcode_layer, + roof_extruder.settings, + roof_extruder_nr, + config, + config, + config, + config, + retract_before_outer_wall, + wipe_dist, + wipe_dist, + roof_extruder_nr, + roof_extruder_nr, + z_seam_config, + roof_paths); + wall_orderer.addToLayer(); + } + gcode_layer.addLinesByOptimizer( + roof_lines, + gcode_layer.configs_storage.support_roof_config, + (pattern == EFillMethod::ZIG_ZAG) ? SpaceFillType::PolyLines : SpaceFillType::Lines); + + current_roof_config.z_offset = -half_layer_height; + current_roof_config.flow /= 2.0; } - gcode_layer.addLinesByOptimizer( - roof_lines, - gcode_layer.configs_storage.support_roof_config, - (pattern == EFillMethod::ZIG_ZAG) ? SpaceFillType::PolyLines : SpaceFillType::Lines); - return true; + return generated_something; } bool FffGcodeWriter::addSupportBottomsToGCode(const SliceDataStorage& storage, LayerPlan& gcode_layer) const diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 4a283c147e..4642c8bfd1 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -38,19 +38,21 @@ constexpr int MINIMUM_SQUARED_LINE_LENGTH = MINIMUM_LINE_LENGTH * MINIMUM_LINE_L GCodePath* LayerPlan::getLatestPathWithConfig( const GCodePathConfig& config, - SpaceFillType space_fill_type, + const coord_t z_offset, + const SpaceFillType space_fill_type, const Ratio flow, const Ratio width_factor, - bool spiralize, + const bool spiralize, const Ratio speed_factor) { std::vector& paths = extruder_plans.back().paths; if (paths.size() > 0 && paths.back().config == config && ! paths.back().done && paths.back().flow == flow && paths.back().width_factor == width_factor - && paths.back().speed_factor == speed_factor && paths.back().mesh == current_mesh) // spiralize can only change when a travel path is in between + && paths.back().speed_factor == speed_factor && paths.back().z_offset == z_offset && paths.back().mesh == current_mesh) // spiralize can only change when a travel path is in between { return &paths.back(); } - paths.emplace_back(GCodePath{ .config = config, + paths.emplace_back(GCodePath{ .z_offset = z_offset, + .config = config, .mesh = current_mesh, .space_fill_type = space_fill_type, .flow = flow, @@ -326,14 +328,14 @@ std::optional> LayerPlan::getFirstTravelDestinationState( return ret; } -GCodePath& LayerPlan::addTravel(const Point p, const bool force_retract) +GCodePath& LayerPlan::addTravel(const Point p, const bool force_retract, const coord_t z_offset) { const GCodePathConfig& travel_config = configs_storage.travel_config_per_extruder[getExtruder()]; const RetractionConfig& retraction_config = current_mesh ? current_mesh->retraction_wipe_config.retraction_config : storage.retraction_wipe_config_per_extruder[getExtruder()].retraction_config; - GCodePath* path = getLatestPathWithConfig(travel_config, SpaceFillType::None); + GCodePath* path = getLatestPathWithConfig(travel_config, z_offset, SpaceFillType::None); bool combed = false; @@ -478,7 +480,7 @@ GCodePath& LayerPlan::addTravel(const Point p, const bool force_retract) return ret; } -GCodePath& LayerPlan::addTravel_simple(Point p, GCodePath* path) +GCodePath& LayerPlan::addTravel_simple(const Point p, GCodePath* path) { bool is_first_travel_of_layer = ! static_cast(last_planned_position); if (is_first_travel_of_layer) @@ -488,7 +490,7 @@ GCodePath& LayerPlan::addTravel_simple(Point p, GCodePath* path) } if (path == nullptr) { - path = getLatestPathWithConfig(configs_storage.travel_config_per_extruder[getExtruder()], SpaceFillType::None); + path = getLatestPathWithConfig(configs_storage.travel_config_per_extruder[getExtruder()], 0, SpaceFillType::None); } path->points.push_back(p); last_planned_position = p; @@ -506,16 +508,16 @@ void LayerPlan::planPrime(const float& prime_blob_wipe_length) } void LayerPlan::addExtrusionMove( - Point p, + const Point p, const GCodePathConfig& config, - SpaceFillType space_fill_type, + const SpaceFillType space_fill_type, const Ratio& flow, const Ratio width_factor, - bool spiralize, - Ratio speed_factor, - double fan_speed) + const bool spiralize, + const Ratio speed_factor, + const double fan_speed) { - GCodePath* path = getLatestPathWithConfig(config, space_fill_type, flow, width_factor, spiralize, speed_factor); + GCodePath* path = getLatestPathWithConfig(config, config.z_offset, space_fill_type, flow, width_factor, spiralize, speed_factor); path->points.push_back(p); path->setFanSpeed(fan_speed); if (! static_cast(first_extrusion_acc_jerk)) @@ -537,7 +539,7 @@ void LayerPlan::addPolygon( { constexpr Ratio width_ratio = 1.0_r; // Not printed with variable line width. Point p0 = polygon[start_idx]; - addTravel(p0, always_retract); + addTravel(p0, always_retract, config.z_offset); const int direction = backwards ? -1 : 1; for (size_t point_idx = 1; point_idx < polygon.size(); point_idx++) { @@ -1250,7 +1252,7 @@ void LayerPlan::addLinesInGivenOrder( } else { - addTravel(start); + addTravel(start, false, config.z_offset); } Point p0 = start; @@ -1947,7 +1949,12 @@ void LayerPlan::writeGCode(GCodeExport& gcode) gcode.writeRetraction(retraction_config->retraction_config); } - if (! path.retract && path.config.isTravelPath() && path.points.size() == 1 && path.points[0] == gcode.getPositionXY() && z == gcode.getPositionZ()) + if (z > 0) + { + gcode.setZ(z + path.z_offset); + } + + if (! path.retract && path.config.isTravelPath() && path.points.size() == 1 && path.points[0] == gcode.getPositionXY() && (z + path.z_offset) == gcode.getPositionZ()) { // ignore travel moves to the current location to avoid needless change of acceleration/jerk continue; diff --git a/src/support.cpp b/src/support.cpp index 188f2b486d..b8de3c5247 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -1805,7 +1805,7 @@ void AreaSupport::generateSupportRoof(SliceDataStorage& storage, const SliceMesh const double minimum_roof_area = mesh.settings.get("minimum_roof_area"); std::vector& support_layers = storage.support.supportLayers; - for (LayerIndex layer_idx = 0; layer_idx < static_cast(support_layers.size() - z_distance_top); layer_idx++) + for (LayerIndex layer_idx = static_cast(support_layers.size() - z_distance_top) - 1; layer_idx >= 0; --layer_idx) { const LayerIndex top_layer_idx_above{ std::min(LayerIndex{ support_layers.size() - 1 }, LayerIndex{ layer_idx + roof_layer_count + z_distance_top }) @@ -1818,6 +1818,7 @@ void AreaSupport::generateSupportRoof(SliceDataStorage& storage, const SliceMesh Polygons roofs; generateSupportInterfaceLayer(global_support_areas_per_layer[layer_idx], mesh_outlines, roof_line_width, roof_outline_offset, minimum_roof_area, roofs); support_layers[layer_idx].support_roof.add(roofs); + support_layers[layer_idx].support_fractional_roof_top = roofs.difference(support_layers[layer_idx + 1].support_roof); scripta::log("support_interface_roofs", roofs, SectionType::SUPPORT, layer_idx); } From a07fb927de6ab53893db31c2af7c196d1c5ed8ae Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Thu, 21 Sep 2023 16:07:07 +0200 Subject: [PATCH 02/56] Proof-of-concept: fractional support z-distance. Instead of half-height layers in each area that could potentially be affected by non-layer-height modulo support z distance, actually calculate the proper z-offset that is needed for the fractional layer. Proof of concept mostly in the sense that the quality of the code added may not reflect our standards, and would also be missing functionality (for instance; what if we print without support-interface, or tree-support at all). part of CURA-11041, which is the proof-of-concept for CURA-10407 --- src/FffGcodeWriter.cpp | 12 +++++++----- src/support.cpp | 6 +++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 359ea4fdf9..1af4378832 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -2287,7 +2287,7 @@ bool FffGcodeWriter::processInsets( if (mesh_group_settings.get("support_enable")) { const coord_t z_distance_top = mesh.settings.get("support_top_distance"); - const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height) + 1; + const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height); // Previously '... +1', but now there is an extra fractional layer on top. const int support_layer_nr = gcode_layer.getLayerNr() - z_distance_top_layers; if (support_layer_nr > 0) @@ -2596,7 +2596,7 @@ void FffGcodeWriter::processTopBottom( { const coord_t layer_height = mesh_config.inset0_config.getLayerThickness(); const coord_t z_distance_top = mesh.settings.get("support_top_distance"); - const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height) + 1; + const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height); // Previously '... +1', but now there is an extra fractional layer on top. support_layer_nr = layer_nr - z_distance_top_layers; } @@ -3327,7 +3327,9 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay support_roof_line_distance *= roof_extruder.settings.get("initial_layer_line_width_factor"); } - const auto half_layer_height = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("layer_height") / 2; + const auto layer_height = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("layer_height"); + const auto support_top_distance = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("support_top_distance"); + const coord_t leftover_support_distance = support_top_distance % layer_height; auto infill_outlines = { support_layer.support_roof.difference(support_layer.support_fractional_roof_top), support_layer.support_fractional_roof_top }; auto current_roof_config = gcode_layer.configs_storage.support_roof_config; // copy! @@ -3417,8 +3419,8 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay gcode_layer.configs_storage.support_roof_config, (pattern == EFillMethod::ZIG_ZAG) ? SpaceFillType::PolyLines : SpaceFillType::Lines); - current_roof_config.z_offset = -half_layer_height; - current_roof_config.flow /= 2.0; + current_roof_config.z_offset = -leftover_support_distance; + current_roof_config.flow *= Ratio(layer_height - leftover_support_distance, layer_height); } return generated_something; } diff --git a/src/support.cpp b/src/support.cpp index b8de3c5247..ba1dc02a6f 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -794,7 +794,7 @@ void AreaSupport::generateOverhangAreasForMesh(SliceDataStorage& storage, SliceM // Don't generate overhang areas if the Z distance is higher than the objects we're generating support for. const coord_t layer_height = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("layer_height"); const coord_t z_distance_top = mesh.settings.get("support_top_distance"); - const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height) + 1; // Support must always be 1 layer below overhang. + const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height); // Previously '... +1', but now there is an extra fractional layer on top. if (z_distance_top_layers + 1 > storage.print_layer_count) { return; @@ -1059,7 +1059,7 @@ void AreaSupport::generateSupportAreasForMesh( // early out const coord_t layer_thickness = mesh_group_settings.get("layer_height"); const coord_t z_distance_top = ((mesh.settings.get("support_roof_enable")) ? roof_settings : infill_settings).get("support_top_distance"); - const size_t layer_z_distance_top = round_up_divide(z_distance_top, layer_thickness) + 1; // support must always be 1 layer below overhang + const size_t layer_z_distance_top = round_up_divide(z_distance_top, layer_thickness); // Previously '... +1', but now there is an extra fractional layer on top. if (layer_z_distance_top + 1 > layer_count) { return; @@ -1805,7 +1805,7 @@ void AreaSupport::generateSupportRoof(SliceDataStorage& storage, const SliceMesh const double minimum_roof_area = mesh.settings.get("minimum_roof_area"); std::vector& support_layers = storage.support.supportLayers; - for (LayerIndex layer_idx = static_cast(support_layers.size() - z_distance_top) - 1; layer_idx >= 0; --layer_idx) + for (LayerIndex layer_idx = static_cast(support_layers.size() - z_distance_top); layer_idx >= 0; --layer_idx) { const LayerIndex top_layer_idx_above{ std::min(LayerIndex{ support_layers.size() - 1 }, LayerIndex{ layer_idx + roof_layer_count + z_distance_top }) From 7bdbe9acc8137cbb23245768737d5da6e3d62f4a Mon Sep 17 00:00:00 2001 From: rburema Date: Thu, 21 Sep 2023 14:08:19 +0000 Subject: [PATCH 03/56] Applied clang-format. --- src/FffGcodeWriter.cpp | 6 +++--- src/LayerPlan.cpp | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 1af4378832..866ab2ee8f 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3332,7 +3332,7 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay const coord_t leftover_support_distance = support_top_distance % layer_height; auto infill_outlines = { support_layer.support_roof.difference(support_layer.support_fractional_roof_top), support_layer.support_fractional_roof_top }; - auto current_roof_config = gcode_layer.configs_storage.support_roof_config; // copy! + auto current_roof_config = gcode_layer.configs_storage.support_roof_config; // copy! bool generated_something = false; for (auto infill_outline : infill_outlines) { @@ -3382,13 +3382,13 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay { gcode_layer.addPolygonsByOptimizer(wall, current_roof_config); } - if (!roof_polygons.empty()) + if (! roof_polygons.empty()) { constexpr bool force_comb_retract = false; gcode_layer.addTravel(roof_polygons[0][0], force_comb_retract); gcode_layer.addPolygonsByOptimizer(roof_polygons, current_roof_config); } - if (!roof_paths.empty()) + if (! roof_paths.empty()) { const GCodePathConfig& config = current_roof_config; constexpr bool retract_before_outer_wall = false; diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 4642c8bfd1..70a6152eb7 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -47,7 +47,8 @@ GCodePath* LayerPlan::getLatestPathWithConfig( { std::vector& paths = extruder_plans.back().paths; if (paths.size() > 0 && paths.back().config == config && ! paths.back().done && paths.back().flow == flow && paths.back().width_factor == width_factor - && paths.back().speed_factor == speed_factor && paths.back().z_offset == z_offset && paths.back().mesh == current_mesh) // spiralize can only change when a travel path is in between + && paths.back().speed_factor == speed_factor && paths.back().z_offset == z_offset + && paths.back().mesh == current_mesh) // spiralize can only change when a travel path is in between { return &paths.back(); } From 16d1a84567072bb7f39b18b2171d7cfea9d0e1c9 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Fri, 22 Sep 2023 14:51:52 +0200 Subject: [PATCH 04/56] Fix crash in proof-of-concept code. part of CURA-11041 --- src/support.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/support.cpp b/src/support.cpp index ba1dc02a6f..a4cf4a711e 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -1805,7 +1805,7 @@ void AreaSupport::generateSupportRoof(SliceDataStorage& storage, const SliceMesh const double minimum_roof_area = mesh.settings.get("minimum_roof_area"); std::vector& support_layers = storage.support.supportLayers; - for (LayerIndex layer_idx = static_cast(support_layers.size() - z_distance_top); layer_idx >= 0; --layer_idx) + for (LayerIndex layer_idx = static_cast(support_layers.size() - z_distance_top) - 1; layer_idx >= 0; --layer_idx) { const LayerIndex top_layer_idx_above{ std::min(LayerIndex{ support_layers.size() - 1 }, LayerIndex{ layer_idx + roof_layer_count + z_distance_top }) From 3820d3b8ad8eb67195ef93c446324dcf7388aa0a Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Fri, 22 Sep 2023 15:05:46 +0200 Subject: [PATCH 05/56] Proof-of-concept. Attempt to fix newly introduced small extrusions. done as part of CURA-11041 --- src/FffGcodeWriter.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 866ab2ee8f..3746a9ada2 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3331,10 +3331,14 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay const auto support_top_distance = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("support_top_distance"); const coord_t leftover_support_distance = support_top_distance % layer_height; - auto infill_outlines = { support_layer.support_roof.difference(support_layer.support_fractional_roof_top), support_layer.support_fractional_roof_top }; + std::vector infill_outlines = + { + Simplify(roof_extruder.settings).polygon(support_layer.support_roof.difference(support_layer.support_fractional_roof_top)), + Simplify(roof_extruder.settings).polygon(support_layer.support_fractional_roof_top) + }; auto current_roof_config = gcode_layer.configs_storage.support_roof_config; // copy! bool generated_something = false; - for (auto infill_outline : infill_outlines) + for (auto& infill_outline : infill_outlines) { Polygons wall; // make sure there is a wall if this is on the first layer From 94d6007a7f7b6e4a11e2e8d77acad0e60a645c4a Mon Sep 17 00:00:00 2001 From: rburema Date: Fri, 22 Sep 2023 13:07:21 +0000 Subject: [PATCH 06/56] Applied clang-format. --- src/FffGcodeWriter.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 3746a9ada2..9361f1ff10 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3331,11 +3331,8 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay const auto support_top_distance = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("support_top_distance"); const coord_t leftover_support_distance = support_top_distance % layer_height; - std::vector infill_outlines = - { - Simplify(roof_extruder.settings).polygon(support_layer.support_roof.difference(support_layer.support_fractional_roof_top)), - Simplify(roof_extruder.settings).polygon(support_layer.support_fractional_roof_top) - }; + std::vector infill_outlines = { Simplify(roof_extruder.settings).polygon(support_layer.support_roof.difference(support_layer.support_fractional_roof_top)), + Simplify(roof_extruder.settings).polygon(support_layer.support_fractional_roof_top) }; auto current_roof_config = gcode_layer.configs_storage.support_roof_config; // copy! bool generated_something = false; for (auto& infill_outline : infill_outlines) From b996cd013d083fb6ca3b19a8ad5ea0952e2fe0be Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 26 Sep 2023 21:15:38 +0200 Subject: [PATCH 07/56] Proof-of-concept. Fix partial-layer-height difference for (support) line-fill. Part of the partial layer-height support distance proof of concept: CURA-11041 --- src/FffGcodeWriter.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 9361f1ff10..1fab3e3005 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3375,6 +3375,9 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay roof_computation.generate(roof_paths, roof_polygons, roof_lines, roof_extruder.settings, gcode_layer.getLayerNr(), SectionType::SUPPORT); if ((gcode_layer.getLayerNr() == 0 && wall.empty()) || (gcode_layer.getLayerNr() > 0 && roof_paths.empty() && roof_polygons.empty() && roof_lines.empty())) { + current_roof_config.z_offset = -leftover_support_distance; + current_roof_config.flow *= Ratio(layer_height - leftover_support_distance, layer_height); + continue; // We didn't create any support roof. } generated_something = true; // We _did_ create at least some support roof. @@ -3417,7 +3420,7 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay } gcode_layer.addLinesByOptimizer( roof_lines, - gcode_layer.configs_storage.support_roof_config, + current_roof_config, (pattern == EFillMethod::ZIG_ZAG) ? SpaceFillType::PolyLines : SpaceFillType::Lines); current_roof_config.z_offset = -leftover_support_distance; From 185a2211d1ad1a95a28c046f7634bb23e9e2284d Mon Sep 17 00:00:00 2001 From: rburema Date: Tue, 26 Sep 2023 19:16:28 +0000 Subject: [PATCH 08/56] Applied clang-format. --- src/FffGcodeWriter.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 1fab3e3005..e497b08a1f 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3418,10 +3418,7 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay roof_paths); wall_orderer.addToLayer(); } - gcode_layer.addLinesByOptimizer( - roof_lines, - current_roof_config, - (pattern == EFillMethod::ZIG_ZAG) ? SpaceFillType::PolyLines : SpaceFillType::Lines); + gcode_layer.addLinesByOptimizer(roof_lines, current_roof_config, (pattern == EFillMethod::ZIG_ZAG) ? SpaceFillType::PolyLines : SpaceFillType::Lines); current_roof_config.z_offset = -leftover_support_distance; current_roof_config.flow *= Ratio(layer_height - leftover_support_distance, layer_height); From de2c993285915c9c2baf067fd807c97e0910f398 Mon Sep 17 00:00:00 2001 From: Remco Burema <41987080+rburema@users.noreply.github.com> Date: Wed, 11 Oct 2023 12:09:26 +0200 Subject: [PATCH 09/56] Fix comment to be technically correct. belatedly part of CURA-11041 Co-authored-by: Casper Lamboo --- include/sliceDataStorage.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 067a0a60a3..4c424a2b09 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -212,7 +212,7 @@ class SupportLayer std::vector support_infill_parts; //!< a list of support infill parts Polygons support_bottom; //!< Piece of support below the support and above the model. This must not overlap with any of the support_infill_parts or support_roof. Polygons support_roof; //!< Piece of support above the support and below the model. This must not overlap with any of the support_infill_parts or support_bottom. - Polygons support_fractional_roof_top; //!< If the support distance is less than a multiple of the layer height, + Polygons support_fractional_roof_top; //!< If the support distance is not exactly a multiple of the layer height, // the first part of support just underneath the model needs to be printed at a fracional layer height. Polygons support_mesh_drop_down; //!< Areas from support meshes which should be supported by more support Polygons support_mesh; //!< Areas from support meshes which should NOT be supported by more support From ad1aa1972ad9e33d86f66baee47478cb6e68d9c7 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 3 Oct 2023 12:24:18 +0200 Subject: [PATCH 10/56] Reverted the changes done in CURA-9521 CURA-11109 --- include/FffGcodeWriter.h | 3 +-- include/infill.h | 7 ++----- src/FffGcodeWriter.cpp | 9 +++------ src/infill.cpp | 10 ++++------ 4 files changed, 10 insertions(+), 19 deletions(-) diff --git a/include/FffGcodeWriter.h b/include/FffGcodeWriter.h index 0e3dea645c..96f504c1e3 100644 --- a/include/FffGcodeWriter.h +++ b/include/FffGcodeWriter.h @@ -569,8 +569,7 @@ class FffGcodeWriter : public NoCopy const Ratio skin_density, const bool monotonic, bool& added_something, - double fan_speed = GCodePathConfig::FAN_SPEED_DEFAULT, - const bool is_bridge_skin = false) const; + double fan_speed = GCodePathConfig::FAN_SPEED_DEFAULT) const; /*! * see if we can avoid printing a lines or zig zag style skin part in multiple segments by moving to diff --git a/include/infill.h b/include/infill.h index 40ca7fbd59..289a0850bb 100644 --- a/include/infill.h +++ b/include/infill.h @@ -206,8 +206,7 @@ class Infill const std::shared_ptr& cross_fill_provider = nullptr, const std::shared_ptr& lightning_layer = nullptr, const SliceMeshStorage* mesh = nullptr, - const Polygons& prevent_small_exposed_to_air = Polygons(), - const bool is_bridge_skin = false); + const Polygons& prevent_small_exposed_to_air = Polygons()); /*! * Generate the wall toolpaths of an infill area. It will return the inner contour and set the inner-contour. @@ -219,7 +218,6 @@ class Infill * \param line_width [in] The optimum wall line width of the walls * \param infill_overlap [in] The overlap of the infill * \param settings [in] A settings storage to use for generating variable-width walls. - * \param is_bridge_skin [in] Setting to filter out the extra skin walls while bridging * \return The inner contour of the wall toolpaths */ static Polygons generateWallToolPaths( @@ -230,8 +228,7 @@ class Infill const coord_t infill_overlap, const Settings& settings, int layer_idx, - SectionType section_type, - const bool is_bridge_skin = false); + SectionType section_type); private: /*! diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index e497b08a1f..55925dce5e 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -2727,8 +2727,7 @@ void FffGcodeWriter::processTopBottom( skin_density, monotonic, added_something, - fan_speed, - is_bridge_skin); + fan_speed); } void FffGcodeWriter::processSkinPrintFeature( @@ -2745,8 +2744,7 @@ void FffGcodeWriter::processSkinPrintFeature( const Ratio skin_density, const bool monotonic, bool& added_something, - double fan_speed, - const bool is_bridge_skin) const + double fan_speed) const { Polygons skin_polygons; Polygons skin_lines; @@ -2806,8 +2804,7 @@ void FffGcodeWriter::processSkinPrintFeature( nullptr, nullptr, nullptr, - small_areas_on_surface ? Polygons() : exposed_to_air, - is_bridge_skin); + small_areas_on_surface ? Polygons() : exposed_to_air); // add paths if (! skin_polygons.empty() || ! skin_lines.empty() || ! skin_paths.empty()) diff --git a/src/infill.cpp b/src/infill.cpp index 9137aa66ca..6da3c25c4f 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -60,14 +60,13 @@ Polygons Infill::generateWallToolPaths( const coord_t infill_overlap, const Settings& settings, int layer_idx, - SectionType section_type, - const bool is_bridge_skin) + SectionType section_type) { outer_contour = outer_contour.offset(infill_overlap); scripta::log("infill_outer_contour", outer_contour, section_type, layer_idx, scripta::CellVDI{ "infill_overlap", infill_overlap }); Polygons inner_contour; - if ((wall_line_count > 0) && (! is_bridge_skin)) + if (wall_line_count > 0) { constexpr coord_t wall_0_inset = 0; // Don't apply any outer wall inset for these. That's just for the outer wall. WallToolPaths wall_toolpaths(outer_contour, line_width, wall_line_count, wall_0_inset, settings, layer_idx, section_type); @@ -91,15 +90,14 @@ void Infill::generate( const std::shared_ptr& cross_fill_provider, const std::shared_ptr& lightning_trees, const SliceMeshStorage* mesh, - const Polygons& prevent_small_exposed_to_air, - const bool is_bridge_skin) + const Polygons& prevent_small_exposed_to_air) { if (outer_contour.empty()) { return; } - inner_contour = generateWallToolPaths(toolpaths, outer_contour, wall_line_count, infill_line_width, infill_overlap, settings, layer_idx, section_type, is_bridge_skin); + inner_contour = generateWallToolPaths(toolpaths, outer_contour, wall_line_count, infill_line_width, infill_overlap, settings, layer_idx, section_type); scripta::log("infill_inner_contour_0", inner_contour, section_type, layer_idx); // It does not make sense to print a pattern in a small region. So the infill region From 88e0f4c9bb8dc755f0209da71c432b974a63fde6 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Mon, 25 Sep 2023 13:53:00 +0200 Subject: [PATCH 11/56] Support brim printed only at layer 0 CURA-10968 --- src/FffGcodeWriter.cpp | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 55925dce5e..a0ba973c15 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1232,24 +1232,28 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan // Add the support brim after the skirt_brim to gcode_layer + //support brim is only added in layer 0 // For support brim we don't care about the order, because support doesn't need to be accurate. - const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; - if (extruder_nr == mesh_group_settings.get("support_extruder_nr_layer_0").extruder_nr) + if (layer_nr == 0) { - total_line_count += storage.support_brim.size(); - Polygons support_brim_lines = storage.support_brim; - support_brim_lines.toPolylines(); - gcode_layer.addLinesByOptimizer( - support_brim_lines, - gcode_layer.configs_storage.skirt_brim_config_per_extruder[extruder_nr], - SpaceFillType::PolyLines, - enable_travel_optimization, - wipe_dist, - flow_ratio, - start_close_to, - fan_speed, - reverse_print_direction, - order_requirements = {}); + const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; + if (extruder_nr == mesh_group_settings.get("support_extruder_nr_layer_0").extruder_nr) + { + total_line_count += storage.support_brim.size(); + Polygons support_brim_lines = storage.support_brim; + support_brim_lines.toPolylines(); + gcode_layer.addLinesByOptimizer( + support_brim_lines, + gcode_layer.configs_storage.skirt_brim_config_per_extruder[extruder_nr], + SpaceFillType::PolyLines, + enable_travel_optimization, + wipe_dist, + flow_ratio, + start_close_to, + fan_speed, + reverse_print_direction, + order_requirements = {}); + } } } From 54e4592ba6d80740eb917b9df8077a1bcf6c34c7 Mon Sep 17 00:00:00 2001 From: saumyaj3 Date: Mon, 25 Sep 2023 11:53:42 +0000 Subject: [PATCH 12/56] Applied clang-format. --- src/FffGcodeWriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index a0ba973c15..eab1cb7b29 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1232,7 +1232,7 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan // Add the support brim after the skirt_brim to gcode_layer - //support brim is only added in layer 0 + // support brim is only added in layer 0 // For support brim we don't care about the order, because support doesn't need to be accurate. if (layer_nr == 0) { From 7a3aa045a9e87d835c450c38db67fd307af84d9e Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Mon, 25 Sep 2023 13:55:28 +0200 Subject: [PATCH 13/56] Comment fix CURA-10968 --- src/FffGcodeWriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index eab1cb7b29..fe08adf389 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1232,7 +1232,7 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan // Add the support brim after the skirt_brim to gcode_layer - // support brim is only added in layer 0 + // Support brim is only added in layer 0 // For support brim we don't care about the order, because support doesn't need to be accurate. if (layer_nr == 0) { From ff858f3f80d6fdd515b7e3cbce33bb272e480170 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Fri, 29 Sep 2023 11:32:03 +0200 Subject: [PATCH 14/56] Comment fix CURA-10968 --- src/FffGcodeWriter.cpp | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index fe08adf389..50429e303b 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1234,26 +1234,23 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan // Add the support brim after the skirt_brim to gcode_layer // Support brim is only added in layer 0 // For support brim we don't care about the order, because support doesn't need to be accurate. - if (layer_nr == 0) + const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; + if ((layer_nr == 0) && (extruder_nr == mesh_group_settings.get("support_extruder_nr_layer_0").extruder_nr)) { - const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; - if (extruder_nr == mesh_group_settings.get("support_extruder_nr_layer_0").extruder_nr) - { - total_line_count += storage.support_brim.size(); - Polygons support_brim_lines = storage.support_brim; - support_brim_lines.toPolylines(); - gcode_layer.addLinesByOptimizer( - support_brim_lines, - gcode_layer.configs_storage.skirt_brim_config_per_extruder[extruder_nr], - SpaceFillType::PolyLines, - enable_travel_optimization, - wipe_dist, - flow_ratio, - start_close_to, - fan_speed, - reverse_print_direction, - order_requirements = {}); - } + total_line_count += storage.support_brim.size(); + Polygons support_brim_lines = storage.support_brim; + support_brim_lines.toPolylines(); + gcode_layer.addLinesByOptimizer( + support_brim_lines, + gcode_layer.configs_storage.skirt_brim_config_per_extruder[extruder_nr], + SpaceFillType::PolyLines, + enable_travel_optimization, + wipe_dist, + flow_ratio, + start_close_to, + fan_speed, + reverse_print_direction, + order_requirements = {}); } } From 0b18634a5e858e00ba026b9eadcb404e724ef14f Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 3 Oct 2023 19:39:58 +0200 Subject: [PATCH 15/56] Use correct path config CURA-11119 CURA-11121 --- src/FffGcodeWriter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 50429e303b..6ac183f0f2 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -2831,10 +2831,10 @@ void FffGcodeWriter::processSkinPrintFeature( gcode_layer, mesh.settings, extruder_nr, - mesh_config.skin_config, - mesh_config.skin_config, - mesh_config.skin_config, - mesh_config.skin_config, + config, + config, + config, + config, retract_before_outer_wall, wipe_dist, wipe_dist, From 09bbf91171c218df592f2cbe6dd8f3e71857987c Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 5 Oct 2023 09:54:12 +0200 Subject: [PATCH 16/56] Change seam position scoring to make it more consistent CURA-11100 --- include/PathOrderOptimizer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index 93198fcd19..464810cefa 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -646,7 +646,7 @@ class PathOrderOptimizer // so the user has some control over where the seam will lie. // the divisor here may need adjusting to obtain the best results (TBD) - corner_shift = score_distance / 10; + corner_shift = score_distance / 50; } float score = score_distance; From 69ff2c953a3e724843c950cf95a1ca7889822b4b Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 5 Oct 2023 17:18:08 +0200 Subject: [PATCH 17/56] Better version of the corner angle computation (to be optimized) CURA-11100 --- include/PathOrderOptimizer.h | 114 +++++++++++++++++------------------ src/FffGcodeWriter.cpp | 2 +- 2 files changed, 56 insertions(+), 60 deletions(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index 464810cefa..b269b1e063 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -136,7 +136,7 @@ class PathOrderOptimizer * This reorders the \ref paths field and fills their starting vertices and * directions. */ - void optimize() + void optimize(bool precompute_start = true) { if(paths.empty()) { @@ -188,7 +188,7 @@ class PathOrderOptimizer //For some Z seam types the start position can be pre-computed. //This is faster since we don't need to re-compute the start position at each step then. - const bool precompute_start = seam_config.type == EZSeamType::RANDOM || seam_config.type == EZSeamType::USER_SPECIFIED || seam_config.type == EZSeamType::SHARPEST_CORNER; + precompute_start &= seam_config.type == EZSeamType::RANDOM || seam_config.type == EZSeamType::USER_SPECIFIED || seam_config.type == EZSeamType::SHARPEST_CORNER; if(precompute_start) { for(auto& path : paths) @@ -656,13 +656,13 @@ class PathOrderOptimizer case EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_INNER: if(corner_angle < 0) // Indeed a concave corner? Give it some advantage over other corners. More advantage for sharper corners. { - score -= (-corner_angle + 1.0) * corner_shift; + score += corner_angle * corner_shift; } break; case EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_OUTER: if(corner_angle > 0) // Indeed a convex corner? { - score -= (corner_angle + 1.0) * corner_shift; + score -= corner_angle * corner_shift; } break; case EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_ANY: @@ -707,6 +707,43 @@ class PathOrderOptimizer return best_i; } + Point findNeighbourPoint(const OrderablePath& path, int here, coord_t distance) + { + assert(distance); + + const Point here_pos = (*path.converted)[here]; + int direction = distance > 0 ? 1 : -1; + distance = std::abs(distance); + + coord_t actual_distance = 0; + int actual_delta = 0; + + Point prev_pos = here_pos; + Point next_pos; + while(actual_distance < distance) + { + actual_delta += direction; + next_pos = (*path.converted)[(here + actual_delta + path.converted->size()) % path.converted->size()]; + actual_distance += vSize(next_pos - prev_pos); + prev_pos = next_pos; + } + + if(actual_distance > distance) // Which is veeeery likely + { + prev_pos = (*path.converted)[(here + actual_delta -direction + path.converted->size()) % path.converted->size()]; + + Point vector = next_pos - prev_pos; + coord_t vector_size = vSize(vector); + Point unit_vector = (vector * 1000) / vector_size; + Point vector_delta = unit_vector * (vector_size - (actual_distance - distance)); + return prev_pos + vector_delta / 1000; + } + else + { + return next_pos; + } + } + /*! * Some models have very sharp corners, but also have a high resolution. If a sharp corner * consists of many points each point individual might have a shallow corner, but the @@ -722,68 +759,27 @@ class PathOrderOptimizer */ float cornerAngle(const OrderablePath& path, int i, const coord_t angle_query_distance = 100, const float fall_off_strength = 0.5) { - // If the edge length becomes too small we cannot accurately calculate the angle - // define a minimum edge length, so we don't get deviant values in the angle calculations - constexpr coord_t min_edge_length = 10; - constexpr coord_t min_edge_length2 = min_edge_length * min_edge_length; + static constexpr coord_t distance_step = 2000; + static constexpr coord_t max_distance = 5000; - const int offset_index = i % path.converted->size(); - Point here = (*path.converted)[offset_index]; + const Point here = (*path.converted)[i]; - const std::function find_neighbour_point = [&offset_index, &path](const int direction, const Point& here) - { - int offset_index_ = offset_index; - Point neighbour; - do - { - offset_index_ = (offset_index_ + path.converted->size() + direction) % path.converted->size(); - neighbour = (*path.converted)[offset_index_]; - } - while (vSize2(here - neighbour) < min_edge_length2 && offset_index_ != offset_index); // find previous point that is at least min_edge_length units away from here - return neighbour; - }; - - const std::function iterate_to_previous_point = [&find_neighbour_point](Point& previous_, Point& here_, Point& next_) - { - const auto dist = vSize(here_ - next_); - next_ = here_; - here_ = previous_; - previous_ = find_neighbour_point(-1, here_); - return dist; - }; - Point previous = find_neighbour_point(-1, here); + float angle = 0.0; + int computed_angles = 0; - const std::function iterate_to_next_point = [&find_neighbour_point](Point& previous_, Point& here_, Point& next_) + for(coord_t distance = distance_step ; distance <= max_distance ; distance += distance_step) { - const auto dist = vSize(here_ - previous_); - previous_ = here_; - here_ = next_; - next_ = find_neighbour_point(1, here_); - return dist; - }; - Point next = find_neighbour_point(1, here); + Point next = findNeighbourPoint(path, i, distance); + Point previous = findNeighbourPoint(path, i, -distance); - float corner_angle = LinearAlg2D::getAngleLeft(previous, here, next) - M_PI; - - for (const auto& iterate_func : {iterate_to_previous_point, iterate_to_next_point}) - { - Point next_ = next; - Point here_ = here; - Point previous_ = previous; - for - ( - coord_t distance_to_query = iterate_func(previous_, here_, next_); - distance_to_query < angle_query_distance && here_ != here; - distance_to_query += iterate_func(previous_, here_, next_) - ) - { - // angles further away from the query point are weighted less - const float angle_weight = 1.0 - pow(distance_to_query / angle_query_distance, fall_off_strength); - corner_angle += (LinearAlg2D::getAngleLeft(previous_, here_, next_) - M_PI) * angle_weight; - } + angle += LinearAlg2D::getAngleLeft(previous, here, next) - M_PI; + computed_angles++; } - return corner_angle / M_PI; // Limit angle between -1 and 1. + angle /= computed_angles; + angle /= M_PI; + + return angle; } /*! diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 6ac183f0f2..aedd5d439b 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1493,7 +1493,7 @@ void FffGcodeWriter::addMeshLayerToGCode( { part_order_optimizer.addPolygon(&part); } - part_order_optimizer.optimize(); + part_order_optimizer.optimize(false); for (const PathOrdering& path : part_order_optimizer.paths) { addMeshPartToGCode(storage, mesh, extruder_nr, mesh_config, *path.vertices, gcode_layer); From 82282725e5894dd3e776e37feba8e56e00ca8c2c Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Thu, 5 Oct 2023 15:18:51 +0000 Subject: [PATCH 18/56] Applied clang-format. --- include/PathOrderOptimizer.h | 302 +++++++++++++++++++---------------- 1 file changed, 160 insertions(+), 142 deletions(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index b269b1e063..939baf6b21 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -4,9 +4,6 @@ #ifndef PATHORDEROPTIMIZER_H #define PATHORDEROPTIMIZER_H -#include -#include - #include "InsetOrderOptimizer.h" // for makeOrderIncludeTransitive #include "PathOrdering.h" #include "pathPlanning/CombPath.h" //To calculate the combing distance if we want to use combing. @@ -16,12 +13,16 @@ #include "utils/linearAlg2D.h" //To find the angle of corners to hide seams. #include "utils/polygonUtils.h" #include "utils/views/dfs.h" -#include -#include + #include #include -#include #include +#include +#include +#include +#include + +#include namespace cura { @@ -99,10 +100,17 @@ class PathOrderOptimizer * it into a polygon. * \param combing_boundary Boundary to avoid when making travel moves. */ - PathOrderOptimizer(const Point start_point, const ZSeamConfig seam_config = ZSeamConfig(), const bool detect_loops = false, const Polygons* combing_boundary = nullptr, const bool reverse_direction = false, const std::unordered_multimap& order_requirements = no_order_requirements, const bool group_outer_walls = false) + PathOrderOptimizer( + const Point start_point, + const ZSeamConfig seam_config = ZSeamConfig(), + const bool detect_loops = false, + const Polygons* combing_boundary = nullptr, + const bool reverse_direction = false, + const std::unordered_multimap& order_requirements = no_order_requirements, + const bool group_outer_walls = false) : start_point(start_point) , seam_config(seam_config) - , combing_boundary((combing_boundary != nullptr && !combing_boundary->empty()) ? combing_boundary : nullptr) + , combing_boundary((combing_boundary != nullptr && ! combing_boundary->empty()) ? combing_boundary : nullptr) , detect_loops(detect_loops) , reverse_direction(reverse_direction) , order_requirements(&order_requirements) @@ -138,70 +146,70 @@ class PathOrderOptimizer */ void optimize(bool precompute_start = true) { - if(paths.empty()) + if (paths.empty()) { return; } - //Get the vertex data and store it in the paths. - for(auto& path : paths) + // Get the vertex data and store it in the paths. + for (auto& path : paths) { path.converted = path.getVertexData(); vertices_to_paths.emplace(path.vertices, &path); } - //If necessary, check polylines to see if they are actually polygons. - if(detect_loops) + // If necessary, check polylines to see if they are actually polygons. + if (detect_loops) { - for(auto& path : paths) + for (auto& path : paths) { - if(!path.is_closed) + if (! path.is_closed) { - //If we want to detect chains, first check if some of the polylines are secretly polygons. - path.is_closed = isLoopingPolyline(path); //If it is, we'll set the seam position correctly later. + // If we want to detect chains, first check if some of the polylines are secretly polygons. + path.is_closed = isLoopingPolyline(path); // If it is, we'll set the seam position correctly later. } } } - - //Add all vertices to a bucket grid so that we can find nearby endpoints quickly. + + // Add all vertices to a bucket grid so that we can find nearby endpoints quickly. const coord_t snap_radius = 10_mu; // 0.01mm grid cells. Chaining only needs to consider polylines which are next to each other. SparsePointGridInclusive line_bucket_grid(snap_radius); - for(const auto& [i, path]: paths | ranges::views::enumerate) + for (const auto& [i, path] : paths | ranges::views::enumerate) { if (path.converted->empty()) { continue; } - if(path.is_closed) + if (path.is_closed) { - for(const Point& point : *path.converted) + for (const Point& point : *path.converted) { - line_bucket_grid.insert(point, i); //Store by index so that we can also mark them down in the `picked` vector. + line_bucket_grid.insert(point, i); // Store by index so that we can also mark them down in the `picked` vector. } } - else //For polylines, only insert the endpoints. Those are the only places we can start from so the only relevant vertices to be near to. + else // For polylines, only insert the endpoints. Those are the only places we can start from so the only relevant vertices to be near to. { line_bucket_grid.insert(path.converted->front(), i); line_bucket_grid.insert(path.converted->back(), i); } } - //For some Z seam types the start position can be pre-computed. - //This is faster since we don't need to re-compute the start position at each step then. + // For some Z seam types the start position can be pre-computed. + // This is faster since we don't need to re-compute the start position at each step then. precompute_start &= seam_config.type == EZSeamType::RANDOM || seam_config.type == EZSeamType::USER_SPECIFIED || seam_config.type == EZSeamType::SHARPEST_CORNER; - if(precompute_start) + if (precompute_start) { - for(auto& path : paths) + for (auto& path : paths) { - if(!path.is_closed || path.converted->empty()) + if (! path.is_closed || path.converted->empty()) { - continue; //Can't pre-compute the seam for open polylines since they're at the endpoint nearest to the current position. + continue; // Can't pre-compute the seam for open polylines since they're at the endpoint nearest to the current position. } path.start_vertex = findStartLocation(path, seam_config.pos); } } - std::vector optimized_order; //To store our result in. At the end we'll std::swap. + std::vector optimized_order; // To store our result in. At the end we'll std::swap. if (order_requirements->empty()) { @@ -213,9 +221,9 @@ class PathOrderOptimizer } - if(reverse_direction && order_requirements->empty()) + if (reverse_direction && order_requirements->empty()) { - std::vector reversed = reverseOrderPaths(optimized_order); //Reverse-insert the optimized order, to invert the ordering. + std::vector reversed = reverseOrderPaths(optimized_order); // Reverse-insert the optimized order, to invert the ordering. std::swap(reversed, paths); } else @@ -225,6 +233,7 @@ class PathOrderOptimizer combing_grid.reset(); } + protected: /*! * If \ref detect_loops is enabled, endpoints of polylines that are closer @@ -276,18 +285,24 @@ class PathOrderOptimizer std::vector getOptimizedOrder(SparsePointGridInclusive line_bucket_grid, size_t snap_radius) { - std::vector optimized_order; //To store our result in. + std::vector optimized_order; // To store our result in. Point current_position = start_point; - std::unordered_map picked(paths.size()); //Fixed size boolean flag for whether each path is already in the optimized vector. + std::unordered_map picked(paths.size()); // Fixed size boolean flag for whether each path is already in the optimized vector. - auto isPicked = [&picked](OrderablePath* c) { return picked[c]; }; - auto notPicked = [&picked](OrderablePath* c) { return !picked[c]; }; + auto isPicked = [&picked](OrderablePath* c) + { + return picked[c]; + }; + auto notPicked = [&picked](OrderablePath* c) + { + return ! picked[c]; + }; - while(optimized_order.size() < paths.size()) + while (optimized_order.size() < paths.size()) { - //Use bucket grid to find paths within snap_radius + // Use bucket grid to find paths within snap_radius std::vector nearby_candidates; for (const auto i : line_bucket_grid.getNearbyVals(current_position, snap_radius)) { @@ -296,14 +311,14 @@ class PathOrderOptimizer std::vector available_candidates; available_candidates.reserve(nearby_candidates.size()); - for(auto candidate : nearby_candidates | ranges::views::filter(notPicked)) + for (auto candidate : nearby_candidates | ranges::views::filter(notPicked)) { available_candidates.push_back(candidate); } - if(available_candidates.empty()) // We need to broaden our search through all candidates + if (available_candidates.empty()) // We need to broaden our search through all candidates { - for(auto path : paths | ranges::views::addressof | ranges::views::filter(notPicked)) + for (auto path : paths | ranges::views::addressof | ranges::views::filter(notPicked)) { available_candidates.push_back(path); } @@ -315,15 +330,15 @@ class PathOrderOptimizer optimized_order.push_back(*best_path); picked[best_path] = true; - if(!best_path->converted->empty()) //If all paths were empty, the best path is still empty. We don't upate the current position then. + if (! best_path->converted->empty()) // If all paths were empty, the best path is still empty. We don't upate the current position then. { - if(best_path->is_closed) + if (best_path->is_closed) { - current_position = (*best_path->converted)[best_path->start_vertex]; //We end where we started. + current_position = (*best_path->converted)[best_path->start_vertex]; // We end where we started. } else { - //Pick the other end from where we started. + // Pick the other end from where we started. current_position = best_path->start_vertex == 0 ? best_path->converted->back() : best_path->converted->front(); } } @@ -332,9 +347,10 @@ class PathOrderOptimizer return optimized_order; } - std::vector getOptimizerOrderWithConstraints(SparsePointGridInclusive line_bucket_grid, size_t snap_radius, const std::unordered_multimap& order_requirements) + std::vector + getOptimizerOrderWithConstraints(SparsePointGridInclusive line_bucket_grid, size_t snap_radius, const std::unordered_multimap& order_requirements) { - std::vector optimized_order; //To store our result in. + std::vector optimized_order; // To store our result in. // initialize the roots set with all possible nodes std::unordered_set roots; @@ -358,8 +374,8 @@ class PathOrderOptimizer std::unordered_set visited; Point current_position = start_point; - std::function(const Path, const std::unordered_multimap&)> get_neighbours = - [current_position, this](const Path current_node, const std::unordered_multimap& graph) + std::function(const Path, const std::unordered_multimap&)> get_neighbours + = [current_position, this](const Path current_node, const std::unordered_multimap& graph) { std::vector order; // Output order to traverse neighbors @@ -382,13 +398,13 @@ class PathOrderOptimizer // update local_current_position auto path = vertices_to_paths[best_candidate]; - if(path->is_closed) + if (path->is_closed) { - local_current_position = (*path->converted)[path->start_vertex]; //We end where we started. + local_current_position = (*path->converted)[path->start_vertex]; // We end where we started. } else { - //Pick the other end from where we started. + // Pick the other end from where we started. local_current_position = path->start_vertex == 0 ? path->converted->back() : path->converted->front(); } } @@ -396,34 +412,33 @@ class PathOrderOptimizer return order; }; - const std::function handle_node = - [¤t_position, &optimized_order, this] - (const Path current_node, const std::nullptr_t _state) + const std::function handle_node + = [¤t_position, &optimized_order, this](const Path current_node, const std::nullptr_t _state) + { + // We should make map from node <-> path for this stuff + for (auto& path : paths) { - // We should make map from node <-> path for this stuff - for (auto& path : paths) + if (path.vertices == current_node) { - if (path.vertices == current_node) + if (path.is_closed) { - if(path.is_closed) - { - current_position = (*path.converted)[path.start_vertex]; //We end where we started. - } - else - { - //Pick the other end from where we started. - current_position = path.start_vertex == 0 ? path.converted->back() : path.converted->front(); - } - - // Add to optimized order - optimized_order.push_back(path); - - break; + current_position = (*path.converted)[path.start_vertex]; // We end where we started. } + else + { + // Pick the other end from where we started. + current_position = path.start_vertex == 0 ? path.converted->back() : path.converted->front(); + } + + // Add to optimized order + optimized_order.push_back(path); + + break; } + } - return nullptr; - }; + return nullptr; + }; if (group_outer_walls) { @@ -482,7 +497,7 @@ class PathOrderOptimizer } else { - while (!roots.empty()) + while (! roots.empty()) { Path root = findClosestPathVertices(current_position, roots); roots.erase(root); @@ -497,13 +512,13 @@ class PathOrderOptimizer std::vector reverseOrderPaths(std::vector pathsOrderPaths) { std::vector reversed; - //Don't replace with swap, assign or insert. They require functions that we can't implement for all template arguments for Path. + // Don't replace with swap, assign or insert. They require functions that we can't implement for all template arguments for Path. reversed.reserve(pathsOrderPaths.size()); - for(auto& path: pathsOrderPaths | ranges::views::reverse) + for (auto& path : pathsOrderPaths | ranges::views::reverse) { reversed.push_back(path); - reversed.back().backwards = !reversed.back().backwards; - if(!reversed.back().is_closed) + reversed.back().backwards = ! reversed.back().backwards; + if (! reversed.back().is_closed) { reversed.back().start_vertex = reversed.back().converted->size() - 1 - reversed.back().start_vertex; } @@ -530,33 +545,35 @@ class PathOrderOptimizer coord_t best_distance2 = std::numeric_limits::max(); OrderablePath* best_candidate = 0; - for(OrderablePath* path : candidate_paths) + for (OrderablePath* path : candidate_paths) { - if(path->converted->empty()) //No vertices in the path. Can't find the start position then or really plan it in. Put that at the end. + if (path->converted->empty()) // No vertices in the path. Can't find the start position then or really plan it in. Put that at the end. { - if(best_distance2 == std::numeric_limits::max()) + if (best_distance2 == std::numeric_limits::max()) { best_candidate = path; } continue; } - const bool precompute_start = seam_config.type == EZSeamType::RANDOM || seam_config.type == EZSeamType::USER_SPECIFIED || seam_config.type == EZSeamType::SHARPEST_CORNER; - if(!path->is_closed || !precompute_start) //Find the start location unless we've already precomputed it. + const bool precompute_start + = seam_config.type == EZSeamType::RANDOM || seam_config.type == EZSeamType::USER_SPECIFIED || seam_config.type == EZSeamType::SHARPEST_CORNER; + if (! path->is_closed || ! precompute_start) // Find the start location unless we've already precomputed it. { path->start_vertex = findStartLocation(*path, start_position); - if(!path->is_closed) //Open polylines start at vertex 0 or vertex N-1. Indicate that they should be reversed if they start at N-1. + if (! path->is_closed) // Open polylines start at vertex 0 or vertex N-1. Indicate that they should be reversed if they start at N-1. { path->backwards = path->start_vertex > 0; } } const Point candidate_position = (*path->converted)[path->start_vertex]; coord_t distance2 = getDirectDistance(start_position, candidate_position); - if(distance2 < best_distance2 && combing_boundary) //If direct distance is longer than best combing distance, the combing distance can never be better, so only compute combing if necessary. + if (distance2 < best_distance2 + && combing_boundary) // If direct distance is longer than best combing distance, the combing distance can never be better, so only compute combing if necessary. { distance2 = getCombingDistance(start_position, candidate_position); } - if(distance2 < best_distance2) //Closer than the best candidate so far. + if (distance2 < best_distance2) // Closer than the best candidate so far. { best_candidate = path; best_distance2 = distance2; @@ -589,30 +606,31 @@ class PathOrderOptimizer * applicable. * \param is_closed Whether the polygon is closed (a polygon) or not * (a polyline). If the path is not closed, it will choose between the two - * endpoints rather than + * endpoints rather than * \return An index to a vertex in that path where printing must start. */ size_t findStartLocation(const OrderablePath& path, const Point& target_pos) { - if(!path.is_closed) + if (! path.is_closed) { - //For polylines, the seam settings are not applicable. Simply choose the position closest to target_pos then. - const coord_t back_distance = (combing_boundary == nullptr) - ? getDirectDistance(path.converted->back(), target_pos) - : getCombingDistance(path.converted->back(), target_pos); - if(back_distance < getDirectDistance(path.converted->front(), target_pos) || (combing_boundary && back_distance < getCombingDistance(path.converted->front(), target_pos))) //Lazy or: Only compute combing distance if direct distance is closer. + // For polylines, the seam settings are not applicable. Simply choose the position closest to target_pos then. + const coord_t back_distance + = (combing_boundary == nullptr) ? getDirectDistance(path.converted->back(), target_pos) : getCombingDistance(path.converted->back(), target_pos); + if (back_distance < getDirectDistance(path.converted->front(), target_pos) + || (combing_boundary + && back_distance < getCombingDistance(path.converted->front(), target_pos))) // Lazy or: Only compute combing distance if direct distance is closer. { - return path.converted->size() - 1; //Back end is closer. + return path.converted->size() - 1; // Back end is closer. } else { - return 0; //Front end is closer. + return 0; // Front end is closer. } } - //Rest of the function only deals with (closed) polygons. We need to be able to find the seam location of those polygons. + // Rest of the function only deals with (closed) polygons. We need to be able to find the seam location of those polygons. - if(seam_config.type == EZSeamType::RANDOM) + if (seam_config.type == EZSeamType::RANDOM) { size_t vert = getRandomPointInPolygon(*path.converted); return vert; @@ -620,14 +638,14 @@ class PathOrderOptimizer size_t best_i; float best_score = std::numeric_limits::infinity(); - for(const auto& [i, here]: **path.converted | ranges::views::enumerate) + for (const auto& [i, here] : **path.converted | ranges::views::enumerate) { - //For most seam types, the shortest distance matters. Not for SHARPEST_CORNER though. - //For SHARPEST_CORNER, use a fixed starting score of 0. - const coord_t distance = (combing_boundary == nullptr) - ? getDirectDistance(here, target_pos) - : getCombingDistance(here, target_pos); - const float score_distance = (seam_config.type == EZSeamType::SHARPEST_CORNER && seam_config.corner_pref != EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE) ? MM2INT(10) : vSize2(here - target_pos); + // For most seam types, the shortest distance matters. Not for SHARPEST_CORNER though. + // For SHARPEST_CORNER, use a fixed starting score of 0. + const coord_t distance = (combing_boundary == nullptr) ? getDirectDistance(here, target_pos) : getCombingDistance(here, target_pos); + const float score_distance = (seam_config.type == EZSeamType::SHARPEST_CORNER && seam_config.corner_pref != EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE) + ? MM2INT(10) + : vSize2(here - target_pos); float corner_angle = cornerAngle(path, i); // angles < 0 are concave (left turning) @@ -650,30 +668,30 @@ class PathOrderOptimizer } float score = score_distance; - switch(seam_config.corner_pref) + switch (seam_config.corner_pref) { default: case EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_INNER: - if(corner_angle < 0) // Indeed a concave corner? Give it some advantage over other corners. More advantage for sharper corners. + if (corner_angle < 0) // Indeed a concave corner? Give it some advantage over other corners. More advantage for sharper corners. { score += corner_angle * corner_shift; } break; case EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_OUTER: - if(corner_angle > 0) // Indeed a convex corner? + if (corner_angle > 0) // Indeed a convex corner? { score -= corner_angle * corner_shift; } break; case EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_ANY: - score -= std::abs(corner_angle) * corner_shift; //Still give sharper corners more advantage. + score -= std::abs(corner_angle) * corner_shift; // Still give sharper corners more advantage. break; case EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE: break; - case EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_WEIGHTED: //Give sharper corners some advantage, but sharper concave corners even more. + case EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_WEIGHTED: // Give sharper corners some advantage, but sharper concave corners even more. { float score_corner = std::abs(corner_angle) * corner_shift; - if(corner_angle < 0) //Concave corner. + if (corner_angle < 0) // Concave corner. { score_corner *= 2; } @@ -683,7 +701,7 @@ class PathOrderOptimizer } constexpr float EPSILON = 25.0; - if(std::abs(best_score - score) <= EPSILON) + if (std::abs(best_score - score) <= EPSILON) { // add breaker for two candidate starting location with similar score // if we don't do this then we (can) get an un-even seam @@ -691,13 +709,13 @@ class PathOrderOptimizer // if x-coord for both points are equal then break ties by // favouring points with lower y-coord const Point& best_point = (*path.converted)[best_i]; - if(std::abs(here.Y - best_point.Y) <= EPSILON ? best_point.X < here.X : best_point.Y < here.Y) + if (std::abs(here.Y - best_point.Y) <= EPSILON ? best_point.X < here.X : best_point.Y < here.Y) { best_score = std::min(best_score, score); best_i = i; } } - else if(score < best_score) + else if (score < best_score) { best_i = i; best_score = score; @@ -720,7 +738,7 @@ class PathOrderOptimizer Point prev_pos = here_pos; Point next_pos; - while(actual_distance < distance) + while (actual_distance < distance) { actual_delta += direction; next_pos = (*path.converted)[(here + actual_delta + path.converted->size()) % path.converted->size()]; @@ -728,9 +746,9 @@ class PathOrderOptimizer prev_pos = next_pos; } - if(actual_distance > distance) // Which is veeeery likely + if (actual_distance > distance) // Which is veeeery likely { - prev_pos = (*path.converted)[(here + actual_delta -direction + path.converted->size()) % path.converted->size()]; + prev_pos = (*path.converted)[(here + actual_delta - direction + path.converted->size()) % path.converted->size()]; Point vector = next_pos - prev_pos; coord_t vector_size = vSize(vector); @@ -745,18 +763,18 @@ class PathOrderOptimizer } /*! - * Some models have very sharp corners, but also have a high resolution. If a sharp corner - * consists of many points each point individual might have a shallow corner, but the - * collective angle of all nearby points is greater. To counter this the cornerAngle is - * calculated from all points within angle_query_distance of the query point. Angles closer - * to the current point are weighted more towards the total angle then points further away. - * The formula for the angle weight is: 1 - (distance_to_query / angle_query_distance)^fall_off_strength - * \param path The vertex data of a path - * \param i index of the query point - * \param angle_query_distance query range (default to 0.1mm) - * \param fall_off_strength fall of strength of the angle weight - * \return sum of angles of all points p in range i - angle_query_distance < p < i + angle_query_distance - */ + * Some models have very sharp corners, but also have a high resolution. If a sharp corner + * consists of many points each point individual might have a shallow corner, but the + * collective angle of all nearby points is greater. To counter this the cornerAngle is + * calculated from all points within angle_query_distance of the query point. Angles closer + * to the current point are weighted more towards the total angle then points further away. + * The formula for the angle weight is: 1 - (distance_to_query / angle_query_distance)^fall_off_strength + * \param path The vertex data of a path + * \param i index of the query point + * \param angle_query_distance query range (default to 0.1mm) + * \param fall_off_strength fall of strength of the angle weight + * \return sum of angles of all points p in range i - angle_query_distance < p < i + angle_query_distance + */ float cornerAngle(const OrderablePath& path, int i, const coord_t angle_query_distance = 100, const float fall_off_strength = 0.5) { static constexpr coord_t distance_step = 2000; @@ -767,7 +785,7 @@ class PathOrderOptimizer float angle = 0.0; int computed_angles = 0; - for(coord_t distance = distance_step ; distance <= max_distance ; distance += distance_step) + for (coord_t distance = distance_step; distance <= max_distance; distance += distance_step) { Point next = findNeighbourPoint(path, i, distance); Point previous = findNeighbourPoint(path, i, -distance); @@ -806,11 +824,11 @@ class PathOrderOptimizer */ coord_t getCombingDistance(const Point& a, const Point& b) { - if(!PolygonUtils::polygonCollidesWithLineSegment(*combing_boundary, a, b)) + if (! PolygonUtils::polygonCollidesWithLineSegment(*combing_boundary, a, b)) { - return getDirectDistance(a, b); //No collision with any line. Just compute the direct distance then. + return getDirectDistance(a, b); // No collision with any line. Just compute the direct distance then. } - if(paths.size() > 100) + if (paths.size() > 100) { /* If we have many paths to optimize the order for, this combing calculation can become very expensive. Instead, penalize travels @@ -818,13 +836,13 @@ class PathOrderOptimizer return getDirectDistance(a, b) * 5; } - if(combing_grid == nullptr) + if (combing_grid == nullptr) { - constexpr coord_t grid_size = 2000; //2mm grid cells. Smaller will use more memory, but reduce chance of unnecessary collision checks. + constexpr coord_t grid_size = 2000; // 2mm grid cells. Smaller will use more memory, but reduce chance of unnecessary collision checks. combing_grid = PolygonUtils::createLocToLineGrid(*combing_boundary, grid_size); } - CombPath comb_path; //Output variable. + CombPath comb_path; // Output variable. constexpr coord_t rounding_error = -25; constexpr coord_t tiny_travel_threshold = 0; constexpr bool fail_on_unavoidable_obstacles = false; @@ -832,12 +850,12 @@ class PathOrderOptimizer coord_t sum = 0; Point last_point = a; - for(const Point& point : comb_path) + for (const Point& point : comb_path) { sum += vSize(point - last_point); last_point = point; } - return sum * sum; //Squared distance, for fair comparison with direct distance. + return sum * sum; // Squared distance, for fair comparison with direct distance. } /*! @@ -852,7 +870,7 @@ class PathOrderOptimizer bool isLoopingPolyline(const OrderablePath& path) { - if(path.converted->empty()) + if (path.converted->empty()) { return false; } @@ -863,6 +881,6 @@ class PathOrderOptimizer template const std::unordered_multimap PathOrderOptimizer::no_order_requirements; -} //namespace cura +} // namespace cura -#endif //PATHORDEROPTIMIZER_H +#endif // PATHORDEROPTIMIZER_H From 9311a7fa06f505d51da42d1af33e0d86f632a806 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 6 Oct 2023 13:07:14 +0200 Subject: [PATCH 19/56] Clean and optimized new corner angle computation algorithm CURA-11100 --- include/PathOrderOptimizer.h | 136 ++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 58 deletions(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index 939baf6b21..108b49b61a 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -636,18 +636,35 @@ class PathOrderOptimizer return vert; } + //Precompute segments lengths because we are going to need them multiple times + std::vector segments_sizes(path.converted->size()); + coord_t total_length = 0; + for(const auto& [i, here]: **path.converted | ranges::views::enumerate) + { + const Point &next = (*path.converted)[(i + 1) % path.converted->size()]; + coord_t segment_size = vSize(next - here); + segments_sizes[i] = segment_size; + total_length += segment_size; + } + size_t best_i; float best_score = std::numeric_limits::infinity(); for (const auto& [i, here] : **path.converted | ranges::views::enumerate) { - // For most seam types, the shortest distance matters. Not for SHARPEST_CORNER though. - // For SHARPEST_CORNER, use a fixed starting score of 0. - const coord_t distance = (combing_boundary == nullptr) ? getDirectDistance(here, target_pos) : getCombingDistance(here, target_pos); - const float score_distance = (seam_config.type == EZSeamType::SHARPEST_CORNER && seam_config.corner_pref != EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE) - ? MM2INT(10) - : vSize2(here - target_pos); + if(i == path.converted->size() - 1) + { + //The path is closed so the last point is the same as the first, don't process it twice + continue; + } - float corner_angle = cornerAngle(path, i); + //For most seam types, the shortest distance matters. Not for SHARPEST_CORNER though. + //For SHARPEST_CORNER, use a fixed starting score of 0. + const coord_t distance = (combing_boundary == nullptr) + ? getDirectDistance(here, target_pos) + : getCombingDistance(here, target_pos); + const float score_distance = (seam_config.type == EZSeamType::SHARPEST_CORNER && seam_config.corner_pref != EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE) ? MM2INT(10) : vSize2(here - target_pos); + + float corner_angle = cornerAngle(path, i, segments_sizes, total_length); // angles < 0 are concave (left turning) // angles > 0 are convex (right turning) @@ -725,79 +742,82 @@ class PathOrderOptimizer return best_i; } - Point findNeighbourPoint(const OrderablePath& path, int here, coord_t distance) + /*! + * Finds a neighbour point on the path, located before or after the given reference point. The neighbour point + * is computed by travelling on the path and stopping when the distance has been reached, For example: + * |------|---------|------|--------------*---| + * H A B C N D + * In this case, H is the start point of the path and ABCD are the actual following points of the path. + * The neighbour point N is found by reaching point D then going a bit backward on the previous segment. + * This approach gets rid of the mesh actual resolution and gives a neighbour point that is on the path + * at a given physical distance. + * \param path The vertex data of a path + * \param here The starting point index + * \param distance The distance we want to travel on the path, which may be positive to go forward + * or negative to go backward + * \param segments_sizes The pre-computed sizes of the segments + * \return The position of the path a the given distance from the reference point + */ + static Point findNeighbourPoint(const OrderablePath& path, int here, coord_t distance, const std::vector &segments_sizes) { - assert(distance); - - const Point here_pos = (*path.converted)[here]; - int direction = distance > 0 ? 1 : -1; + const int direction = distance > 0 ? 1 : -1; + const int size_delta = distance > 0 ? -1 : 0; distance = std::abs(distance); - coord_t actual_distance = 0; + // Travel on the path until we reach the distance int actual_delta = 0; - - Point prev_pos = here_pos; - Point next_pos; - while (actual_distance < distance) + coord_t travelled_distance = 0; + coord_t segment_size = 0; + while(travelled_distance < distance) { actual_delta += direction; - next_pos = (*path.converted)[(here + actual_delta + path.converted->size()) % path.converted->size()]; - actual_distance += vSize(next_pos - prev_pos); - prev_pos = next_pos; + segment_size = segments_sizes[(here + actual_delta + size_delta + path.converted->size()) % path.converted->size()]; + travelled_distance += segment_size; } - if (actual_distance > distance) // Which is veeeery likely + const Point &next_pos = (*path.converted)[(here + actual_delta + path.converted->size()) % path.converted->size()]; + + if(travelled_distance > distance) [[likely]] { - prev_pos = (*path.converted)[(here + actual_delta - direction + path.converted->size()) % path.converted->size()]; + // We have overtaken the required distance, go backward on the last segment + int prev = (here + actual_delta -direction + path.converted->size()) % path.converted->size(); + const Point &prev_pos = (*path.converted)[prev]; - Point vector = next_pos - prev_pos; - coord_t vector_size = vSize(vector); - Point unit_vector = (vector * 1000) / vector_size; - Point vector_delta = unit_vector * (vector_size - (actual_distance - distance)); + const Point vector = next_pos - prev_pos; + const Point unit_vector = (vector * 1000) / segment_size; + const Point vector_delta = unit_vector * (segment_size - (travelled_distance - distance)); return prev_pos + vector_delta / 1000; } else { + // Luckily, the required distance stops exactly on an existing point return next_pos; } } /*! - * Some models have very sharp corners, but also have a high resolution. If a sharp corner - * consists of many points each point individual might have a shallow corner, but the - * collective angle of all nearby points is greater. To counter this the cornerAngle is - * calculated from all points within angle_query_distance of the query point. Angles closer - * to the current point are weighted more towards the total angle then points further away. - * The formula for the angle weight is: 1 - (distance_to_query / angle_query_distance)^fall_off_strength - * \param path The vertex data of a path - * \param i index of the query point - * \param angle_query_distance query range (default to 0.1mm) - * \param fall_off_strength fall of strength of the angle weight - * \return sum of angles of all points p in range i - angle_query_distance < p < i + angle_query_distance - */ - float cornerAngle(const OrderablePath& path, int i, const coord_t angle_query_distance = 100, const float fall_off_strength = 0.5) + * Some models have very sharp corners, but also have a high resolution. If a sharp corner + * consists of many points each point individual might have a shallow corner, but the + * collective angle of all nearby points is greater. To counter this the cornerAngle is + * calculated from two points within angle_query_distance of the query point, no matter + * what segment this leads us to + * \param path The vertex data of a path + * \param i index of the query point + * \param segments_sizes The pre-computed sizes of the segments + * \param total_length The path total length + * \param angle_query_distance query range (default to 1mm) + * \return angle between the reference point and the two sibling points, weighed to [-1.0 ; 1.0] + */ + static float cornerAngle(const OrderablePath& path, int i, const std::vector &segments_sizes, coord_t total_length, const coord_t angle_query_distance = 1000) { - static constexpr coord_t distance_step = 2000; - static constexpr coord_t max_distance = 5000; - - const Point here = (*path.converted)[i]; - - float angle = 0.0; - int computed_angles = 0; - - for (coord_t distance = distance_step; distance <= max_distance; distance += distance_step) - { - Point next = findNeighbourPoint(path, i, distance); - Point previous = findNeighbourPoint(path, i, -distance); - - angle += LinearAlg2D::getAngleLeft(previous, here, next) - M_PI; - computed_angles++; - } + const coord_t bounded_distance = std::min(angle_query_distance, total_length / 2); + const Point &here = (*path.converted)[i]; + const Point next = findNeighbourPoint(path, i, bounded_distance, segments_sizes); + const Point previous = findNeighbourPoint(path, i, -bounded_distance, segments_sizes); - angle /= computed_angles; - angle /= M_PI; + float angle = LinearAlg2D::getAngleLeft(previous, here, next) - M_PI; - return angle; + return angle / M_PI; } /*! From 55c43275b86220ab88fe3aeb3e61b4d56e26d8cc Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Fri, 6 Oct 2023 11:12:44 +0000 Subject: [PATCH 20/56] Applied clang-format. --- include/PathOrderOptimizer.h | 62 ++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index 108b49b61a..d8d6d9ca17 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -636,12 +636,12 @@ class PathOrderOptimizer return vert; } - //Precompute segments lengths because we are going to need them multiple times + // Precompute segments lengths because we are going to need them multiple times std::vector segments_sizes(path.converted->size()); coord_t total_length = 0; - for(const auto& [i, here]: **path.converted | ranges::views::enumerate) + for (const auto& [i, here] : **path.converted | ranges::views::enumerate) { - const Point &next = (*path.converted)[(i + 1) % path.converted->size()]; + const Point& next = (*path.converted)[(i + 1) % path.converted->size()]; coord_t segment_size = vSize(next - here); segments_sizes[i] = segment_size; total_length += segment_size; @@ -651,18 +651,18 @@ class PathOrderOptimizer float best_score = std::numeric_limits::infinity(); for (const auto& [i, here] : **path.converted | ranges::views::enumerate) { - if(i == path.converted->size() - 1) + if (i == path.converted->size() - 1) { - //The path is closed so the last point is the same as the first, don't process it twice + // The path is closed so the last point is the same as the first, don't process it twice continue; } - //For most seam types, the shortest distance matters. Not for SHARPEST_CORNER though. - //For SHARPEST_CORNER, use a fixed starting score of 0. - const coord_t distance = (combing_boundary == nullptr) - ? getDirectDistance(here, target_pos) - : getCombingDistance(here, target_pos); - const float score_distance = (seam_config.type == EZSeamType::SHARPEST_CORNER && seam_config.corner_pref != EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE) ? MM2INT(10) : vSize2(here - target_pos); + // For most seam types, the shortest distance matters. Not for SHARPEST_CORNER though. + // For SHARPEST_CORNER, use a fixed starting score of 0. + const coord_t distance = (combing_boundary == nullptr) ? getDirectDistance(here, target_pos) : getCombingDistance(here, target_pos); + const float score_distance = (seam_config.type == EZSeamType::SHARPEST_CORNER && seam_config.corner_pref != EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE) + ? MM2INT(10) + : vSize2(here - target_pos); float corner_angle = cornerAngle(path, i, segments_sizes, total_length); // angles < 0 are concave (left turning) @@ -758,7 +758,7 @@ class PathOrderOptimizer * \param segments_sizes The pre-computed sizes of the segments * \return The position of the path a the given distance from the reference point */ - static Point findNeighbourPoint(const OrderablePath& path, int here, coord_t distance, const std::vector &segments_sizes) + static Point findNeighbourPoint(const OrderablePath& path, int here, coord_t distance, const std::vector& segments_sizes) { const int direction = distance > 0 ? 1 : -1; const int size_delta = distance > 0 ? -1 : 0; @@ -768,20 +768,20 @@ class PathOrderOptimizer int actual_delta = 0; coord_t travelled_distance = 0; coord_t segment_size = 0; - while(travelled_distance < distance) + while (travelled_distance < distance) { actual_delta += direction; segment_size = segments_sizes[(here + actual_delta + size_delta + path.converted->size()) % path.converted->size()]; travelled_distance += segment_size; } - const Point &next_pos = (*path.converted)[(here + actual_delta + path.converted->size()) % path.converted->size()]; + const Point& next_pos = (*path.converted)[(here + actual_delta + path.converted->size()) % path.converted->size()]; - if(travelled_distance > distance) [[likely]] + if (travelled_distance > distance) [[likely]] { // We have overtaken the required distance, go backward on the last segment - int prev = (here + actual_delta -direction + path.converted->size()) % path.converted->size(); - const Point &prev_pos = (*path.converted)[prev]; + int prev = (here + actual_delta - direction + path.converted->size()) % path.converted->size(); + const Point& prev_pos = (*path.converted)[prev]; const Point vector = next_pos - prev_pos; const Point unit_vector = (vector * 1000) / segment_size; @@ -796,22 +796,22 @@ class PathOrderOptimizer } /*! - * Some models have very sharp corners, but also have a high resolution. If a sharp corner - * consists of many points each point individual might have a shallow corner, but the - * collective angle of all nearby points is greater. To counter this the cornerAngle is - * calculated from two points within angle_query_distance of the query point, no matter - * what segment this leads us to - * \param path The vertex data of a path - * \param i index of the query point - * \param segments_sizes The pre-computed sizes of the segments - * \param total_length The path total length - * \param angle_query_distance query range (default to 1mm) - * \return angle between the reference point and the two sibling points, weighed to [-1.0 ; 1.0] - */ - static float cornerAngle(const OrderablePath& path, int i, const std::vector &segments_sizes, coord_t total_length, const coord_t angle_query_distance = 1000) + * Some models have very sharp corners, but also have a high resolution. If a sharp corner + * consists of many points each point individual might have a shallow corner, but the + * collective angle of all nearby points is greater. To counter this the cornerAngle is + * calculated from two points within angle_query_distance of the query point, no matter + * what segment this leads us to + * \param path The vertex data of a path + * \param i index of the query point + * \param segments_sizes The pre-computed sizes of the segments + * \param total_length The path total length + * \param angle_query_distance query range (default to 1mm) + * \return angle between the reference point and the two sibling points, weighed to [-1.0 ; 1.0] + */ + static float cornerAngle(const OrderablePath& path, int i, const std::vector& segments_sizes, coord_t total_length, const coord_t angle_query_distance = 1000) { const coord_t bounded_distance = std::min(angle_query_distance, total_length / 2); - const Point &here = (*path.converted)[i]; + const Point& here = (*path.converted)[i]; const Point next = findNeighbourPoint(path, i, bounded_distance, segments_sizes); const Point previous = findNeighbourPoint(path, i, -bounded_distance, segments_sizes); From 57a0daec11b3b5e76af7df4c500c35e39b672b3b Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 9 Oct 2023 10:38:33 +0200 Subject: [PATCH 21/56] Removed debug output --- src/SkeletalTrapezoidationGraph.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/SkeletalTrapezoidationGraph.cpp b/src/SkeletalTrapezoidationGraph.cpp index ed8cc1035d..4657b8ee97 100644 --- a/src/SkeletalTrapezoidationGraph.cpp +++ b/src/SkeletalTrapezoidationGraph.cpp @@ -3,17 +3,18 @@ #include "SkeletalTrapezoidationGraph.h" -#include +#include "utils/linearAlg2D.h" +#include "utils/macros.h" #include -#include "utils/linearAlg2D.h" -#include "utils/macros.h" +#include namespace cura { -STHalfEdge::STHalfEdge(SkeletalTrapezoidationEdge data) : HalfEdge(data) +STHalfEdge::STHalfEdge(SkeletalTrapezoidationEdge data) + : HalfEdge(data) { } @@ -131,7 +132,8 @@ STHalfEdge* STHalfEdge::getNextUnconnected() return result->twin; } -STHalfEdgeNode::STHalfEdgeNode(SkeletalTrapezoidationJoint data, Point p) : HalfEdgeNode(data, p) +STHalfEdgeNode::STHalfEdgeNode(SkeletalTrapezoidationJoint data, Point p) + : HalfEdgeNode(data, p) { } @@ -223,7 +225,10 @@ void SkeletalTrapezoidationGraph::collapseSmallEdges(coord_t snap_dist) } }; - auto should_collapse = [snap_dist](node_t* a, node_t* b) { return shorterThen(a->p - b->p, snap_dist); }; + auto should_collapse = [snap_dist](node_t* a, node_t* b) + { + return shorterThen(a->p - b->p, snap_dist); + }; for (auto edge_it = edges.begin(); edge_it != edges.end();) { @@ -253,10 +258,6 @@ void SkeletalTrapezoidationGraph::collapseSmallEdges(coord_t snap_dist) { edge_from_3->from = quad_mid->from; edge_from_3->twin->to = quad_mid->from; - if (count > 50) - { - std::cerr << edge_from_3->from->p << " - " << edge_from_3->to->p << '\n'; - } if (++count > 1000) { break; From 26ea92b20a383b9f4dcfba7f432a66923d11dd9c Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 9 Oct 2023 10:52:13 +0200 Subject: [PATCH 22/56] Fixed some edge-cases with new angle calculation CURA-11100 --- include/PathOrderOptimizer.h | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index d8d6d9ca17..ab58d30651 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -689,16 +689,12 @@ class PathOrderOptimizer { default: case EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_INNER: - if (corner_angle < 0) // Indeed a concave corner? Give it some advantage over other corners. More advantage for sharper corners. - { - score += corner_angle * corner_shift; - } + // Give advantage to concave corners. More advantage for sharper corners. + score += corner_angle * corner_shift; break; case EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_OUTER: - if (corner_angle > 0) // Indeed a convex corner? - { - score -= corner_angle * corner_shift; - } + // Give advantage to convex corners. More advantage for sharper corners. + score -= corner_angle * corner_shift; break; case EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_ANY: score -= std::abs(corner_angle) * corner_shift; // Still give sharper corners more advantage. @@ -717,7 +713,7 @@ class PathOrderOptimizer } } - constexpr float EPSILON = 25.0; + constexpr float EPSILON = 5.0; if (std::abs(best_score - score) <= EPSILON) { // add breaker for two candidate starting location with similar score From 31399b138dfd827ee31ac38b23e9e7c8d2afe4cc Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 5 Oct 2023 11:48:49 +0200 Subject: [PATCH 23/56] Remove unused variable boyscouting CURA-11110 --- src/skin.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/skin.cpp b/src/skin.cpp index 227591a8c4..28fc60c238 100644 --- a/src/skin.cpp +++ b/src/skin.cpp @@ -346,8 +346,6 @@ void SkinInfillAreaComputation::generateRoofingFillAndSkinFill(SliceLayerPart& p */ Polygons SkinInfillAreaComputation::generateFilledAreaAbove(SliceLayerPart& part, size_t roofing_layer_count) { - const size_t wall_idx = std::min(size_t(2), mesh.settings.get("wall_line_count")); - Polygons filled_area_above = getOutlineOnLayer(part, layer_nr + roofing_layer_count); if (! no_small_gaps_heuristic) { From e44da002c65a2ed90a1d961c836a4a48158d28fd Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 5 Oct 2023 12:45:17 +0200 Subject: [PATCH 24/56] Use different config for roofing inner/outer walls Implementation is not fully desired since it has some downsides 1. When a layer-part is partially a roof the whole outer/inner wall uses the inner/outer wall roofing print-configuration 2. Some logic is duplicated, namely the function that calculates the `filled_area_above`. This function previously lived in `SkinInfillAreaComputation`. It's not logical to create a `SkinInfillAreaComputation` instance just to re-use this utility. Proposal to fix this is to move the logic of calculating the `filled_area_above` to a more central location, this will be done in a seperate ticket. 3. The `inset0_roofing_config` and `insetX_roofing_config` contain `line_width` properties. Changing the line-widths here doesn't actually change the line width. The line widths can only be changed through the `insetX_config` and `inset0_config` configs CURA-11110 --- include/settings/MeshPathConfigs.h | 2 + src/FffGcodeWriter.cpp | 96 +++++++++++++++++++++++++++++- src/settings/MeshPathConfigs.cpp | 26 ++++++++ 3 files changed, 122 insertions(+), 2 deletions(-) diff --git a/include/settings/MeshPathConfigs.h b/include/settings/MeshPathConfigs.h index 43457fbc8c..61c993b9a8 100644 --- a/include/settings/MeshPathConfigs.h +++ b/include/settings/MeshPathConfigs.h @@ -15,6 +15,8 @@ struct MeshPathConfigs { GCodePathConfig inset0_config{}; GCodePathConfig insetX_config{}; + GCodePathConfig inset0_roofing_config{}; + GCodePathConfig insetX_roofing_config{}; GCodePathConfig bridge_inset0_config{}; GCodePathConfig bridge_insetX_config{}; GCodePathConfig skin_config{}; diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index aedd5d439b..c3750c3b18 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -21,6 +21,8 @@ #include "utils/math.h" #include "utils/orderOptimizer.h" +#include +#include #include #include @@ -2392,6 +2394,96 @@ bool FffGcodeWriter::processInsets( } else { + // for layers that (partially) do not have any layers above we apply the roofing configuration + auto use_roofing_config = [&part, &mesh, &gcode_layer](){ + const auto getOutlineOnLayer = [mesh](const SliceLayerPart& part_here, const LayerIndex layer2_nr) -> Polygons + { + Polygons result; + if (layer2_nr >= static_cast(mesh.layers.size())) + { + return result; + } + const SliceLayer& layer2 = mesh.layers[layer2_nr]; + for (const SliceLayerPart& part2 : layer2.parts) + { + if (part_here.boundaryBox.hit(part2.boundaryBox)) + { + result.add(part2.outline); + } + } + return result; + }; + + const auto filled_area_above = [&getOutlineOnLayer, &part, &mesh, &gcode_layer]() -> Polygons + { + const size_t roofing_layer_count = std::min(mesh.settings.get("roofing_layer_count"), mesh.settings.get("top_layers")); + const bool no_small_gaps_heuristic = mesh.settings.get("skin_no_small_gaps_heuristic"); + const int layer_nr = gcode_layer.getLayerNr(); + auto filled_area_above = getOutlineOnLayer(part, layer_nr + roofing_layer_count); + if (! no_small_gaps_heuristic) + { + for (int layer_nr_above = layer_nr + 1; layer_nr_above < layer_nr + roofing_layer_count; layer_nr_above++) + { + Polygons outlines_above = getOutlineOnLayer(part, layer_nr_above); + filled_area_above = filled_area_above.intersection(outlines_above); + } + } + if (layer_nr > 0) + { + // if the skin has air below it then cutting it into regions could cause a region + // to be wholely or partly above air and it may not be printable so restrict + // the regions that have air above (the visible regions) to not include any area that + // has air below (fixes https://github.com/Ultimaker/Cura/issues/2656) + + // set air_below to the skin area for the current layer that has air below it + Polygons air_below = getOutlineOnLayer(part, layer_nr).difference(getOutlineOnLayer(part, layer_nr - 1)); + + if (! air_below.empty()) + { + // add the polygons that have air below to the no air above polygons + filled_area_above = filled_area_above.unionPolygons(air_below); + } + } + + return filled_area_above; + }(); + + if (filled_area_above.empty()) + { + return true; + } + + const auto point_view = ranges::views::transform([](auto extrusion_junction) { return extrusion_junction.p; }); + + for (const auto& path: part.wall_toolpaths) + { + for (const auto& wall: path) + { + for (const auto& p : wall | point_view) + { + if (!filled_area_above.inside(p)) + { + return true; + } + } + + for (const auto& window : wall | point_view | ranges::views::sliding(2)) + { + auto p0 = window[0]; + auto p1 = window[1]; + if (PolygonUtils::polygonCollidesWithLineSegment(filled_area_above, p0, p1)) + { + return true; + } + } + } + } + return 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( @@ -2405,8 +2497,8 @@ bool FffGcodeWriter::processInsets( gcode_layer, mesh.settings, extruder_nr, - mesh_config.inset0_config, - mesh_config.insetX_config, + inset0_config, + insetX_config, mesh_config.bridge_inset0_config, mesh_config.bridge_insetX_config, mesh.settings.get("travel_retract_before_outer_wall"), diff --git a/src/settings/MeshPathConfigs.cpp b/src/settings/MeshPathConfigs.cpp index 942084a231..a89b444bd3 100644 --- a/src/settings/MeshPathConfigs.cpp +++ b/src/settings/MeshPathConfigs.cpp @@ -28,6 +28,32 @@ MeshPathConfigs::MeshPathConfigs(const SliceMeshStorage& mesh, const coord_t lay .speed_derivatives = { .speed = mesh.settings.get("speed_wall_x"), .acceleration = mesh.settings.get("acceleration_wall_x"), .jerk = mesh.settings.get("jerk_wall_x") } } + , inset0_roofing_config + { + .type = PrintFeatureType::OuterWall, + .line_width = static_cast( + mesh.settings.get("wall_line_width_0") * line_width_factor_per_extruder[mesh.settings.get("wall_0_extruder_nr").extruder_nr]), + .layer_thickness = layer_thickness, + .flow = mesh.settings.get("wall_0_material_flow_roofing") * (layer_nr == 0 ? mesh.settings.get("wall_0_material_flow_layer_0") : Ratio{ 1.0 }), + .speed_derivatives = { + .speed = mesh.settings.get("speed_wall_0_roofing"), + .acceleration = mesh.settings.get("acceleration_wall_0_roofing"), + .jerk = mesh.settings.get("jerk_wall_0_roofing") + } + } + , insetX_roofing_config + { + .type = PrintFeatureType::OuterWall, + .line_width = static_cast( + mesh.settings.get("wall_line_width_x") * line_width_factor_per_extruder[mesh.settings.get("wall_x_extruder_nr").extruder_nr]), + .layer_thickness = layer_thickness, + .flow = mesh.settings.get("wall_x_material_flow_roofing") * (layer_nr == 0 ? mesh.settings.get("wall_x_material_flow_layer_0") : Ratio{ 1.0 }), + .speed_derivatives = { + .speed = mesh.settings.get("speed_wall_x_roofing"), + .acceleration = mesh.settings.get("acceleration_wall_x_roofing"), + .jerk = mesh.settings.get("jerk_wall_x_roofing") + } + } , bridge_inset0_config{ .type = PrintFeatureType::OuterWall, .line_width = static_cast( mesh.settings.get("wall_line_width_0") From 5a815f6ea769cbbf39d0fc21a1eeffe7c64e3e42 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Thu, 5 Oct 2023 10:47:34 +0000 Subject: [PATCH 25/56] Applied clang-format. --- src/FffGcodeWriter.cpp | 15 +++++++---- src/settings/MeshPathConfigs.cpp | 46 ++++++++++++++------------------ 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index c3750c3b18..7d15063a22 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -2395,7 +2395,8 @@ bool FffGcodeWriter::processInsets( else { // for layers that (partially) do not have any layers above we apply the roofing configuration - auto use_roofing_config = [&part, &mesh, &gcode_layer](){ + auto use_roofing_config = [&part, &mesh, &gcode_layer]() + { const auto getOutlineOnLayer = [mesh](const SliceLayerPart& part_here, const LayerIndex layer2_nr) -> Polygons { Polygons result; @@ -2453,15 +2454,19 @@ bool FffGcodeWriter::processInsets( return true; } - const auto point_view = ranges::views::transform([](auto extrusion_junction) { return extrusion_junction.p; }); + const auto point_view = ranges::views::transform( + [](auto extrusion_junction) + { + return extrusion_junction.p; + }); - for (const auto& path: part.wall_toolpaths) + for (const auto& path : part.wall_toolpaths) { - for (const auto& wall: path) + for (const auto& wall : path) { for (const auto& p : wall | point_view) { - if (!filled_area_above.inside(p)) + if (! filled_area_above.inside(p)) { return true; } diff --git a/src/settings/MeshPathConfigs.cpp b/src/settings/MeshPathConfigs.cpp index a89b444bd3..aa71d89e07 100644 --- a/src/settings/MeshPathConfigs.cpp +++ b/src/settings/MeshPathConfigs.cpp @@ -28,32 +28,26 @@ MeshPathConfigs::MeshPathConfigs(const SliceMeshStorage& mesh, const coord_t lay .speed_derivatives = { .speed = mesh.settings.get("speed_wall_x"), .acceleration = mesh.settings.get("acceleration_wall_x"), .jerk = mesh.settings.get("jerk_wall_x") } } - , inset0_roofing_config - { - .type = PrintFeatureType::OuterWall, - .line_width = static_cast( - mesh.settings.get("wall_line_width_0") * line_width_factor_per_extruder[mesh.settings.get("wall_0_extruder_nr").extruder_nr]), - .layer_thickness = layer_thickness, - .flow = mesh.settings.get("wall_0_material_flow_roofing") * (layer_nr == 0 ? mesh.settings.get("wall_0_material_flow_layer_0") : Ratio{ 1.0 }), - .speed_derivatives = { - .speed = mesh.settings.get("speed_wall_0_roofing"), - .acceleration = mesh.settings.get("acceleration_wall_0_roofing"), - .jerk = mesh.settings.get("jerk_wall_0_roofing") - } - } - , insetX_roofing_config - { - .type = PrintFeatureType::OuterWall, - .line_width = static_cast( - mesh.settings.get("wall_line_width_x") * line_width_factor_per_extruder[mesh.settings.get("wall_x_extruder_nr").extruder_nr]), - .layer_thickness = layer_thickness, - .flow = mesh.settings.get("wall_x_material_flow_roofing") * (layer_nr == 0 ? mesh.settings.get("wall_x_material_flow_layer_0") : Ratio{ 1.0 }), - .speed_derivatives = { - .speed = mesh.settings.get("speed_wall_x_roofing"), - .acceleration = mesh.settings.get("acceleration_wall_x_roofing"), - .jerk = mesh.settings.get("jerk_wall_x_roofing") - } - } + , inset0_roofing_config{ .type = PrintFeatureType::OuterWall, + .line_width = static_cast( + mesh.settings.get("wall_line_width_0") + * line_width_factor_per_extruder[mesh.settings.get("wall_0_extruder_nr").extruder_nr]), + .layer_thickness = layer_thickness, + .flow + = mesh.settings.get("wall_0_material_flow_roofing") * (layer_nr == 0 ? mesh.settings.get("wall_0_material_flow_layer_0") : Ratio{ 1.0 }), + .speed_derivatives = { .speed = mesh.settings.get("speed_wall_0_roofing"), + .acceleration = mesh.settings.get("acceleration_wall_0_roofing"), + .jerk = mesh.settings.get("jerk_wall_0_roofing") } } + , insetX_roofing_config{ .type = PrintFeatureType::OuterWall, + .line_width = static_cast( + mesh.settings.get("wall_line_width_x") + * line_width_factor_per_extruder[mesh.settings.get("wall_x_extruder_nr").extruder_nr]), + .layer_thickness = layer_thickness, + .flow + = mesh.settings.get("wall_x_material_flow_roofing") * (layer_nr == 0 ? mesh.settings.get("wall_x_material_flow_layer_0") : Ratio{ 1.0 }), + .speed_derivatives = { .speed = mesh.settings.get("speed_wall_x_roofing"), + .acceleration = mesh.settings.get("acceleration_wall_x_roofing"), + .jerk = mesh.settings.get("jerk_wall_x_roofing") } } , bridge_inset0_config{ .type = PrintFeatureType::OuterWall, .line_width = static_cast( mesh.settings.get("wall_line_width_0") From 0a91c6544fa68d942c14b9f9c8f995bf2e93f130 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Thu, 5 Oct 2023 15:17:34 +0200 Subject: [PATCH 26/56] the length of brim is correctly calculated in case of no adhesion CURA-11097 --- src/FffGcodeWriter.cpp | 1 - src/SkirtBrim.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 7d15063a22..3534122248 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3147,7 +3147,6 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer } island_order_optimizer.optimize(); - const auto support_brim_line_count = infill_extruder.settings.get("support_brim_line_count"); const auto support_connect_zigzags = infill_extruder.settings.get("support_connect_zigzags"); const auto support_structure = infill_extruder.settings.get("support_structure"); const Point infill_origin; diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 6aed96d7fe..2c1c134d3c 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -668,7 +668,7 @@ void SkirtBrim::generateSupportBrim() storage.support_brim.add(brim_line); - const coord_t length = skirt_brim_length + storage.support_brim.polygonLength(); + const coord_t length = (adhesion_type == EPlatformAdhesion::NONE)? skirt_brim_length: skirt_brim_length + storage.support_brim.polygonLength(); if (skirt_brim_number + 1 >= line_count && length > 0 && length < minimal_length) // Make brim or skirt have more lines when total length is too small. { line_count++; From 3f811919eb9625a6b24f235203dbc06c711b2af9 Mon Sep 17 00:00:00 2001 From: saumyaj3 Date: Thu, 5 Oct 2023 13:18:20 +0000 Subject: [PATCH 27/56] Applied clang-format. --- src/SkirtBrim.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 2c1c134d3c..98992c67d9 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -668,7 +668,7 @@ void SkirtBrim::generateSupportBrim() storage.support_brim.add(brim_line); - const coord_t length = (adhesion_type == EPlatformAdhesion::NONE)? skirt_brim_length: skirt_brim_length + storage.support_brim.polygonLength(); + const coord_t length = (adhesion_type == EPlatformAdhesion::NONE) ? skirt_brim_length : skirt_brim_length + storage.support_brim.polygonLength(); if (skirt_brim_number + 1 >= line_count && length > 0 && length < minimal_length) // Make brim or skirt have more lines when total length is too small. { line_count++; From edfd1ce608135f220ce0cd199d3ec77417d84058 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Fri, 6 Oct 2023 10:54:26 +0200 Subject: [PATCH 28/56] comment for adding if statement CURA-11097 --- src/SkirtBrim.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 98992c67d9..1731714763 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -667,8 +667,8 @@ void SkirtBrim::generateSupportBrim() } storage.support_brim.add(brim_line); - - const coord_t length = (adhesion_type == EPlatformAdhesion::NONE) ? skirt_brim_length : skirt_brim_length + storage.support_brim.polygonLength(); + // In case of adhesion::NONE length of support brim is only the length of the brims formed for the support + const coord_t length = (adhesion_type == EPlatformAdhesion::NONE) ? skirt_brim_length: skirt_brim_length + storage.support_brim.polygonLength(); if (skirt_brim_number + 1 >= line_count && length > 0 && length < minimal_length) // Make brim or skirt have more lines when total length is too small. { line_count++; From 1be41240e9718e37a732ebde45a8b0e242025ee5 Mon Sep 17 00:00:00 2001 From: saumyaj3 Date: Fri, 6 Oct 2023 08:56:34 +0000 Subject: [PATCH 29/56] Applied clang-format. --- src/SkirtBrim.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 1731714763..94761b0717 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -668,7 +668,7 @@ void SkirtBrim::generateSupportBrim() storage.support_brim.add(brim_line); // In case of adhesion::NONE length of support brim is only the length of the brims formed for the support - const coord_t length = (adhesion_type == EPlatformAdhesion::NONE) ? skirt_brim_length: skirt_brim_length + storage.support_brim.polygonLength(); + const coord_t length = (adhesion_type == EPlatformAdhesion::NONE) ? skirt_brim_length : skirt_brim_length + storage.support_brim.polygonLength(); if (skirt_brim_number + 1 >= line_count && length > 0 && length < minimal_length) // Make brim or skirt have more lines when total length is too small. { line_count++; From 77028a968349074d5a1a3e14d2bb6f6931a90c3e Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 9 Oct 2023 15:26:34 +0200 Subject: [PATCH 30/56] Minor optimization CURA-11100 Co-authored-by: Casper Lamboo --- include/PathOrderOptimizer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index ab58d30651..ce11a18b12 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -642,7 +642,7 @@ class PathOrderOptimizer for (const auto& [i, here] : **path.converted | ranges::views::enumerate) { const Point& next = (*path.converted)[(i + 1) % path.converted->size()]; - coord_t segment_size = vSize(next - here); + const coord_t segment_size = vSize(next - here); segments_sizes[i] = segment_size; total_length += segment_size; } From 784ecfc5b21673caf498e7b3af4266e4f783831b Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 9 Oct 2023 15:44:51 +0200 Subject: [PATCH 31/56] Applied code suggestion by @casperlamboo CURA-11100 --- include/PathOrderOptimizer.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index ce11a18b12..506e624927 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -649,14 +650,8 @@ class PathOrderOptimizer size_t best_i; float best_score = std::numeric_limits::infinity(); - for (const auto& [i, here] : **path.converted | ranges::views::enumerate) + for (const auto& [i, here] : **path.converted | ranges::views::drop_last(1) | ranges::views::enumerate) { - if (i == path.converted->size() - 1) - { - // The path is closed so the last point is the same as the first, don't process it twice - continue; - } - // For most seam types, the shortest distance matters. Not for SHARPEST_CORNER though. // For SHARPEST_CORNER, use a fixed starting score of 0. const coord_t distance = (combing_boundary == nullptr) ? getDirectDistance(here, target_pos) : getCombingDistance(here, target_pos); From 948f860bd13e31473190bc34fc1880e2a1d8232e Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Mon, 9 Oct 2023 13:45:37 +0000 Subject: [PATCH 32/56] Applied clang-format. --- include/PathOrderOptimizer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index 506e624927..ae7591db45 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -17,10 +17,10 @@ #include #include #include +#include #include #include #include -#include #include #include From a96e603c50d1d14c8efcd75cb3f4ec652cb54196 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 10 Oct 2023 10:40:09 +0200 Subject: [PATCH 33/56] pin gRPC defs to 0.1.0-beta.1 --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index dea1860300..841ec2d936 100644 --- a/conanfile.py +++ b/conanfile.py @@ -85,7 +85,7 @@ def requirements(self): self.requires("arcus/5.3.0") self.requires("asio-grpc/2.6.0") self.requires("grpc/1.50.1") - self.requires("curaengine_grpc_definitions/(latest)@ultimaker/testing") + self.requires("curaengine_grpc_definitions/0.1.0-beta.1") self.requires("clipper/6.4.2") self.requires("boost/1.82.0") self.requires("rapidjson/1.1.0") From 6c20ccd6a9538411fcb220c4813ab8ade3be5207 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 10 Oct 2023 10:40:52 +0200 Subject: [PATCH 34/56] set version to 5.5.0-beta.2 --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index 841ec2d936..2556e86c45 100644 --- a/conanfile.py +++ b/conanfile.py @@ -40,7 +40,7 @@ class CuraEngineConan(ConanFile): def set_version(self): if not self.version: - self.version = "5.5.0-beta.1" + self.version = "5.5.0-beta.2" def export_sources(self): copy(self, "CMakeLists.txt", self.recipe_folder, self.export_sources_folder) From 9ab698b750974212ec9bd68c5e5b107ea37b46a7 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 10 Oct 2023 10:42:59 +0200 Subject: [PATCH 35/56] set version to 5.6.0-alpha --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index 2556e86c45..27c205dc58 100644 --- a/conanfile.py +++ b/conanfile.py @@ -40,7 +40,7 @@ class CuraEngineConan(ConanFile): def set_version(self): if not self.version: - self.version = "5.5.0-beta.2" + self.version = "5.6.0-alpha" def export_sources(self): copy(self, "CMakeLists.txt", self.recipe_folder, self.export_sources_folder) From 81883c036b0a0e1c620ac26ce847787980388797 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 10 Oct 2023 11:05:34 +0200 Subject: [PATCH 36/56] loosen deps version --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index 27c205dc58..b498c3b84d 100644 --- a/conanfile.py +++ b/conanfile.py @@ -85,7 +85,7 @@ def requirements(self): self.requires("arcus/5.3.0") self.requires("asio-grpc/2.6.0") self.requires("grpc/1.50.1") - self.requires("curaengine_grpc_definitions/0.1.0-beta.1") + self.requires("curaengine_grpc_definitions/(latest)@ultimaker/testing") self.requires("clipper/6.4.2") self.requires("boost/1.82.0") self.requires("rapidjson/1.1.0") From ab538dc676bb351446f10ccb07dffbfb6af4a5b3 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Fri, 13 Oct 2023 15:50:39 +0200 Subject: [PATCH 37/56] Small refactor. done as part of CURA-10407 --- src/support.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/support.cpp b/src/support.cpp index a4cf4a711e..2c2ddb9fa3 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -686,28 +686,26 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage) } } - for (LayerIndex layer_idx = 0; layer_idx < storage.print_layer_count; layer_idx++) + for (Polygons& support_areas : global_support_areas_per_layer) { - Polygons& support_areas = global_support_areas_per_layer[layer_idx]; support_areas = support_areas.unionPolygons(); } // handle support interface - for (unsigned int mesh_idx = 0; mesh_idx < storage.meshes.size(); mesh_idx++) + for (auto& mesh : storage.meshes) { - SliceMeshStorage& mesh = *storage.meshes[mesh_idx]; - if (mesh.settings.get("infill_mesh") || mesh.settings.get("anti_overhang_mesh")) + if (mesh->settings.get("infill_mesh") || mesh->settings.get("anti_overhang_mesh")) { continue; } - if (mesh.settings.get("support_roof_enable")) + if (mesh->settings.get("support_roof_enable")) { - generateSupportRoof(storage, mesh, global_support_areas_per_layer); + generateSupportRoof(storage, *mesh, global_support_areas_per_layer); } - if (mesh.settings.get("support_bottom_enable")) + if (mesh->settings.get("support_bottom_enable")) { - generateSupportBottom(storage, mesh, global_support_areas_per_layer); + generateSupportBottom(storage, *mesh, global_support_areas_per_layer); } } From 8c3740ddad305c434558401e459222175c9de6b0 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Fri, 13 Oct 2023 16:02:19 +0200 Subject: [PATCH 38/56] Support-infill can has fractional layers + refactor spike-code for roofs. - Move code outside of the gcode-writer. For example, z-offset is now calulated in the settings themselves. - Other than support roofs, support infill now also is fractional layer 'aware'. this is the 'main' commit for CURA-10407 -- splitting this into different commits would've been a bit more hassle than it's worth, as several of the changes are closely related --- include/FffGcodeWriter.h | 4 +- include/SupportInfillPart.h | 3 +- include/settings/PathConfigStorage.h | 2 + include/sliceDataStorage.h | 5 +- src/FffGcodeWriter.cpp | 188 +++++++++++++-------------- src/SupportInfillPart.cpp | 3 +- src/settings/PathConfigStorage.cpp | 15 +++ src/support.cpp | 36 ++--- 8 files changed, 134 insertions(+), 122 deletions(-) diff --git a/include/FffGcodeWriter.h b/include/FffGcodeWriter.h index 96f504c1e3..e46f2b471c 100644 --- a/include/FffGcodeWriter.h +++ b/include/FffGcodeWriter.h @@ -634,10 +634,12 @@ class FffGcodeWriter : public NoCopy * layer. * * \param[in] storage Where the slice data is stored. + * \param[in] support_roof_outlines which polygons to generate roofs for -- originally split-up because of fractional (layer-height) layers + * \param[in] current_roof_config config to be used -- most importantly, support has slightly different configs for fractional (layer-height) layers * \param gcodeLayer The initial planning of the g-code of the layer. * \return Whether any support skin was added to the layer plan. */ - bool addSupportRoofsToGCode(const SliceDataStorage& storage, LayerPlan& gcodeLayer) const; + bool addSupportRoofsToGCode(const SliceDataStorage& storage, const Polygons& support_roof_outlines, const GCodePathConfig& current_roof_config, LayerPlan& gcode_layer) const; /*! * Add the support bottoms to the layer plan \p gcodeLayer of the current diff --git a/include/SupportInfillPart.h b/include/SupportInfillPart.h index 2a1849ab55..8e00845ac5 100644 --- a/include/SupportInfillPart.h +++ b/include/SupportInfillPart.h @@ -34,8 +34,9 @@ class SupportInfillPart std::vector wall_toolpaths; //!< Any walls go here, not in the areas, where they could be combined vertically (don't combine walls). Binned by inset_idx. coord_t custom_line_distance; + bool use_fractional_config; - SupportInfillPart(const PolygonsPart& outline, coord_t support_line_width, int inset_count_to_generate = 0, coord_t custom_line_distance = 0 ); + SupportInfillPart(const PolygonsPart& outline, coord_t support_line_width, bool use_fractional_config, int inset_count_to_generate = 0, coord_t custom_line_distance = 0 ); const Polygons& getInfillArea() const; }; diff --git a/include/settings/PathConfigStorage.h b/include/settings/PathConfigStorage.h index e7bd54773a..4ba5bf2837 100644 --- a/include/settings/PathConfigStorage.h +++ b/include/settings/PathConfigStorage.h @@ -48,7 +48,9 @@ class PathConfigStorage std::vector prime_tower_config_per_extruder; //!< Configuration for the prime tower per extruder. std::vector support_infill_config; //!< The config used to print the normal support, rather than the support interface + std::vector support_fractional_infill_config; //!< The config used to print the normal support on fractional layer-height parts. GCodePathConfig support_roof_config; //!< The config used to print the dense roofs of support. + GCodePathConfig support_fractional_roof_config; //!< The config used to print the dense roofs of support on fractional layer-height parts. GCodePathConfig support_bottom_config; //!< The config to use to print the dense bottoms of support std::vector mesh_configs; //!< For each meash the config for all its feature types diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 4c424a2b09..80b825211a 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -212,8 +212,9 @@ class SupportLayer std::vector support_infill_parts; //!< a list of support infill parts Polygons support_bottom; //!< Piece of support below the support and above the model. This must not overlap with any of the support_infill_parts or support_roof. Polygons support_roof; //!< Piece of support above the support and below the model. This must not overlap with any of the support_infill_parts or support_bottom. - Polygons support_fractional_roof_top; //!< If the support distance is not exactly a multiple of the layer height, - // the first part of support just underneath the model needs to be printed at a fracional layer height. + // NOTE: This is _all_ of the support_roof, and as such, overlaps with support_fractional_roof! + Polygons support_fractional_roof; //!< If the support distance is not exactly a multiple of the layer height, + // the first part of support just underneath the model needs to be printed at a fracional layer height. Polygons support_mesh_drop_down; //!< Areas from support meshes which should be supported by more support Polygons support_mesh; //!< Areas from support meshes which should NOT be supported by more support Polygons anti_overhang; //!< Areas where no overhang should be detected. diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 3534122248..2d74becd90 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3064,7 +3064,8 @@ bool FffGcodeWriter::addSupportToGCode(const SliceDataStorage& storage, LayerPla } if (extruder_nr == support_roof_extruder_nr) { - support_added |= addSupportRoofsToGCode(storage, gcode_layer); + support_added |= addSupportRoofsToGCode(storage, support_layer.support_roof.difference(support_layer.support_fractional_roof), gcode_layer.configs_storage.support_roof_config, gcode_layer); + support_added |= addSupportRoofsToGCode(storage, support_layer.support_fractional_roof, gcode_layer.configs_storage.support_fractional_roof_config, gcode_layer); } if (extruder_nr == support_bottom_extruder_nr) { @@ -3160,6 +3161,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer for (const PathOrdering& path : island_order_optimizer.paths) { const SupportInfillPart& part = *path.vertices; + const auto& configs = part.use_fractional_config ? gcode_layer.configs_storage.support_fractional_infill_config : gcode_layer.configs_storage.support_infill_config; // always process the wall overlap if walls are generated const int current_support_infill_overlap = (part.inset_count_to_generate > 0) ? default_support_infill_overlap : 0; @@ -3169,7 +3171,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer if (! wall_toolpaths.empty()) { - const GCodePathConfig& config = gcode_layer.configs_storage.support_infill_config[0]; + const GCodePathConfig& config = configs[0]; constexpr bool retract_before_outer_wall = false; constexpr coord_t wipe_dist = 0; const ZSeamConfig z_seam_config(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); @@ -3223,7 +3225,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer { support_line_distance_here /= 2; } - const Polygons& area = part.infill_area_per_combine_per_density[density_idx][combine_idx]; + const Polygons& area = Simplify(infill_extruder.settings).polygon(part.infill_area_per_combine_per_density[density_idx][combine_idx]); constexpr size_t wall_count = 0; // Walls are generated somewhere else, so their layers aren't vertically combined. const coord_t small_area_width = 0; @@ -3239,7 +3241,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer current_support_infill_overlap - (density_idx == max_density_idx ? 0 : wall_line_count * support_line_width), infill_multiplier, support_infill_angle, - gcode_layer.z, + gcode_layer.z + configs[combine_idx].z_offset, support_shift, max_resolution, max_deviation, @@ -3303,7 +3305,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer gcode_layer.addPolygonsByOptimizer( support_polygons, - gcode_layer.configs_storage.support_infill_config[combine_idx], + configs[combine_idx], z_seam_config, wall_0_wipe_dist, spiralize, @@ -3324,7 +3326,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer gcode_layer.addLinesByOptimizer( support_lines, - gcode_layer.configs_storage.support_infill_config[combine_idx], + configs[combine_idx], (support_pattern == EFillMethod::ZIG_ZAG) ? SpaceFillType::PolyLines : SpaceFillType::Lines, enable_travel_optimization, wipe_dist, @@ -3340,7 +3342,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer // If not, the pattern may still generate gap filling (if it's connected infill or zigzag). We still want to print those. if (wall_line_count == 0 || ! wall_toolpaths_here.empty()) { - const GCodePathConfig& config = gcode_layer.configs_storage.support_infill_config[0]; + const GCodePathConfig& config = configs[0]; constexpr bool retract_before_outer_wall = false; constexpr coord_t wipe_dist = 0; constexpr coord_t simplify_curvature = 0; @@ -3375,7 +3377,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer } -bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, LayerPlan& gcode_layer) const +bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, const Polygons& support_roof_outlines, const GCodePathConfig& current_roof_config, LayerPlan& gcode_layer) const { const SupportLayer& support_layer = storage.support.supportLayers[std::max(LayerIndex{ 0 }, gcode_layer.getLayerNr())]; @@ -3421,103 +3423,87 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay support_roof_line_distance *= roof_extruder.settings.get("initial_layer_line_width_factor"); } - const auto layer_height = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("layer_height"); - const auto support_top_distance = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("support_top_distance"); - const coord_t leftover_support_distance = support_top_distance % layer_height; - - std::vector infill_outlines = { Simplify(roof_extruder.settings).polygon(support_layer.support_roof.difference(support_layer.support_fractional_roof_top)), - Simplify(roof_extruder.settings).polygon(support_layer.support_fractional_roof_top) }; - auto current_roof_config = gcode_layer.configs_storage.support_roof_config; // copy! - bool generated_something = false; - for (auto& infill_outline : infill_outlines) + Polygons infill_outline = support_roof_outlines; + Polygons wall; + // make sure there is a wall if this is on the first layer + if (gcode_layer.getLayerNr() == 0) { - Polygons wall; - // make sure there is a wall if this is on the first layer - if (gcode_layer.getLayerNr() == 0) - { - wall = support_layer.support_roof.offset(-support_roof_line_width / 2); - infill_outline = wall.offset(-support_roof_line_width / 2); - } - - Infill roof_computation( - pattern, - zig_zaggify_infill, - connect_polygons, - infill_outline, - current_roof_config.getLineWidth(), - support_roof_line_distance, - support_roof_overlap, - infill_multiplier, - fill_angle, - gcode_layer.z + current_roof_config.z_offset, - extra_infill_shift, - max_resolution, - max_deviation, - wall_line_count, - small_area_width, - infill_origin, - skip_stitching, - fill_gaps, - connected_zigzags, - use_endpieces, - skip_some_zags, - zag_skip_count, - pocket_size); - Polygons roof_polygons; - std::vector roof_paths; - Polygons roof_lines; - roof_computation.generate(roof_paths, roof_polygons, roof_lines, roof_extruder.settings, gcode_layer.getLayerNr(), SectionType::SUPPORT); - if ((gcode_layer.getLayerNr() == 0 && wall.empty()) || (gcode_layer.getLayerNr() > 0 && roof_paths.empty() && roof_polygons.empty() && roof_lines.empty())) - { - current_roof_config.z_offset = -leftover_support_distance; - current_roof_config.flow *= Ratio(layer_height - leftover_support_distance, layer_height); - - continue; // We didn't create any support roof. - } - generated_something = true; // We _did_ create at least some support roof. - gcode_layer.setIsInside(false); // going to print stuff outside print object, i.e. support - if (gcode_layer.getLayerNr() == 0) - { - gcode_layer.addPolygonsByOptimizer(wall, current_roof_config); - } - if (! roof_polygons.empty()) - { - constexpr bool force_comb_retract = false; - gcode_layer.addTravel(roof_polygons[0][0], force_comb_retract); - gcode_layer.addPolygonsByOptimizer(roof_polygons, current_roof_config); - } - if (! roof_paths.empty()) - { - const GCodePathConfig& config = current_roof_config; - constexpr bool retract_before_outer_wall = false; - constexpr coord_t wipe_dist = 0; - const ZSeamConfig z_seam_config(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); + wall = support_layer.support_roof.offset(-support_roof_line_width / 2); + infill_outline = wall.offset(-support_roof_line_width / 2); + } + infill_outline = Simplify(roof_extruder.settings).polygon(infill_outline); - InsetOrderOptimizer wall_orderer( - *this, - storage, - gcode_layer, - roof_extruder.settings, - roof_extruder_nr, - config, - config, - config, - config, - retract_before_outer_wall, - wipe_dist, - wipe_dist, - roof_extruder_nr, - roof_extruder_nr, - z_seam_config, - roof_paths); - wall_orderer.addToLayer(); - } - gcode_layer.addLinesByOptimizer(roof_lines, current_roof_config, (pattern == EFillMethod::ZIG_ZAG) ? SpaceFillType::PolyLines : SpaceFillType::Lines); + Infill roof_computation( + pattern, + zig_zaggify_infill, + connect_polygons, + infill_outline, + current_roof_config.getLineWidth(), + support_roof_line_distance, + support_roof_overlap, + infill_multiplier, + fill_angle, + gcode_layer.z + current_roof_config.z_offset, + extra_infill_shift, + max_resolution, + max_deviation, + wall_line_count, + small_area_width, + infill_origin, + skip_stitching, + fill_gaps, + connected_zigzags, + use_endpieces, + skip_some_zags, + zag_skip_count, + pocket_size); + Polygons roof_polygons; + std::vector roof_paths; + Polygons roof_lines; + roof_computation.generate(roof_paths, roof_polygons, roof_lines, roof_extruder.settings, gcode_layer.getLayerNr(), SectionType::SUPPORT); + if ((gcode_layer.getLayerNr() == 0 && wall.empty()) || (gcode_layer.getLayerNr() > 0 && roof_paths.empty() && roof_polygons.empty() && roof_lines.empty())) + { + return false; // We didn't create any support roof. + } + gcode_layer.setIsInside(false); // going to print stuff outside print object, i.e. support + if (gcode_layer.getLayerNr() == 0) + { + gcode_layer.addPolygonsByOptimizer(wall, current_roof_config); + } + if (! roof_polygons.empty()) + { + constexpr bool force_comb_retract = false; + gcode_layer.addTravel(roof_polygons[0][0], force_comb_retract); + gcode_layer.addPolygonsByOptimizer(roof_polygons, current_roof_config); + } + if (! roof_paths.empty()) + { + const GCodePathConfig& config = current_roof_config; + constexpr bool retract_before_outer_wall = false; + constexpr coord_t wipe_dist = 0; + const ZSeamConfig z_seam_config(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); - current_roof_config.z_offset = -leftover_support_distance; - current_roof_config.flow *= Ratio(layer_height - leftover_support_distance, layer_height); + InsetOrderOptimizer wall_orderer( + *this, + storage, + gcode_layer, + roof_extruder.settings, + roof_extruder_nr, + config, + config, + config, + config, + retract_before_outer_wall, + wipe_dist, + wipe_dist, + roof_extruder_nr, + roof_extruder_nr, + z_seam_config, + roof_paths); + wall_orderer.addToLayer(); } - return generated_something; + gcode_layer.addLinesByOptimizer(roof_lines, current_roof_config, (pattern == EFillMethod::ZIG_ZAG) ? SpaceFillType::PolyLines : SpaceFillType::Lines); + return true; } bool FffGcodeWriter::addSupportBottomsToGCode(const SliceDataStorage& storage, LayerPlan& gcode_layer) const diff --git a/src/SupportInfillPart.cpp b/src/SupportInfillPart.cpp index 76344af468..fbc7c66096 100644 --- a/src/SupportInfillPart.cpp +++ b/src/SupportInfillPart.cpp @@ -7,12 +7,13 @@ using namespace cura; -SupportInfillPart::SupportInfillPart(const PolygonsPart& outline, coord_t support_line_width, int inset_count_to_generate, coord_t custom_line_distance) +SupportInfillPart::SupportInfillPart(const PolygonsPart& outline, coord_t support_line_width, bool use_fractional_config, int inset_count_to_generate, coord_t custom_line_distance) : outline(outline) , outline_boundary_box(outline) , support_line_width(support_line_width) , inset_count_to_generate(inset_count_to_generate) , custom_line_distance(custom_line_distance) +, use_fractional_config(use_fractional_config) { infill_area_per_combine_per_density.clear(); } diff --git a/src/settings/PathConfigStorage.cpp b/src/settings/PathConfigStorage.cpp index f6e6d1b703..2ecf94eb70 100644 --- a/src/settings/PathConfigStorage.cpp +++ b/src/settings/PathConfigStorage.cpp @@ -150,6 +150,21 @@ PathConfigStorage::PathConfigStorage(const SliceDataStorage& storage, const Laye { handleInitialLayerSpeedup(storage, layer_nr, initial_speedup_layer_count); } + + const auto layer_height = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("layer_height"); + const auto support_top_distance = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("support_top_distance"); + const coord_t leftover_support_distance = support_top_distance % layer_height; + + support_fractional_infill_config = support_infill_config; // copy + for (auto& config : support_fractional_infill_config) + { + config.z_offset = -leftover_support_distance; + config.flow *= Ratio(layer_height - leftover_support_distance, layer_height); + } + + support_fractional_roof_config = support_roof_config; // copy + support_fractional_roof_config.z_offset = -leftover_support_distance; + support_fractional_roof_config.flow *= Ratio(layer_height - leftover_support_distance, layer_height); } void MeshPathConfigs::smoothAllSpeeds(const SpeedDerivatives& first_layer_config, const LayerIndex layer_nr, const LayerIndex max_speed_layer) diff --git a/src/support.cpp b/src/support.cpp index 2c2ddb9fa3..46246f0f2c 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -106,7 +106,6 @@ void AreaSupport::splitGlobalSupportAreasIntoSupportInfillParts( { // The first layer will be printed with a grid pattern wall_line_count_this_layer++; } - assert(storage.support.supportLayers[layer_nr].support_infill_parts.empty() && "support infill part list is supposed to be uninitialized"); const Polygons& global_support_areas = global_support_areas_per_layer[layer_nr]; if (global_support_areas.size() == 0 || layer_nr < min_layer || layer_nr > max_layer) @@ -116,19 +115,26 @@ void AreaSupport::splitGlobalSupportAreasIntoSupportInfillParts( continue; } - std::vector support_islands = global_support_areas.splitIntoParts(); - for (const PolygonsPart& island_outline : support_islands) + const Polygons& global_support_areas_above = (layer_nr + 1) >= global_support_areas_per_layer.size() ? Polygons() : global_support_areas_per_layer[layer_nr + 1]; + const auto all_support_areas_in_layer = { global_support_areas.intersection(global_support_areas_above), global_support_areas.difference(global_support_areas_above) }; + bool use_fractional_config = false; + for (auto& support_areas : all_support_areas_in_layer) { - coord_t support_line_width_here = support_line_width; - if (layer_nr == 0 && mesh_group_settings.get("adhesion_type") != EPlatformAdhesion::RAFT) + std::vector support_islands = support_areas.splitIntoParts(); + for (const PolygonsPart& island_outline : support_islands) { - support_line_width_here *= infill_extruder.settings.get("initial_layer_line_width_factor"); - } - // We don't generate insets and infill area for the parts yet because later the skirt/brim and prime - // tower will remove themselves from the support, so the outlines of the parts can be changed. - SupportInfillPart support_infill_part(island_outline, support_line_width_here, wall_line_count_this_layer); + coord_t support_line_width_here = support_line_width; + if (layer_nr == 0 && mesh_group_settings.get("adhesion_type") != EPlatformAdhesion::RAFT) + { + support_line_width_here *= infill_extruder.settings.get("initial_layer_line_width_factor"); + } + // We don't generate insets and infill area for the parts yet because later the skirt/brim and prime + // tower will remove themselves from the support, so the outlines of the parts can be changed. + SupportInfillPart support_infill_part(island_outline, support_line_width_here, use_fractional_config, wall_line_count_this_layer); - storage.support.supportLayers[layer_nr].support_infill_parts.push_back(support_infill_part); + storage.support.supportLayers[layer_nr].support_infill_parts.push_back(support_infill_part); + } + use_fractional_config = true; } } } @@ -1816,16 +1822,14 @@ void AreaSupport::generateSupportRoof(SliceDataStorage& storage, const SliceMesh Polygons roofs; generateSupportInterfaceLayer(global_support_areas_per_layer[layer_idx], mesh_outlines, roof_line_width, roof_outline_offset, minimum_roof_area, roofs); support_layers[layer_idx].support_roof.add(roofs); - support_layers[layer_idx].support_fractional_roof_top = roofs.difference(support_layers[layer_idx + 1].support_roof); + support_layers[layer_idx].support_fractional_roof.add(roofs.difference(support_layers[layer_idx + 1].support_roof)); scripta::log("support_interface_roofs", roofs, SectionType::SUPPORT, layer_idx); } // Remove support in between the support roof and the model. Subtracts the roof polygons from the support polygons on the layers above it. for (auto [layer_idx, support_layer] : support_layers | ranges::views::enumerate | ranges::views::drop(1) | ranges::views::drop_last(z_distance_top)) { - Polygons roof = support_layer.support_roof; - - if (roof.empty()) + if (support_layer.support_roof.empty()) { continue; } @@ -1834,7 +1838,7 @@ void AreaSupport::generateSupportRoof(SliceDataStorage& storage, const SliceMesh int upper = std::min(static_cast(layer_idx + roof_layer_count + z_distance_top + 5), static_cast(global_support_areas_per_layer.size()) - 1); for (Polygons& global_support : global_support_areas_per_layer | ranges::views::slice(lower, upper)) { - global_support = global_support.difference(roof); + global_support = global_support.difference(support_layer.support_roof); } } } From 830c56a1179f6690c8694fa67fcb33e4f8cc18fa Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Fri, 13 Oct 2023 16:17:09 +0200 Subject: [PATCH 39/56] Fractional(-support)-layers: Prevent nozzle from impacting build-plate. part of CURA-10407 --- src/support.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/support.cpp b/src/support.cpp index 46246f0f2c..23fa7e66c6 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -115,7 +115,7 @@ void AreaSupport::splitGlobalSupportAreasIntoSupportInfillParts( continue; } - const Polygons& global_support_areas_above = (layer_nr + 1) >= global_support_areas_per_layer.size() ? Polygons() : global_support_areas_per_layer[layer_nr + 1]; + const Polygons& global_support_areas_above = (layer_nr + 1) >= global_support_areas_per_layer.size() || layer_nr <= 0 ? Polygons() : global_support_areas_per_layer[layer_nr + 1]; const auto all_support_areas_in_layer = { global_support_areas.intersection(global_support_areas_above), global_support_areas.difference(global_support_areas_above) }; bool use_fractional_config = false; for (auto& support_areas : all_support_areas_in_layer) @@ -1822,7 +1822,10 @@ void AreaSupport::generateSupportRoof(SliceDataStorage& storage, const SliceMesh Polygons roofs; generateSupportInterfaceLayer(global_support_areas_per_layer[layer_idx], mesh_outlines, roof_line_width, roof_outline_offset, minimum_roof_area, roofs); support_layers[layer_idx].support_roof.add(roofs); - support_layers[layer_idx].support_fractional_roof.add(roofs.difference(support_layers[layer_idx + 1].support_roof)); + if (layer_idx > 0) + { + support_layers[layer_idx].support_fractional_roof.add(roofs.difference(support_layers[layer_idx + 1].support_roof)); + } scripta::log("support_interface_roofs", roofs, SectionType::SUPPORT, layer_idx); } From 06a0157abfc38a0850537820f74e3724f7ad6c1d Mon Sep 17 00:00:00 2001 From: rburema Date: Fri, 13 Oct 2023 14:18:03 +0000 Subject: [PATCH 40/56] Applied clang-format. --- include/SupportInfillPart.h | 18 +++++++++--------- src/FffGcodeWriter.cpp | 12 ++++++++++-- src/SupportInfillPart.cpp | 13 +++++++------ src/support.cpp | 3 ++- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/include/SupportInfillPart.h b/include/SupportInfillPart.h index 8e00845ac5..45ff44e4e2 100644 --- a/include/SupportInfillPart.h +++ b/include/SupportInfillPart.h @@ -4,12 +4,12 @@ #ifndef SUPPORT_INFILL_PART_H #define SUPPORT_INFILL_PART_H -#include - #include "utils/AABB.h" #include "utils/ExtrusionLine.h" #include "utils/polygon.h" +#include + namespace cura { @@ -25,18 +25,18 @@ namespace cura class SupportInfillPart { public: - PolygonsPart outline; //!< The outline of the support infill area - AABB outline_boundary_box; //!< The boundary box for the infill area - coord_t support_line_width; //!< The support line width - int inset_count_to_generate; //!< The number of insets need to be generated from the outline. This is not the actual insets that will be generated. - std::vector> infill_area_per_combine_per_density; //!< a list of separated sub-areas which requires different infill densities and combined thicknesses - // for infill_areas[x][n], x means the density level and n means the thickness + PolygonsPart outline; //!< The outline of the support infill area + AABB outline_boundary_box; //!< The boundary box for the infill area + coord_t support_line_width; //!< The support line width + int inset_count_to_generate; //!< The number of insets need to be generated from the outline. This is not the actual insets that will be generated. + std::vector> infill_area_per_combine_per_density; //!< a list of separated sub-areas which requires different infill densities and combined thicknesses + // for infill_areas[x][n], x means the density level and n means the thickness std::vector wall_toolpaths; //!< Any walls go here, not in the areas, where they could be combined vertically (don't combine walls). Binned by inset_idx. coord_t custom_line_distance; bool use_fractional_config; - SupportInfillPart(const PolygonsPart& outline, coord_t support_line_width, bool use_fractional_config, int inset_count_to_generate = 0, coord_t custom_line_distance = 0 ); + SupportInfillPart(const PolygonsPart& outline, coord_t support_line_width, bool use_fractional_config, int inset_count_to_generate = 0, coord_t custom_line_distance = 0); const Polygons& getInfillArea() const; }; diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 2d74becd90..e7adca9412 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3064,7 +3064,11 @@ bool FffGcodeWriter::addSupportToGCode(const SliceDataStorage& storage, LayerPla } if (extruder_nr == support_roof_extruder_nr) { - support_added |= addSupportRoofsToGCode(storage, support_layer.support_roof.difference(support_layer.support_fractional_roof), gcode_layer.configs_storage.support_roof_config, gcode_layer); + support_added |= addSupportRoofsToGCode( + storage, + support_layer.support_roof.difference(support_layer.support_fractional_roof), + gcode_layer.configs_storage.support_roof_config, + gcode_layer); support_added |= addSupportRoofsToGCode(storage, support_layer.support_fractional_roof, gcode_layer.configs_storage.support_fractional_roof_config, gcode_layer); } if (extruder_nr == support_bottom_extruder_nr) @@ -3377,7 +3381,11 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer } -bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, const Polygons& support_roof_outlines, const GCodePathConfig& current_roof_config, LayerPlan& gcode_layer) const +bool FffGcodeWriter::addSupportRoofsToGCode( + const SliceDataStorage& storage, + const Polygons& support_roof_outlines, + const GCodePathConfig& current_roof_config, + LayerPlan& gcode_layer) const { const SupportLayer& support_layer = storage.support.supportLayers[std::max(LayerIndex{ 0 }, gcode_layer.getLayerNr())]; diff --git a/src/SupportInfillPart.cpp b/src/SupportInfillPart.cpp index fbc7c66096..ae0b8cf7c1 100644 --- a/src/SupportInfillPart.cpp +++ b/src/SupportInfillPart.cpp @@ -2,18 +2,19 @@ // CuraEngine is released under the terms of the AGPLv3 or higher. #include "SupportInfillPart.h" + #include "support.h" using namespace cura; SupportInfillPart::SupportInfillPart(const PolygonsPart& outline, coord_t support_line_width, bool use_fractional_config, int inset_count_to_generate, coord_t custom_line_distance) -: outline(outline) -, outline_boundary_box(outline) -, support_line_width(support_line_width) -, inset_count_to_generate(inset_count_to_generate) -, custom_line_distance(custom_line_distance) -, use_fractional_config(use_fractional_config) + : outline(outline) + , outline_boundary_box(outline) + , support_line_width(support_line_width) + , inset_count_to_generate(inset_count_to_generate) + , custom_line_distance(custom_line_distance) + , use_fractional_config(use_fractional_config) { infill_area_per_combine_per_density.clear(); } diff --git a/src/support.cpp b/src/support.cpp index 23fa7e66c6..5db9c9932e 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -115,7 +115,8 @@ void AreaSupport::splitGlobalSupportAreasIntoSupportInfillParts( continue; } - const Polygons& global_support_areas_above = (layer_nr + 1) >= global_support_areas_per_layer.size() || layer_nr <= 0 ? Polygons() : global_support_areas_per_layer[layer_nr + 1]; + const Polygons& global_support_areas_above + = (layer_nr + 1) >= global_support_areas_per_layer.size() || layer_nr <= 0 ? Polygons() : global_support_areas_per_layer[layer_nr + 1]; const auto all_support_areas_in_layer = { global_support_areas.intersection(global_support_areas_above), global_support_areas.difference(global_support_areas_above) }; bool use_fractional_config = false; for (auto& support_areas : all_support_areas_in_layer) From 4682128777e104805e295d5c1a0aa2428a3b8410 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Fri, 13 Oct 2023 21:21:41 +0200 Subject: [PATCH 41/56] Fix unit-test. done for CURA-10407 --- tests/LayerPlanTest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/LayerPlanTest.cpp b/tests/LayerPlanTest.cpp index b583005053..e7428f421c 100644 --- a/tests/LayerPlanTest.cpp +++ b/tests/LayerPlanTest.cpp @@ -169,6 +169,7 @@ class LayerPlanTest : public testing::Test settings->add("support_roof_extruder_nr", "0"); settings->add("support_roof_line_width", "0.404"); settings->add("support_roof_material_flow", "104"); + settings->add("support_top_distance", "200"); settings->add("wall_line_count", "3"); settings->add("wall_line_width_x", "0.3"); settings->add("wall_line_width_0", "0.301"); From 3bea2989ad1c0b2cb4e8a5cec651fbba6bbacb28 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 17 Oct 2023 15:52:37 +0200 Subject: [PATCH 42/56] Introduce fractional roof-top layer-heigths in tree-support. Add fractional support-roof and split non-interface support according to layers above. Might refactor the (now) duplicated code (fragments) later if feasible. part of CURA-10407 --- src/TreeSupport.cpp | 11 +++++++++-- src/TreeSupportTipGenerator.cpp | 30 ++++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/TreeSupport.cpp b/src/TreeSupport.cpp index c226588ebe..eb4509bad6 100644 --- a/src/TreeSupport.cpp +++ b/src/TreeSupport.cpp @@ -2226,9 +2226,16 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor support_layer_storage[layer_idx] = support_layer_storage[layer_idx].difference(floor_layer.offset(10)); // Subtract the support floor from the normal support. } - for (PolygonsPart part : support_layer_storage[layer_idx].splitIntoParts(true)) // Convert every part into a PolygonsPart for the support. + const Polygons support_layer_storage_above = (layer_idx + 1) >= support_layer_storage.size() || layer_idx <= 0 ? Polygons() : support_layer_storage[layer_idx + 1].offset(config.maximum_move_distance); + const auto all_support_areas_in_layer = { support_layer_storage[layer_idx].intersection(support_layer_storage_above), support_layer_storage[layer_idx].difference(support_layer_storage_above) }; + bool use_fractional_config = false; + for (auto& support_areas : all_support_areas_in_layer) { - storage.support.supportLayers[layer_idx].support_infill_parts.emplace_back(part, config.support_line_width, config.support_wall_count); + for (auto& part : support_areas.splitIntoParts(true)) // Convert every part into a PolygonsPart for the support. + { + storage.support.supportLayers[layer_idx].support_infill_parts.emplace_back(part, config.support_line_width, use_fractional_config, config.support_wall_count); + } + use_fractional_config = true; } { diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index 99677f9c09..91ec303194 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -1164,9 +1164,20 @@ void TreeSupportTipGenerator::generateTips( { if (use_fake_roof) { - for (auto part : support_roof_drawn[layer_idx].splitIntoParts()) + const Polygons support_roof_drawn_above = (layer_idx + 1) >= support_roof_drawn.size() || layer_idx <= 0 ? Polygons() : support_roof_drawn[layer_idx + 1].offset(config.maximum_move_distance);; + const auto all_support_areas_in_layer = { support_roof_drawn[layer_idx].intersection(support_roof_drawn_above), support_roof_drawn[layer_idx].difference(support_roof_drawn_above)}; + bool use_fractional_config = false; + for (auto& support_areas : all_support_areas_in_layer) { - storage.support.supportLayers[layer_idx].support_infill_parts.emplace_back(part, config.support_line_width, 0, support_roof_line_distance); + for (const auto& part : support_areas.splitIntoParts()) + { + if (part.area() < config.min_feature_size * config.min_feature_size) + { + continue; + } + storage.support.supportLayers[layer_idx].support_infill_parts.emplace_back(part, config.support_line_width, use_fractional_config, 0, support_roof_line_distance); + } + use_fractional_config = true; } placed_support_lines_support_areas[layer_idx].add(TreeSupportUtils::generateSupportInfillLines( support_roof_drawn[layer_idx], @@ -1186,6 +1197,21 @@ void TreeSupportTipGenerator::generateTips( } }); + cura::parallel_for( + 1, + mesh.overhang_areas.size() - z_distance_delta, + [&](const LayerIndex layer_idx) + { + if (layer_idx > 0) + { + storage.support.supportLayers[layer_idx].support_fractional_roof.add( + storage.support.supportLayers[layer_idx].support_roof.difference( + storage.support.supportLayers[layer_idx + 1].support_roof + ) + ); + } + }); + removeUselessAddedPoints(new_tips, storage, additional_support_areas); for (auto [layer_idx, tips_on_layer] : new_tips | ranges::views::enumerate) From ab39a7738099ea6d9d44984d8b1cb2eacbf59cb4 Mon Sep 17 00:00:00 2001 From: rburema Date: Tue, 17 Oct 2023 14:01:46 +0000 Subject: [PATCH 43/56] Applied clang-format. --- src/TreeSupport.cpp | 6 ++++-- src/TreeSupportTipGenerator.cpp | 15 ++++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/TreeSupport.cpp b/src/TreeSupport.cpp index eb4509bad6..0c9a145cc3 100644 --- a/src/TreeSupport.cpp +++ b/src/TreeSupport.cpp @@ -2226,8 +2226,10 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor support_layer_storage[layer_idx] = support_layer_storage[layer_idx].difference(floor_layer.offset(10)); // Subtract the support floor from the normal support. } - const Polygons support_layer_storage_above = (layer_idx + 1) >= support_layer_storage.size() || layer_idx <= 0 ? Polygons() : support_layer_storage[layer_idx + 1].offset(config.maximum_move_distance); - const auto all_support_areas_in_layer = { support_layer_storage[layer_idx].intersection(support_layer_storage_above), support_layer_storage[layer_idx].difference(support_layer_storage_above) }; + const Polygons support_layer_storage_above + = (layer_idx + 1) >= support_layer_storage.size() || layer_idx <= 0 ? Polygons() : support_layer_storage[layer_idx + 1].offset(config.maximum_move_distance); + const auto all_support_areas_in_layer + = { support_layer_storage[layer_idx].intersection(support_layer_storage_above), support_layer_storage[layer_idx].difference(support_layer_storage_above) }; bool use_fractional_config = false; for (auto& support_areas : all_support_areas_in_layer) { diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index 91ec303194..110acd0436 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -1164,8 +1164,11 @@ void TreeSupportTipGenerator::generateTips( { if (use_fake_roof) { - const Polygons support_roof_drawn_above = (layer_idx + 1) >= support_roof_drawn.size() || layer_idx <= 0 ? Polygons() : support_roof_drawn[layer_idx + 1].offset(config.maximum_move_distance);; - const auto all_support_areas_in_layer = { support_roof_drawn[layer_idx].intersection(support_roof_drawn_above), support_roof_drawn[layer_idx].difference(support_roof_drawn_above)}; + const Polygons support_roof_drawn_above + = (layer_idx + 1) >= support_roof_drawn.size() || layer_idx <= 0 ? Polygons() : support_roof_drawn[layer_idx + 1].offset(config.maximum_move_distance); + ; + const auto all_support_areas_in_layer + = { support_roof_drawn[layer_idx].intersection(support_roof_drawn_above), support_roof_drawn[layer_idx].difference(support_roof_drawn_above) }; bool use_fractional_config = false; for (auto& support_areas : all_support_areas_in_layer) { @@ -1175,7 +1178,8 @@ void TreeSupportTipGenerator::generateTips( { continue; } - storage.support.supportLayers[layer_idx].support_infill_parts.emplace_back(part, config.support_line_width, use_fractional_config, 0, support_roof_line_distance); + storage.support.supportLayers[layer_idx] + .support_infill_parts.emplace_back(part, config.support_line_width, use_fractional_config, 0, support_roof_line_distance); } use_fractional_config = true; } @@ -1205,10 +1209,7 @@ void TreeSupportTipGenerator::generateTips( if (layer_idx > 0) { storage.support.supportLayers[layer_idx].support_fractional_roof.add( - storage.support.supportLayers[layer_idx].support_roof.difference( - storage.support.supportLayers[layer_idx + 1].support_roof - ) - ); + storage.support.supportLayers[layer_idx].support_roof.difference(storage.support.supportLayers[layer_idx + 1].support_roof)); } }); From e1e90a44fdfcdd575c246919e2484d111fcaf0cd Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 17 Oct 2023 17:50:53 +0200 Subject: [PATCH 44/56] Print lower fractional layer heights before full ones, pt 1. Take care of the ordering before it gets to all the order optimizers. part of CURA-10407 --- src/FffGcodeWriter.cpp | 5 ++++- src/TreeSupport.cpp | 2 +- src/TreeSupportTipGenerator.cpp | 2 +- src/support.cpp | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index e7adca9412..d232cc5d7c 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3058,6 +3058,10 @@ bool FffGcodeWriter::addSupportToGCode(const SliceDataStorage& storage, LayerPla return support_added; } + if (extruder_nr == support_roof_extruder_nr) + { + support_added |= addSupportRoofsToGCode(storage, support_layer.support_fractional_roof, gcode_layer.configs_storage.support_fractional_roof_config, gcode_layer); + } if (extruder_nr == support_infill_extruder_nr) { support_added |= processSupportInfill(storage, gcode_layer); @@ -3069,7 +3073,6 @@ bool FffGcodeWriter::addSupportToGCode(const SliceDataStorage& storage, LayerPla support_layer.support_roof.difference(support_layer.support_fractional_roof), gcode_layer.configs_storage.support_roof_config, gcode_layer); - support_added |= addSupportRoofsToGCode(storage, support_layer.support_fractional_roof, gcode_layer.configs_storage.support_fractional_roof_config, gcode_layer); } if (extruder_nr == support_bottom_extruder_nr) { diff --git a/src/TreeSupport.cpp b/src/TreeSupport.cpp index 0c9a145cc3..f1a0504461 100644 --- a/src/TreeSupport.cpp +++ b/src/TreeSupport.cpp @@ -2229,7 +2229,7 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor const Polygons support_layer_storage_above = (layer_idx + 1) >= support_layer_storage.size() || layer_idx <= 0 ? Polygons() : support_layer_storage[layer_idx + 1].offset(config.maximum_move_distance); const auto all_support_areas_in_layer - = { support_layer_storage[layer_idx].intersection(support_layer_storage_above), support_layer_storage[layer_idx].difference(support_layer_storage_above) }; + = { support_layer_storage[layer_idx].difference(support_layer_storage_above), support_layer_storage[layer_idx].intersection(support_layer_storage_above) }; bool use_fractional_config = false; for (auto& support_areas : all_support_areas_in_layer) { diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index 110acd0436..2b4d9db870 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -1168,7 +1168,7 @@ void TreeSupportTipGenerator::generateTips( = (layer_idx + 1) >= support_roof_drawn.size() || layer_idx <= 0 ? Polygons() : support_roof_drawn[layer_idx + 1].offset(config.maximum_move_distance); ; const auto all_support_areas_in_layer - = { support_roof_drawn[layer_idx].intersection(support_roof_drawn_above), support_roof_drawn[layer_idx].difference(support_roof_drawn_above) }; + = { support_roof_drawn[layer_idx].difference(support_roof_drawn_above), support_roof_drawn[layer_idx].intersection(support_roof_drawn_above) }; bool use_fractional_config = false; for (auto& support_areas : all_support_areas_in_layer) { diff --git a/src/support.cpp b/src/support.cpp index 5db9c9932e..ce5c8b5e9b 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -117,7 +117,7 @@ void AreaSupport::splitGlobalSupportAreasIntoSupportInfillParts( const Polygons& global_support_areas_above = (layer_nr + 1) >= global_support_areas_per_layer.size() || layer_nr <= 0 ? Polygons() : global_support_areas_per_layer[layer_nr + 1]; - const auto all_support_areas_in_layer = { global_support_areas.intersection(global_support_areas_above), global_support_areas.difference(global_support_areas_above) }; + const auto all_support_areas_in_layer = { global_support_areas.difference(global_support_areas_above), global_support_areas.intersection(global_support_areas_above) }; bool use_fractional_config = false; for (auto& support_areas : all_support_areas_in_layer) { From f61991bbf0c4528eb9992a82d8361f4f1d0dd957 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 17 Oct 2023 17:51:41 +0200 Subject: [PATCH 45/56] Remove debug code and typos. while working on CURA-10407 --- src/TreeSupportTipGenerator.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index 2b4d9db870..908544513d 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -1166,7 +1166,6 @@ void TreeSupportTipGenerator::generateTips( { const Polygons support_roof_drawn_above = (layer_idx + 1) >= support_roof_drawn.size() || layer_idx <= 0 ? Polygons() : support_roof_drawn[layer_idx + 1].offset(config.maximum_move_distance); - ; const auto all_support_areas_in_layer = { support_roof_drawn[layer_idx].difference(support_roof_drawn_above), support_roof_drawn[layer_idx].intersection(support_roof_drawn_above) }; bool use_fractional_config = false; @@ -1174,10 +1173,6 @@ void TreeSupportTipGenerator::generateTips( { for (const auto& part : support_areas.splitIntoParts()) { - if (part.area() < config.min_feature_size * config.min_feature_size) - { - continue; - } storage.support.supportLayers[layer_idx] .support_infill_parts.emplace_back(part, config.support_line_width, use_fractional_config, 0, support_roof_line_distance); } From 774cc0f1176e5ab6a207623221dc1b74bb6dba00 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 17 Oct 2023 18:09:00 +0200 Subject: [PATCH 46/56] Fix flip-around of boolean. Refactor in prep for consolidation. There's some code duplication that needs to be consolidated, so refactor the 'copy' (or original rather) so it's like the others and can be easily combined into one funciton. While that was being done, found that the booleans weren't flipped after the order of the input array was changed. (In order to print the lower bits _first_, _then_ the 'normal' support. part of CURA-10407 --- src/TreeSupport.cpp | 4 ++-- src/TreeSupportTipGenerator.cpp | 4 ++-- src/support.cpp | 26 ++++++++++++-------------- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/TreeSupport.cpp b/src/TreeSupport.cpp index f1a0504461..8d228ffa71 100644 --- a/src/TreeSupport.cpp +++ b/src/TreeSupport.cpp @@ -2230,14 +2230,14 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor = (layer_idx + 1) >= support_layer_storage.size() || layer_idx <= 0 ? Polygons() : support_layer_storage[layer_idx + 1].offset(config.maximum_move_distance); const auto all_support_areas_in_layer = { support_layer_storage[layer_idx].difference(support_layer_storage_above), support_layer_storage[layer_idx].intersection(support_layer_storage_above) }; - bool use_fractional_config = false; + bool use_fractional_config = true; for (auto& support_areas : all_support_areas_in_layer) { for (auto& part : support_areas.splitIntoParts(true)) // Convert every part into a PolygonsPart for the support. { storage.support.supportLayers[layer_idx].support_infill_parts.emplace_back(part, config.support_line_width, use_fractional_config, config.support_wall_count); } - use_fractional_config = true; + use_fractional_config = false; } { diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index 908544513d..7d669396c9 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -1168,7 +1168,7 @@ void TreeSupportTipGenerator::generateTips( = (layer_idx + 1) >= support_roof_drawn.size() || layer_idx <= 0 ? Polygons() : support_roof_drawn[layer_idx + 1].offset(config.maximum_move_distance); const auto all_support_areas_in_layer = { support_roof_drawn[layer_idx].difference(support_roof_drawn_above), support_roof_drawn[layer_idx].intersection(support_roof_drawn_above) }; - bool use_fractional_config = false; + bool use_fractional_config = true; for (auto& support_areas : all_support_areas_in_layer) { for (const auto& part : support_areas.splitIntoParts()) @@ -1176,7 +1176,7 @@ void TreeSupportTipGenerator::generateTips( storage.support.supportLayers[layer_idx] .support_infill_parts.emplace_back(part, config.support_line_width, use_fractional_config, 0, support_roof_line_distance); } - use_fractional_config = true; + use_fractional_config = false; } placed_support_lines_support_areas[layer_idx].add(TreeSupportUtils::generateSupportInfillLines( support_roof_drawn[layer_idx], diff --git a/src/support.cpp b/src/support.cpp index ce5c8b5e9b..973b3528e7 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -115,27 +115,25 @@ void AreaSupport::splitGlobalSupportAreasIntoSupportInfillParts( continue; } + coord_t support_line_width_here = support_line_width; + if (layer_nr == 0 && mesh_group_settings.get("adhesion_type") != EPlatformAdhesion::RAFT) + { + support_line_width_here *= infill_extruder.settings.get("initial_layer_line_width_factor"); + } + // We don't generate insets and infill area for the parts yet because later the skirt/brim and prime + // tower will remove themselves from the support, so the outlines of the parts can be changed. + const Polygons& global_support_areas_above = (layer_nr + 1) >= global_support_areas_per_layer.size() || layer_nr <= 0 ? Polygons() : global_support_areas_per_layer[layer_nr + 1]; const auto all_support_areas_in_layer = { global_support_areas.difference(global_support_areas_above), global_support_areas.intersection(global_support_areas_above) }; - bool use_fractional_config = false; + bool use_fractional_config = true; for (auto& support_areas : all_support_areas_in_layer) { - std::vector support_islands = support_areas.splitIntoParts(); - for (const PolygonsPart& island_outline : support_islands) + for (const PolygonsPart& island_outline : support_areas.splitIntoParts()) { - coord_t support_line_width_here = support_line_width; - if (layer_nr == 0 && mesh_group_settings.get("adhesion_type") != EPlatformAdhesion::RAFT) - { - support_line_width_here *= infill_extruder.settings.get("initial_layer_line_width_factor"); - } - // We don't generate insets and infill area for the parts yet because later the skirt/brim and prime - // tower will remove themselves from the support, so the outlines of the parts can be changed. - SupportInfillPart support_infill_part(island_outline, support_line_width_here, use_fractional_config, wall_line_count_this_layer); - - storage.support.supportLayers[layer_nr].support_infill_parts.push_back(support_infill_part); + storage.support.supportLayers[layer_nr].support_infill_parts.emplace_back(island_outline, support_line_width_here, use_fractional_config, wall_line_count_this_layer); } - use_fractional_config = true; + use_fractional_config = false; } } } From 7c02094b0f16fc0dac9a1bbbb55e32c729d428e8 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 17 Oct 2023 18:52:28 +0200 Subject: [PATCH 47/56] Consolidate duplicated code into 'fillInfillParts'. done as part of CURA-10407 --- include/sliceDataStorage.h | 11 +++++++++++ src/TreeSupport.cpp | 15 ++------------- src/TreeSupportTipGenerator.cpp | 15 +-------------- src/sliceDataStorage.cpp | 16 ++++++++++++++++ src/support.cpp | 14 +------------- 5 files changed, 31 insertions(+), 40 deletions(-) diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 80b825211a..81d14f24a7 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -226,6 +226,17 @@ class SupportLayer * \param exclude_polygons_boundary_box The boundary box for the polygons to exclude */ void excludeAreasFromSupportInfillAreas(const Polygons& exclude_polygons, const AABB& exclude_polygons_boundary_box); + + /* Fill up the infill parts for the support with the given support polygons. The support polygons will be split into parts. This also takes into account fractional-height support layers. + * + * \param layer_nr Current layer index. + * \param support_fill_per_layer All of the (infill) support (since the layer above might be needed). + * \param support_line_width Line width of the support extrusions. + * \param wall_line_count Wall-line count around the fill. + * \param grow_layer_above (optional, default to 0) In cases where support shrinks per layer up, an appropriate offset may be nescesary. + * \param unionAll (optional, default to false) Wether to 'union all' for the split into parts bit. + */ + void fillInfillParts(const LayerIndex layer_nr, const std::vector& support_fill_per_layer, const coord_t support_line_width, const coord_t wall_line_count, const coord_t grow_layer_above = 0, const bool unionAll = false); }; class SupportStorage diff --git a/src/TreeSupport.cpp b/src/TreeSupport.cpp index 8d228ffa71..7c4fcda0a7 100644 --- a/src/TreeSupport.cpp +++ b/src/TreeSupport.cpp @@ -2226,19 +2226,8 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor support_layer_storage[layer_idx] = support_layer_storage[layer_idx].difference(floor_layer.offset(10)); // Subtract the support floor from the normal support. } - const Polygons support_layer_storage_above - = (layer_idx + 1) >= support_layer_storage.size() || layer_idx <= 0 ? Polygons() : support_layer_storage[layer_idx + 1].offset(config.maximum_move_distance); - const auto all_support_areas_in_layer - = { support_layer_storage[layer_idx].difference(support_layer_storage_above), support_layer_storage[layer_idx].intersection(support_layer_storage_above) }; - bool use_fractional_config = true; - for (auto& support_areas : all_support_areas_in_layer) - { - for (auto& part : support_areas.splitIntoParts(true)) // Convert every part into a PolygonsPart for the support. - { - storage.support.supportLayers[layer_idx].support_infill_parts.emplace_back(part, config.support_line_width, use_fractional_config, config.support_wall_count); - } - use_fractional_config = false; - } + constexpr bool convert_every_part = true; // Convert every part into a PolygonsPart for the support. + storage.support.supportLayers[layer_idx].fillInfillParts(layer_idx, support_layer_storage, config.support_line_width, config.support_wall_count, config.maximum_move_distance, convert_every_part); { std::lock_guard critical_section_progress(critical_sections); diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index 7d669396c9..552f229dd6 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -1164,20 +1164,7 @@ void TreeSupportTipGenerator::generateTips( { if (use_fake_roof) { - const Polygons support_roof_drawn_above - = (layer_idx + 1) >= support_roof_drawn.size() || layer_idx <= 0 ? Polygons() : support_roof_drawn[layer_idx + 1].offset(config.maximum_move_distance); - const auto all_support_areas_in_layer - = { support_roof_drawn[layer_idx].difference(support_roof_drawn_above), support_roof_drawn[layer_idx].intersection(support_roof_drawn_above) }; - bool use_fractional_config = true; - for (auto& support_areas : all_support_areas_in_layer) - { - for (const auto& part : support_areas.splitIntoParts()) - { - storage.support.supportLayers[layer_idx] - .support_infill_parts.emplace_back(part, config.support_line_width, use_fractional_config, 0, support_roof_line_distance); - } - use_fractional_config = false; - } + storage.support.supportLayers[layer_idx].fillInfillParts(layer_idx, support_roof_drawn, config.support_line_width, support_roof_line_distance, config.maximum_move_distance); placed_support_lines_support_areas[layer_idx].add(TreeSupportUtils::generateSupportInfillLines( support_roof_drawn[layer_idx], config, diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index 4533fbb8be..61c6ff1689 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -705,4 +705,20 @@ void SupportLayer::excludeAreasFromSupportInfillAreas(const Polygons& exclude_po } } +void SupportLayer::fillInfillParts(const LayerIndex layer_nr, const std::vector& support_fill_per_layer, const coord_t support_line_width, const coord_t wall_line_count, const coord_t grow_layer_above /*has default 0*/, const bool unionAll /*has default false*/) +{ + const Polygons& support_this_layer = support_fill_per_layer[layer_nr]; + const Polygons& support_layer_above = (layer_nr + 1) >= support_fill_per_layer.size() || layer_nr <= 0 ? Polygons() : support_fill_per_layer[layer_nr + 1].offset(grow_layer_above); + const auto all_support_areas_in_layer = { support_this_layer.difference(support_layer_above), support_this_layer.intersection(support_layer_above) }; + bool use_fractional_config = true; + for (auto& support_areas : all_support_areas_in_layer) + { + for (const PolygonsPart& island_outline : support_areas.splitIntoParts(unionAll)) + { + support_infill_parts.emplace_back(island_outline, support_line_width, use_fractional_config, wall_line_count); + } + use_fractional_config = false; + } +} + } // namespace cura diff --git a/src/support.cpp b/src/support.cpp index 973b3528e7..a0b049fe04 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -122,19 +122,7 @@ void AreaSupport::splitGlobalSupportAreasIntoSupportInfillParts( } // We don't generate insets and infill area for the parts yet because later the skirt/brim and prime // tower will remove themselves from the support, so the outlines of the parts can be changed. - - const Polygons& global_support_areas_above - = (layer_nr + 1) >= global_support_areas_per_layer.size() || layer_nr <= 0 ? Polygons() : global_support_areas_per_layer[layer_nr + 1]; - const auto all_support_areas_in_layer = { global_support_areas.difference(global_support_areas_above), global_support_areas.intersection(global_support_areas_above) }; - bool use_fractional_config = true; - for (auto& support_areas : all_support_areas_in_layer) - { - for (const PolygonsPart& island_outline : support_areas.splitIntoParts()) - { - storage.support.supportLayers[layer_nr].support_infill_parts.emplace_back(island_outline, support_line_width_here, use_fractional_config, wall_line_count_this_layer); - } - use_fractional_config = false; - } + storage.support.supportLayers[layer_nr].fillInfillParts(layer_nr, global_support_areas_per_layer, support_line_width_here, wall_line_count_this_layer); } } From bd1b63430edd92a5f8f6815a4d3d219fe70351fb Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 17 Oct 2023 19:22:21 +0200 Subject: [PATCH 48/56] Print lower fractional layer heights before full ones, pt 2. Take care of the order optimizer w.r.t. partially fractional-height support-layers. part of CURA-10407 --- src/FffGcodeWriter.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index d232cc5d7c..2350305217 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -21,6 +21,7 @@ #include "utils/math.h" #include "utils/orderOptimizer.h" +#include #include #include #include @@ -3148,11 +3149,13 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer const auto zag_skip_count = infill_extruder.settings.get("support_zag_skip_count"); // create a list of outlines and use PathOrderOptimizer to optimize the travel move + PathOrderOptimizer island_order_optimizer_initial(gcode_layer.getLastPlannedPositionOrStartingPosition()); PathOrderOptimizer island_order_optimizer(gcode_layer.getLastPlannedPositionOrStartingPosition()); for (const SupportInfillPart& part : support_layer.support_infill_parts) { - island_order_optimizer.addPolygon(&part); + (part.use_fractional_config ? island_order_optimizer_initial : island_order_optimizer).addPolygon(&part); } + island_order_optimizer_initial.optimize(); island_order_optimizer.optimize(); const auto support_connect_zigzags = infill_extruder.settings.get("support_connect_zigzags"); @@ -3165,7 +3168,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer bool need_travel_to_end_of_last_spiral = true; // Print the thicker infill lines first. (double or more layer thickness, infill combined with previous layers) - for (const PathOrdering& path : island_order_optimizer.paths) + for (const PathOrdering& path : ranges::views::concat(island_order_optimizer_initial.paths, island_order_optimizer.paths)) { const SupportInfillPart& part = *path.vertices; const auto& configs = part.use_fractional_config ? gcode_layer.configs_storage.support_fractional_infill_config : gcode_layer.configs_storage.support_infill_config; From 42b3a7115585e5efbfb27c5cb9c27ac9d256c53b Mon Sep 17 00:00:00 2001 From: rburema Date: Tue, 17 Oct 2023 17:25:07 +0000 Subject: [PATCH 49/56] Applied clang-format. --- include/sliceDataStorage.h | 13 ++++++++++--- src/TreeSupport.cpp | 5 +++-- src/TreeSupportTipGenerator.cpp | 3 ++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 81d14f24a7..dd99d8d197 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -227,16 +227,23 @@ class SupportLayer */ void excludeAreasFromSupportInfillAreas(const Polygons& exclude_polygons, const AABB& exclude_polygons_boundary_box); - /* Fill up the infill parts for the support with the given support polygons. The support polygons will be split into parts. This also takes into account fractional-height support layers. + /* Fill up the infill parts for the support with the given support polygons. The support polygons will be split into parts. This also takes into account fractional-height + * support layers. * * \param layer_nr Current layer index. * \param support_fill_per_layer All of the (infill) support (since the layer above might be needed). * \param support_line_width Line width of the support extrusions. * \param wall_line_count Wall-line count around the fill. * \param grow_layer_above (optional, default to 0) In cases where support shrinks per layer up, an appropriate offset may be nescesary. - * \param unionAll (optional, default to false) Wether to 'union all' for the split into parts bit. + * \param unionAll (optional, default to false) Wether to 'union all' for the split into parts bit. */ - void fillInfillParts(const LayerIndex layer_nr, const std::vector& support_fill_per_layer, const coord_t support_line_width, const coord_t wall_line_count, const coord_t grow_layer_above = 0, const bool unionAll = false); + void fillInfillParts( + const LayerIndex layer_nr, + const std::vector& support_fill_per_layer, + const coord_t support_line_width, + const coord_t wall_line_count, + const coord_t grow_layer_above = 0, + const bool unionAll = false); }; class SupportStorage diff --git a/src/TreeSupport.cpp b/src/TreeSupport.cpp index 7c4fcda0a7..9ce458d7f7 100644 --- a/src/TreeSupport.cpp +++ b/src/TreeSupport.cpp @@ -2226,8 +2226,9 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor support_layer_storage[layer_idx] = support_layer_storage[layer_idx].difference(floor_layer.offset(10)); // Subtract the support floor from the normal support. } - constexpr bool convert_every_part = true; // Convert every part into a PolygonsPart for the support. - storage.support.supportLayers[layer_idx].fillInfillParts(layer_idx, support_layer_storage, config.support_line_width, config.support_wall_count, config.maximum_move_distance, convert_every_part); + constexpr bool convert_every_part = true; // Convert every part into a PolygonsPart for the support. + storage.support.supportLayers[layer_idx] + .fillInfillParts(layer_idx, support_layer_storage, config.support_line_width, config.support_wall_count, config.maximum_move_distance, convert_every_part); { std::lock_guard critical_section_progress(critical_sections); diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index 552f229dd6..d362052739 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -1164,7 +1164,8 @@ void TreeSupportTipGenerator::generateTips( { if (use_fake_roof) { - storage.support.supportLayers[layer_idx].fillInfillParts(layer_idx, support_roof_drawn, config.support_line_width, support_roof_line_distance, config.maximum_move_distance); + storage.support.supportLayers[layer_idx] + .fillInfillParts(layer_idx, support_roof_drawn, config.support_line_width, support_roof_line_distance, config.maximum_move_distance); placed_support_lines_support_areas[layer_idx].add(TreeSupportUtils::generateSupportInfillLines( support_roof_drawn[layer_idx], config, From e78f42c19bb46e314432f3e074dbdfa0e7f03976 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 24 Oct 2023 22:14:11 +0200 Subject: [PATCH 50/56] Fix slice in fractional support The code was attempting to access an index that was out of bounds of the array. Add guards to prevent this access. CURA-11041 --- src/support.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/support.cpp b/src/support.cpp index a0b049fe04..09a8fb1de3 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -1809,7 +1809,7 @@ void AreaSupport::generateSupportRoof(SliceDataStorage& storage, const SliceMesh Polygons roofs; generateSupportInterfaceLayer(global_support_areas_per_layer[layer_idx], mesh_outlines, roof_line_width, roof_outline_offset, minimum_roof_area, roofs); support_layers[layer_idx].support_roof.add(roofs); - if (layer_idx > 0) + if (layer_idx > 0 && layer_idx < support_layers.size() - 1) { support_layers[layer_idx].support_fractional_roof.add(roofs.difference(support_layers[layer_idx + 1].support_roof)); } From 131cae1f4a49d0ec4086bbae90659492b62be671 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Tue, 24 Oct 2023 20:14:53 +0000 Subject: [PATCH 51/56] Applied clang-format. --- src/sliceDataStorage.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index 61c6ff1689..b178075a26 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -705,10 +705,17 @@ void SupportLayer::excludeAreasFromSupportInfillAreas(const Polygons& exclude_po } } -void SupportLayer::fillInfillParts(const LayerIndex layer_nr, const std::vector& support_fill_per_layer, const coord_t support_line_width, const coord_t wall_line_count, const coord_t grow_layer_above /*has default 0*/, const bool unionAll /*has default false*/) +void SupportLayer::fillInfillParts( + const LayerIndex layer_nr, + const std::vector& support_fill_per_layer, + const coord_t support_line_width, + const coord_t wall_line_count, + const coord_t grow_layer_above /*has default 0*/, + const bool unionAll /*has default false*/) { const Polygons& support_this_layer = support_fill_per_layer[layer_nr]; - const Polygons& support_layer_above = (layer_nr + 1) >= support_fill_per_layer.size() || layer_nr <= 0 ? Polygons() : support_fill_per_layer[layer_nr + 1].offset(grow_layer_above); + const Polygons& support_layer_above + = (layer_nr + 1) >= support_fill_per_layer.size() || layer_nr <= 0 ? Polygons() : support_fill_per_layer[layer_nr + 1].offset(grow_layer_above); const auto all_support_areas_in_layer = { support_this_layer.difference(support_layer_above), support_this_layer.intersection(support_layer_above) }; bool use_fractional_config = true; for (auto& support_areas : all_support_areas_in_layer) From 1609f0e97096d2877d299ce040c33e317b3e5fe7 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 25 Oct 2023 15:35:36 +0200 Subject: [PATCH 52/56] Fix possible crash --- src/LayerPlan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 70a6152eb7..254c40d06a 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -2079,7 +2079,7 @@ void LayerPlan::writeGCode(GCodeExport& gcode) // Prevent the final travel(s) from resetting to the 'previous' layer height. gcode.setZ(final_travel_z); } - for (unsigned int point_idx = 0; point_idx < path.points.size() - 1; point_idx++) + for (size_t point_idx = 0; point_idx + 1 < path.points.size(); point_idx++) { gcode.writeTravel(path.points[point_idx], speed); } From 98fc849b147d9603e3310a7511168dcc6dc9f176 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 25 Oct 2023 22:55:51 +0200 Subject: [PATCH 53/56] (From code review.) Small refactors and add documentation. done as part of CURA-10407 --- include/GCodePathConfig.h | 2 +- include/LayerPlan.h | 7 ++++--- include/SupportInfillPart.h | 2 +- include/pathPlanning/GCodePath.h | 2 +- src/LayerPlan.cpp | 12 ++++++------ 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/include/GCodePathConfig.h b/include/GCodePathConfig.h index 1f0da38d60..4531b650aa 100644 --- a/include/GCodePathConfig.h +++ b/include/GCodePathConfig.h @@ -18,7 +18,7 @@ namespace cura */ struct GCodePathConfig { - coord_t z_offset{}; + coord_t z_offset{}; // wall_toolpaths; //!< Any walls go here, not in the areas, where they could be combined vertically (don't combine walls). Binned by inset_idx. coord_t custom_line_distance; - bool use_fractional_config; + bool use_fractional_config; //!< Request to use the configuration used to fill a partial layer height here, instead of the normal full layer height configuration. SupportInfillPart(const PolygonsPart& outline, coord_t support_line_width, bool use_fractional_config, int inset_count_to_generate = 0, coord_t custom_line_distance = 0); diff --git a/include/pathPlanning/GCodePath.h b/include/pathPlanning/GCodePath.h index ef59a8747d..639e67bb85 100644 --- a/include/pathPlanning/GCodePath.h +++ b/include/pathPlanning/GCodePath.h @@ -29,7 +29,7 @@ namespace cura */ struct GCodePath { - coord_t z_offset{}; + coord_t z_offset{}; // mesh; //!< Which mesh this path belongs to, if any. If it's not part of any mesh, the mesh should be nullptr; SpaceFillType space_fill_type{}; //!< The type of space filling of which this path is a part diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 254c40d06a..0da4344f6a 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -38,8 +38,8 @@ constexpr int MINIMUM_SQUARED_LINE_LENGTH = MINIMUM_LINE_LENGTH * MINIMUM_LINE_L GCodePath* LayerPlan::getLatestPathWithConfig( const GCodePathConfig& config, - const coord_t z_offset, const SpaceFillType space_fill_type, + const coord_t z_offset, const Ratio flow, const Ratio width_factor, const bool spiralize, @@ -329,14 +329,14 @@ std::optional> LayerPlan::getFirstTravelDestinationState( return ret; } -GCodePath& LayerPlan::addTravel(const Point p, const bool force_retract, const coord_t z_offset) +GCodePath& LayerPlan::addTravel(const Point& p, const bool force_retract, const coord_t z_offset) { const GCodePathConfig& travel_config = configs_storage.travel_config_per_extruder[getExtruder()]; const RetractionConfig& retraction_config = current_mesh ? current_mesh->retraction_wipe_config.retraction_config : storage.retraction_wipe_config_per_extruder[getExtruder()].retraction_config; - GCodePath* path = getLatestPathWithConfig(travel_config, z_offset, SpaceFillType::None); + GCodePath* path = getLatestPathWithConfig(travel_config, SpaceFillType::None, z_offset); bool combed = false; @@ -481,7 +481,7 @@ GCodePath& LayerPlan::addTravel(const Point p, const bool force_retract, const c return ret; } -GCodePath& LayerPlan::addTravel_simple(const Point p, GCodePath* path) +GCodePath& LayerPlan::addTravel_simple(const Point& p, GCodePath* path) { bool is_first_travel_of_layer = ! static_cast(last_planned_position); if (is_first_travel_of_layer) @@ -491,7 +491,7 @@ GCodePath& LayerPlan::addTravel_simple(const Point p, GCodePath* path) } if (path == nullptr) { - path = getLatestPathWithConfig(configs_storage.travel_config_per_extruder[getExtruder()], 0, SpaceFillType::None); + path = getLatestPathWithConfig(configs_storage.travel_config_per_extruder[getExtruder()], SpaceFillType::None); } path->points.push_back(p); last_planned_position = p; @@ -518,7 +518,7 @@ void LayerPlan::addExtrusionMove( const Ratio speed_factor, const double fan_speed) { - GCodePath* path = getLatestPathWithConfig(config, config.z_offset, space_fill_type, flow, width_factor, spiralize, speed_factor); + GCodePath* path = getLatestPathWithConfig(config, space_fill_type, config.z_offset, flow, width_factor, spiralize, speed_factor); path->points.push_back(p); path->setFanSpeed(fan_speed); if (! static_cast(first_extrusion_acc_jerk)) From 78fcc88b5518e42750e8fcb0567d3fdf37f4ae7d Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 25 Oct 2023 23:21:40 +0200 Subject: [PATCH 54/56] Correct for support-gap equal to exact layer-height multiple. part of CURA-10407 --- src/FffGcodeWriter.cpp | 4 ++-- src/support.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 9ea700bb36..58424f79fb 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -2289,7 +2289,7 @@ bool FffGcodeWriter::processInsets( if (mesh_group_settings.get("support_enable")) { const coord_t z_distance_top = mesh.settings.get("support_top_distance"); - const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height); // Previously '... +1', but now there is an extra fractional layer on top. + const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height) + (z_distance_top % layer_height == 0) ? 1 : 0; const int support_layer_nr = gcode_layer.getLayerNr() - z_distance_top_layers; if (support_layer_nr > 0) @@ -2693,7 +2693,7 @@ void FffGcodeWriter::processTopBottom( { const coord_t layer_height = mesh_config.inset0_config.getLayerThickness(); const coord_t z_distance_top = mesh.settings.get("support_top_distance"); - const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height); // Previously '... +1', but now there is an extra fractional layer on top. + const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height) + (z_distance_top % layer_height == 0) ? 1 : 0; support_layer_nr = layer_nr - z_distance_top_layers; } diff --git a/src/support.cpp b/src/support.cpp index 09a8fb1de3..4f57ce44ee 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -785,7 +785,7 @@ void AreaSupport::generateOverhangAreasForMesh(SliceDataStorage& storage, SliceM // Don't generate overhang areas if the Z distance is higher than the objects we're generating support for. const coord_t layer_height = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("layer_height"); const coord_t z_distance_top = mesh.settings.get("support_top_distance"); - const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height); // Previously '... +1', but now there is an extra fractional layer on top. + const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height) + (z_distance_top % layer_height == 0) ? 1 : 0; if (z_distance_top_layers + 1 > storage.print_layer_count) { return; @@ -1050,7 +1050,7 @@ void AreaSupport::generateSupportAreasForMesh( // early out const coord_t layer_thickness = mesh_group_settings.get("layer_height"); const coord_t z_distance_top = ((mesh.settings.get("support_roof_enable")) ? roof_settings : infill_settings).get("support_top_distance"); - const size_t layer_z_distance_top = round_up_divide(z_distance_top, layer_thickness); // Previously '... +1', but now there is an extra fractional layer on top. + const size_t layer_z_distance_top = round_up_divide(z_distance_top, layer_thickness) + (z_distance_top % layer_thickness == 0) ? 1 : 0; if (layer_z_distance_top + 1 > layer_count) { return; From 54edc02f5e7458738a7a712eee91cd4aa11d61ba Mon Sep 17 00:00:00 2001 From: rburema Date: Wed, 25 Oct 2023 21:22:30 +0000 Subject: [PATCH 55/56] Applied clang-format. --- include/FffGcodeWriter.h | 6 +++--- include/SupportInfillPart.h | 4 ++-- include/pathPlanning/GCodePath.h | 6 +++--- include/settings/PathConfigStorage.h | 4 ++-- src/LayerPlan.cpp | 18 ++++++++--------- src/TreeSupport.cpp | 28 +++++++++++++------------- src/TreeSupportTipGenerator.cpp | 22 ++++++++++---------- src/support.cpp | 30 ++++++++++++++-------------- 8 files changed, 59 insertions(+), 59 deletions(-) diff --git a/include/FffGcodeWriter.h b/include/FffGcodeWriter.h index e46f2b471c..7e5908e136 100644 --- a/include/FffGcodeWriter.h +++ b/include/FffGcodeWriter.h @@ -4,6 +4,9 @@ #ifndef GCODE_WRITER_H #define GCODE_WRITER_H +#include +#include + #include "FanSpeedLayerTime.h" #include "LayerPlanBuffer.h" #include "gcodeExport.h" @@ -12,9 +15,6 @@ #include "utils/ExtrusionLine.h" //Processing variable-width paths. #include "utils/NoCopy.h" -#include -#include - namespace cura { diff --git a/include/SupportInfillPart.h b/include/SupportInfillPart.h index 70de71aecc..1767847cb7 100644 --- a/include/SupportInfillPart.h +++ b/include/SupportInfillPart.h @@ -4,12 +4,12 @@ #ifndef SUPPORT_INFILL_PART_H #define SUPPORT_INFILL_PART_H +#include + #include "utils/AABB.h" #include "utils/ExtrusionLine.h" #include "utils/polygon.h" -#include - namespace cura { diff --git a/include/pathPlanning/GCodePath.h b/include/pathPlanning/GCodePath.h index 639e67bb85..da4efd30aa 100644 --- a/include/pathPlanning/GCodePath.h +++ b/include/pathPlanning/GCodePath.h @@ -4,6 +4,9 @@ #ifndef PATH_PLANNING_G_CODE_PATH_H #define PATH_PLANNING_G_CODE_PATH_H +#include +#include + #include "GCodePathConfig.h" #include "SpaceFillType.h" #include "TimeMaterialEstimates.h" @@ -11,9 +14,6 @@ #include "sliceDataStorage.h" #include "utils/IntPoint.h" -#include -#include - namespace cura { diff --git a/include/settings/PathConfigStorage.h b/include/settings/PathConfigStorage.h index 4ba5bf2837..feafea23bf 100644 --- a/include/settings/PathConfigStorage.h +++ b/include/settings/PathConfigStorage.h @@ -4,14 +4,14 @@ #ifndef SETTINGS_PATH_CONFIGS_H #define SETTINGS_PATH_CONFIGS_H +#include + #include "GCodePathConfig.h" #include "pathPlanning/SpeedDerivatives.h" #include "settings/MeshPathConfigs.h" #include "settings/types/LayerIndex.h" #include "utils/Coord_t.h" -#include - namespace cura { diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 0da4344f6a..52305a9521 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -3,6 +3,15 @@ #include "LayerPlan.h" +#include +#include +#include +#include + +#include +#include +#include + #include "Application.h" //To communicate layer view data. #include "ExtruderTrain.h" #include "PathOrderMonotonic.h" //Monotonic ordering of skin lines. @@ -20,15 +29,6 @@ #include "utils/polygonUtils.h" #include "utils/section_type.h" -#include -#include -#include - -#include -#include -#include -#include - namespace cura { diff --git a/src/TreeSupport.cpp b/src/TreeSupport.cpp index 9ce458d7f7..bf876ec582 100644 --- a/src/TreeSupport.cpp +++ b/src/TreeSupport.cpp @@ -3,6 +3,20 @@ #include "TreeSupport.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + #include "Application.h" //To get settings. #include "TreeSupportTipGenerator.h" #include "TreeSupportUtils.h" @@ -18,20 +32,6 @@ #include "utils/polygonUtils.h" //For moveInside. #include "utils/section_type.h" -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - namespace cura { diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index d362052739..094a819544 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -3,6 +3,17 @@ #include "TreeSupportTipGenerator.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include + #include "Application.h" //To get settings. #include "TreeSupportUtils.h" #include "infill/SierpinskiFillProvider.h" @@ -13,17 +24,6 @@ #include "utils/math.h" //For round_up_divide and PI. #include "utils/polygonUtils.h" //For moveInside. -#include -#include -#include -#include -#include - -#include -#include -#include -#include - namespace cura { diff --git a/src/support.cpp b/src/support.cpp index 4f57ce44ee..1a641c208e 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -3,6 +3,21 @@ #include "support.h" +#include // sqrt, round +#include +#include // ifstream.good() +#include // pair + +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "Application.h" //To get settings. #include "BoostInterface.hpp" #include "ExtruderTrain.h" @@ -24,21 +39,6 @@ #include "utils/math.h" #include "utils/views/get.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include // sqrt, round -#include -#include // ifstream.good() -#include // pair - namespace cura { From 4a09451702b7c130583719067da49b6981fbf3ef Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Thu, 26 Oct 2023 14:35:54 +0200 Subject: [PATCH 56/56] Really correct support z-gap for all heights now hopefully. part of CURA-10407 --- src/FffGcodeWriter.cpp | 4 ++-- src/support.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 58424f79fb..4605960d39 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -2289,7 +2289,7 @@ bool FffGcodeWriter::processInsets( if (mesh_group_settings.get("support_enable")) { const coord_t z_distance_top = mesh.settings.get("support_top_distance"); - const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height) + (z_distance_top % layer_height == 0) ? 1 : 0; + const size_t z_distance_top_layers = (z_distance_top / layer_height) + 1; const int support_layer_nr = gcode_layer.getLayerNr() - z_distance_top_layers; if (support_layer_nr > 0) @@ -2693,7 +2693,7 @@ void FffGcodeWriter::processTopBottom( { const coord_t layer_height = mesh_config.inset0_config.getLayerThickness(); const coord_t z_distance_top = mesh.settings.get("support_top_distance"); - const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height) + (z_distance_top % layer_height == 0) ? 1 : 0; + const size_t z_distance_top_layers = (z_distance_top / layer_height) + 1; support_layer_nr = layer_nr - z_distance_top_layers; } diff --git a/src/support.cpp b/src/support.cpp index 1a641c208e..6bae947fa2 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -785,7 +785,7 @@ void AreaSupport::generateOverhangAreasForMesh(SliceDataStorage& storage, SliceM // Don't generate overhang areas if the Z distance is higher than the objects we're generating support for. const coord_t layer_height = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("layer_height"); const coord_t z_distance_top = mesh.settings.get("support_top_distance"); - const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height) + (z_distance_top % layer_height == 0) ? 1 : 0; + const size_t z_distance_top_layers = (z_distance_top / layer_height) + 1; if (z_distance_top_layers + 1 > storage.print_layer_count) { return; @@ -1050,7 +1050,7 @@ void AreaSupport::generateSupportAreasForMesh( // early out const coord_t layer_thickness = mesh_group_settings.get("layer_height"); const coord_t z_distance_top = ((mesh.settings.get("support_roof_enable")) ? roof_settings : infill_settings).get("support_top_distance"); - const size_t layer_z_distance_top = round_up_divide(z_distance_top, layer_thickness) + (z_distance_top % layer_thickness == 0) ? 1 : 0; + const size_t layer_z_distance_top = (z_distance_top / layer_thickness) + 1; if (layer_z_distance_top + 1 > layer_count) { return;