From b621644d96d4334f246c0475ef65cedf499fdf74 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Thu, 21 Sep 2023 15:38:05 +0200 Subject: [PATCH 001/116] 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 002/116] 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 003/116] 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 c6f5b9ae30c43f5b9faf59b1df427a275da77678 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 21 Sep 2023 16:51:29 +0200 Subject: [PATCH 004/116] Basically working prime tower without raft CURA-10993 --- src/FffGcodeWriter.cpp | 4 +- src/PrimeTower.cpp | 107 +++++++++++++++++++++-------------------- src/raft.cpp | 50 ++++++++++--------- 3 files changed, 86 insertions(+), 75 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 235f6f587e..0bc8b7a809 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -161,7 +161,9 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep } run_multiple_producers_ordered_consumer( - process_layer_starting_layer_nr, + // process_layer_starting_layer_nr, + -Raft::getTotalExtraLayers(), + // total_layers + Raft::getFillerLayerCount() - 1, total_layers, [&storage, total_layers, this](int layer_nr) { diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 3a4846c69c..b731011398 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -1,65 +1,69 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. -#include -#include +#include "PrimeTower.h" #include "Application.h" //To get settings. #include "ExtruderTrain.h" -#include "gcodeExport.h" -#include "infill.h" #include "LayerPlan.h" -#include "PrimeTower.h" #include "PrintFeature.h" -#include "raft.h" #include "Scene.h" #include "Slice.h" +#include "gcodeExport.h" +#include "infill.h" +#include "raft.h" #include "sliceDataStorage.h" -#define CIRCLE_RESOLUTION 32 //The number of vertices in each circle. +#include +#include + +#define CIRCLE_RESOLUTION 32 // The number of vertices in each circle. -namespace cura +namespace cura { PrimeTower::PrimeTower() -: wipe_from_middle(false) + : wipe_from_middle(false) { const Scene& scene = Application::getInstance().current_slice->scene; { EPlatformAdhesion adhesion_type = scene.current_mesh_group->settings.get("adhesion_type"); - //When we have multiple extruders sharing the same heater/nozzle, we expect that all the extruders have been + // When we have multiple extruders sharing the same heater/nozzle, we expect that all the extruders have been //'primed' by the print-start gcode script, but we don't know which one has been left at the tip of the nozzle - //and whether it needs 'purging' (before extruding a pure material) or not, so we need to prime (actually purge) - //each extruder before it is used for the model. This can done by the (per-extruder) brim lines or (per-extruder) - //skirt lines when they are used, but we need to do that inside the first prime-tower layer when they are not - //used (sacrifying for this purpose the usual single-extruder first layer, that would be better for prime-tower - //adhesion). - - multiple_extruders_on_first_layer = scene.current_mesh_group->settings.get("machine_extruders_share_nozzle") && ((adhesion_type != EPlatformAdhesion::SKIRT) && (adhesion_type != EPlatformAdhesion::BRIM)); + // and whether it needs 'purging' (before extruding a pure material) or not, so we need to prime (actually purge) + // each extruder before it is used for the model. This can done by the (per-extruder) brim lines or (per-extruder) + // skirt lines when they are used, but we need to do that inside the first prime-tower layer when they are not + // used (sacrifying for this purpose the usual single-extruder first layer, that would be better for prime-tower + // adhesion). + + multiple_extruders_on_first_layer = scene.current_mesh_group->settings.get("machine_extruders_share_nozzle") + && ((adhesion_type != EPlatformAdhesion::SKIRT) && (adhesion_type != EPlatformAdhesion::BRIM)); } - enabled = scene.current_mesh_group->settings.get("prime_tower_enable") - && scene.current_mesh_group->settings.get("prime_tower_min_volume") > 10 + enabled = scene.current_mesh_group->settings.get("prime_tower_enable") && scene.current_mesh_group->settings.get("prime_tower_min_volume") > 10 && scene.current_mesh_group->settings.get("prime_tower_size") > 10; - would_have_actual_tower = enabled; // Assume so for now. + would_have_actual_tower = enabled; // Assume so for now. extruder_count = scene.extruders.size(); extruder_order.resize(extruder_count); for (unsigned int extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++) { - extruder_order[extruder_nr] = extruder_nr; //Start with default order, then sort. + extruder_order[extruder_nr] = extruder_nr; // Start with default order, then sort. } - //Sort from high adhesion to low adhesion. - const Scene* scene_pointer = &scene; //Communicate to lambda via pointer to prevent copy. - std::stable_sort(extruder_order.begin(), extruder_order.end(), [scene_pointer](const unsigned int& extruder_nr_a, const unsigned int& extruder_nr_b) -> bool - { - const Ratio adhesion_a = scene_pointer->extruders[extruder_nr_a].settings.get("material_adhesion_tendency"); - const Ratio adhesion_b = scene_pointer->extruders[extruder_nr_b].settings.get("material_adhesion_tendency"); - return adhesion_a < adhesion_b; - }); + // Sort from high adhesion to low adhesion. + const Scene* scene_pointer = &scene; // Communicate to lambda via pointer to prevent copy. + std::stable_sort( + extruder_order.begin(), + extruder_order.end(), + [scene_pointer](const unsigned int& extruder_nr_a, const unsigned int& extruder_nr_b) -> bool + { + const Ratio adhesion_a = scene_pointer->extruders[extruder_nr_a].settings.get("material_adhesion_tendency"); + const Ratio adhesion_b = scene_pointer->extruders[extruder_nr_b].settings.get("material_adhesion_tendency"); + return adhesion_a < adhesion_b; + }); } void PrimeTower::checkUsed(const SliceDataStorage& storage) @@ -78,7 +82,7 @@ void PrimeTower::checkUsed(const SliceDataStorage& storage) void PrimeTower::generateGroundpoly() { - if (!enabled) + if (! enabled) { return; } @@ -97,7 +101,8 @@ void PrimeTower::generateGroundpoly() void PrimeTower::generatePaths(const SliceDataStorage& storage) { - would_have_actual_tower = storage.max_print_height_second_to_last_extruder >= 0; //Maybe it turns out that we don't need a prime tower after all because there are no layer switches. + would_have_actual_tower + = storage.max_print_height_second_to_last_extruder >= 0; // Maybe it turns out that we don't need a prime tower after all because there are no layer switches. if (would_have_actual_tower && enabled) { generatePaths_denseInfill(); @@ -113,7 +118,7 @@ void PrimeTower::generatePaths_denseInfill() pattern_per_extruder.resize(extruder_count); pattern_per_extruder_layer0.resize(extruder_count); - coord_t cumulative_inset = 0; //Each tower shape is going to be printed inside the other. This is the inset we're doing for each extruder. + coord_t cumulative_inset = 0; // Each tower shape is going to be printed inside the other. This is the inset we're doing for each extruder. for (size_t extruder_nr : extruder_order) { const coord_t line_width = scene.extruders[extruder_nr].settings.get("prime_tower_line_width"); @@ -122,28 +127,28 @@ void PrimeTower::generatePaths_denseInfill() coord_t current_volume = 0; ExtrusionMoves& pattern = pattern_per_extruder[extruder_nr]; - //Create the walls of the prime tower. + // Create the walls of the prime tower. unsigned int wall_nr = 0; for (; current_volume < required_volume; wall_nr++) { - //Create a new polygon with an offset from the outer polygon. + // Create a new polygon with an offset from the outer polygon. Polygons polygons = outer_poly.offset(-cumulative_inset - wall_nr * line_width - line_width / 2); pattern.polygons.add(polygons); current_volume += polygons.polygonLength() * line_width * layer_height * flow; - if (polygons.empty()) //Don't continue. We won't ever reach the required volume because it doesn't fit. + if (polygons.empty()) // Don't continue. We won't ever reach the required volume because it doesn't fit. { break; } } - //Only the most inside extruder needs to fill the inside of the prime tower - if (extruder_nr != extruder_order.back()) + // Only the most inside extruder needs to fill the inside of the prime tower + if (false /*extruder_nr != extruder_order.back()*/) { pattern_per_extruder_layer0 = pattern_per_extruder; } else { - //Generate the pattern for the first layer. + // Generate the pattern for the first layer. coord_t line_width_layer0 = line_width * scene.extruders[extruder_nr].settings.get("initial_layer_line_width_factor"); ExtrusionMoves& pattern_layer0 = pattern_per_extruder_layer0[extruder_nr]; @@ -151,7 +156,7 @@ void PrimeTower::generatePaths_denseInfill() // the infill pattern because the infill pattern tries to connect polygons in different insets which causes the // first layer of the prime tower to not stick well. Polygons inset = outer_poly.offset(-cumulative_inset - line_width_layer0 / 2); - while (!inset.empty()) + while (! inset.empty()) { pattern_layer0.polygons.add(inset); inset = inset.offset(-line_width_layer0); @@ -183,7 +188,7 @@ void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_la } const LayerIndex layer_nr = gcode_layer.getLayerNr(); - if (layer_nr < 0 || layer_nr > storage.max_print_height_second_to_last_extruder + 1) + if (/*layer_nr < 0 ||*/ layer_nr > storage.max_print_height_second_to_last_extruder + 1) { return; } @@ -207,7 +212,7 @@ void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_la // post-wipe: if (post_wipe) { - //Make sure we wipe the old extruder on the prime tower. + // Make sure we wipe the old extruder on the prime tower. const Settings& previous_settings = Application::getInstance().current_slice->scene.extruders[prev_extruder].settings; const Point previous_nozzle_offset = Point(previous_settings.get("machine_nozzle_offset_x"), previous_settings.get("machine_nozzle_offset_y")); const Settings& new_settings = Application::getInstance().current_slice->scene.extruders[new_extruder].settings; @@ -220,9 +225,9 @@ void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_la void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t extruder_nr) const { - const ExtrusionMoves& pattern = (gcode_layer.getLayerNr() == -static_cast(Raft::getFillerLayerCount())) - ? pattern_per_extruder_layer0[extruder_nr] - : pattern_per_extruder[extruder_nr]; + const ExtrusionMoves& pattern + //= (gcode_layer.getLayerNr() == -static_cast(Raft::getFillerLayerCount())) ? pattern_per_extruder_layer0[extruder_nr] : pattern_per_extruder[extruder_nr]; + = (gcode_layer.getLayerNr() == -static_cast(Raft::getTotalExtraLayers())) ? pattern_per_extruder_layer0[extruder_nr] : pattern_per_extruder[extruder_nr]; const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; @@ -234,7 +239,7 @@ void PrimeTower::subtractFromSupport(SliceDataStorage& storage) { const Polygons outside_polygon = outer_poly.getOutsidePolygons(); AABB outside_polygon_boundary_box(outside_polygon); - for(size_t layer = 0; layer <= (size_t)storage.max_print_height_second_to_last_extruder + 1 && layer < storage.support.supportLayers.size(); layer++) + for (size_t layer = 0; layer <= (size_t)storage.max_print_height_second_to_last_extruder + 1 && layer < storage.support.supportLayers.size(); layer++) { SupportLayer& support_layer = storage.support.supportLayers[layer]; // take the differences of the support infill parts and the prime tower area @@ -244,13 +249,13 @@ void PrimeTower::subtractFromSupport(SliceDataStorage& storage) void PrimeTower::gotoStartLocation(LayerPlan& gcode_layer, const int extruder_nr) const { - int current_start_location_idx = ((((extruder_nr + 1) * gcode_layer.getLayerNr()) % number_of_prime_tower_start_locations) - + number_of_prime_tower_start_locations) % number_of_prime_tower_start_locations; + int current_start_location_idx = ((((extruder_nr + 1) * gcode_layer.getLayerNr()) % number_of_prime_tower_start_locations) + number_of_prime_tower_start_locations) + % number_of_prime_tower_start_locations; const ClosestPolygonPoint wipe_location = prime_tower_start_locations[current_start_location_idx]; const ExtruderTrain& train = Application::getInstance().current_slice->scene.extruders[extruder_nr]; - const coord_t inward_dist = train.settings.get("machine_nozzle_size") * 3 / 2 ; + const coord_t inward_dist = train.settings.get("machine_nozzle_size") * 3 / 2; const coord_t start_dist = train.settings.get("machine_nozzle_size") * 2; const Point prime_end = PolygonUtils::moveInsideDiagonally(wipe_location, inward_dist); const Point outward_dir = wipe_location.location - prime_end; @@ -259,4 +264,4 @@ void PrimeTower::gotoStartLocation(LayerPlan& gcode_layer, const int extruder_nr gcode_layer.addTravel(prime_start); } -}//namespace cura +} // namespace cura diff --git a/src/raft.cpp b/src/raft.cpp index 96c81be90b..16134f55bc 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -1,17 +1,18 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. -#include +#include "raft.h" #include "Application.h" //To get settings. #include "ExtruderTrain.h" -#include "raft.h" #include "Slice.h" +#include "settings/EnumSettings.h" //For EPlatformAdhesion. #include "sliceDataStorage.h" #include "support.h" -#include "settings/EnumSettings.h" //For EPlatformAdhesion. #include "utils/math.h" +#include + namespace cura { @@ -21,24 +22,27 @@ void Raft::generate(SliceDataStorage& storage) const Settings& settings = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("raft_base_extruder_nr").settings; const coord_t distance = settings.get("raft_margin"); constexpr bool include_support = true; - constexpr bool dont_include_prime_tower = false; // Prime tower raft will be handled separately in 'storage.primeRaftOutline'; see below. + constexpr bool dont_include_prime_tower = false; // Prime tower raft will be handled separately in 'storage.primeRaftOutline'; see below. storage.raftOutline = storage.getLayerOutlines(0, include_support, dont_include_prime_tower).offset(distance, ClipperLib::jtRound); const coord_t shield_line_width_layer0 = settings.get("skirt_brim_line_width"); if (storage.draft_protection_shield.size() > 0) { - Polygons draft_shield_raft = storage.draft_protection_shield.offset(shield_line_width_layer0) // start half a line width outside shield - .difference(storage.draft_protection_shield.offset(-distance - shield_line_width_layer0 / 2, ClipperLib::jtRound)); // end distance inside shield + Polygons draft_shield_raft + = storage.draft_protection_shield + .offset(shield_line_width_layer0) // start half a line width outside shield + .difference(storage.draft_protection_shield.offset(-distance - shield_line_width_layer0 / 2, ClipperLib::jtRound)); // end distance inside shield storage.raftOutline = storage.raftOutline.unionPolygons(draft_shield_raft); } if (storage.oozeShield.size() > 0 && storage.oozeShield[0].size() > 0) { const Polygons& ooze_shield = storage.oozeShield[0]; - Polygons ooze_shield_raft = ooze_shield.offset(shield_line_width_layer0) // start half a line width outside shield + Polygons ooze_shield_raft = ooze_shield + .offset(shield_line_width_layer0) // start half a line width outside shield .difference(ooze_shield.offset(-distance - shield_line_width_layer0 / 2, ClipperLib::jtRound)); // end distance inside shield storage.raftOutline = storage.raftOutline.unionPolygons(ooze_shield_raft); } - if(settings.get("raft_remove_inside_corners")) + if (settings.get("raft_remove_inside_corners")) { storage.raftOutline.makeConvex(); } @@ -62,25 +66,25 @@ void Raft::generate(SliceDataStorage& storage) } } - storage.primeRaftOutline = storage.primeTower.outer_poly.offset(distance, ClipperLib::jtRound); - // NOTE: the raft doesn't take the prime tower brim into account, because it's (currently) not being printed when printing a raft - if (settings.get("raft_remove_inside_corners")) - { - storage.primeRaftOutline = storage.primeRaftOutline.unionPolygons(storage.raftOutline); - storage.primeRaftOutline.makeConvex(); - } - storage.primeRaftOutline = storage.primeRaftOutline.difference(storage.raftOutline); // In case of overlaps. + // storage.primeRaftOutline = storage.primeTower.outer_poly.offset(distance, ClipperLib::jtRound); + // NOTE: the raft doesn't take the prime tower brim into account, because it's (currently) not being printed when printing a raft + // if (settings.get("raft_remove_inside_corners")) + //{ + // storage.primeRaftOutline = storage.primeRaftOutline.unionPolygons(storage.raftOutline); + // storage.primeRaftOutline.makeConvex(); + // } + // storage.primeRaftOutline = storage.primeRaftOutline.difference(storage.raftOutline); // In case of overlaps. } coord_t Raft::getTotalThickness() { - const Settings& mesh_group_settings =Application::getInstance().current_slice->scene.current_mesh_group->settings; + const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; const ExtruderTrain& base_train = mesh_group_settings.get("raft_base_extruder_nr"); const ExtruderTrain& interface_train = mesh_group_settings.get("raft_interface_extruder_nr"); const ExtruderTrain& surface_train = mesh_group_settings.get("raft_surface_extruder_nr"); return base_train.settings.get("raft_base_thickness") - + interface_train.settings.get("raft_interface_layers") * interface_train.settings.get("raft_interface_thickness") - + surface_train.settings.get("raft_surface_layers") * surface_train.settings.get("raft_surface_thickness"); + + interface_train.settings.get("raft_interface_layers") * interface_train.settings.get("raft_interface_thickness") + + surface_train.settings.get("raft_surface_layers") * surface_train.settings.get("raft_surface_thickness"); } coord_t Raft::getZdiffBetweenRaftAndLayer0() @@ -115,7 +119,7 @@ coord_t Raft::getFillerLayerHeight() size_t Raft::getTotalExtraLayers() { - const Settings& mesh_group_settings =Application::getInstance().current_slice->scene.current_mesh_group->settings; + const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; const ExtruderTrain& base_train = mesh_group_settings.get("raft_base_extruder_nr"); const ExtruderTrain& interface_train = mesh_group_settings.get("raft_interface_extruder_nr"); const ExtruderTrain& surface_train = mesh_group_settings.get("raft_surface_extruder_nr"); @@ -127,4 +131,4 @@ size_t Raft::getTotalExtraLayers() } -}//namespace cura +} // namespace cura From f0e4ababa60dc5c78303c382460d1e56a0a04f7a Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 21 Sep 2023 17:00:40 +0200 Subject: [PATCH 005/116] Add brim on prime tower without raft CURA-10993 --- src/PrimeTower.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index b731011398..d6ff7a3fcd 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -155,11 +155,16 @@ void PrimeTower::generatePaths_denseInfill() // Generate a concentric infill pattern in the form insets for the prime tower's first layer instead of using // the infill pattern because the infill pattern tries to connect polygons in different insets which causes the // first layer of the prime tower to not stick well. - Polygons inset = outer_poly.offset(-cumulative_inset - line_width_layer0 / 2); - while (! inset.empty()) + Polygons inset = outer_poly.offset(-(-cumulative_inset - line_width_layer0 / 2)); + /*while (! inset.empty()) { pattern_layer0.polygons.add(inset); inset = inset.offset(-line_width_layer0); + }*/ + for (int i = 0; i < 15; ++i) + { + pattern_layer0.polygons.add(inset); + inset = inset.offset(line_width_layer0); } } cumulative_inset += wall_nr * line_width; @@ -225,14 +230,18 @@ void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_la void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t extruder_nr) const { - const ExtrusionMoves& pattern - //= (gcode_layer.getLayerNr() == -static_cast(Raft::getFillerLayerCount())) ? pattern_per_extruder_layer0[extruder_nr] : pattern_per_extruder[extruder_nr]; - = (gcode_layer.getLayerNr() == -static_cast(Raft::getTotalExtraLayers())) ? pattern_per_extruder_layer0[extruder_nr] : pattern_per_extruder[extruder_nr]; - const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; + const ExtrusionMoves& pattern = pattern_per_extruder[extruder_nr]; gcode_layer.addPolygonsByOptimizer(pattern.polygons, config); gcode_layer.addLinesByOptimizer(pattern.lines, config, SpaceFillType::Lines); + + if (gcode_layer.getLayerNr() == -static_cast(Raft::getTotalExtraLayers())) + { + const ExtrusionMoves& pattern0 = pattern_per_extruder_layer0[extruder_nr]; + gcode_layer.addPolygonsByOptimizer(pattern0.polygons, config); + gcode_layer.addLinesByOptimizer(pattern0.lines, config, SpaceFillType::Lines); + } } void PrimeTower::subtractFromSupport(SliceDataStorage& storage) From 22824f9d44fdea70471b0f64c4a3b95dd06b5d83 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 22 Sep 2023 09:23:23 +0200 Subject: [PATCH 006/116] Fixed missing prime tower hull on some layers CURA-10993 --- src/FffGcodeWriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 0bc8b7a809..520a8b42d2 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1346,7 +1346,7 @@ std::vector FffGcodeWriter::getUsedExtrudersOnLayerExcludingStartingExtr std::vector extruder_is_used_on_this_layer = storage.getExtrudersUsed(layer_nr); // The outermost prime tower extruder is always used if there is a prime tower, apart on layers with negative index (e.g. for the raft) - if (mesh_group_settings.get("prime_tower_enable") && layer_nr >= 0 && layer_nr <= storage.max_print_height_second_to_last_extruder) + if (mesh_group_settings.get("prime_tower_enable") && /*layer_nr >= 0 &&*/ layer_nr <= storage.max_print_height_second_to_last_extruder) { extruder_is_used_on_this_layer[storage.primeTower.extruder_order[0]] = true; } From cc01931e836a7d00ae2c6032d5d2e904af35fa8b Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 22 Sep 2023 10:28:53 +0200 Subject: [PATCH 007/116] Higher brim for primer tower to make it stronger CURA-10993 --- src/PrimeTower.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index d6ff7a3fcd..316be75b3a 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -236,7 +236,8 @@ void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t ext gcode_layer.addPolygonsByOptimizer(pattern.polygons, config); gcode_layer.addLinesByOptimizer(pattern.lines, config, SpaceFillType::Lines); - if (gcode_layer.getLayerNr() == -static_cast(Raft::getTotalExtraLayers())) + // if (gcode_layer.getLayerNr() == -static_cast(Raft::getTotalExtraLayers())) + if (gcode_layer.getLayerNr() < 0 && extruder_nr == 0) { const ExtrusionMoves& pattern0 = pattern_per_extruder_layer0[extruder_nr]; gcode_layer.addPolygonsByOptimizer(pattern0.polygons, config); From 16d1a84567072bb7f39b18b2171d7cfea9d0e1c9 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Fri, 22 Sep 2023 14:51:52 +0200 Subject: [PATCH 008/116] 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 009/116] 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 010/116] 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 48e83717de4465e7110003e48697f9d49bf3afc8 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 22 Sep 2023 16:42:38 +0200 Subject: [PATCH 011/116] Print prime tower during raft print CURA-10993 --- src/FffGcodeWriter.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 520a8b42d2..5554355ba3 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -143,21 +143,21 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep findLayerSeamsForSpiralize(storage, total_layers); } - int process_layer_starting_layer_nr = 0; + // int process_layer_starting_layer_nr = 0; const bool has_raft = scene.current_mesh_group->settings.get("adhesion_type") == EPlatformAdhesion::RAFT; if (has_raft) { processRaft(storage); // process filler layers to fill the airgap with helper object (support etc) so that they stick better to the raft. // only process the filler layers if there is anything to print in them. - for (bool extruder_is_used_in_filler_layers : storage.getExtrudersUsed(-1)) + /*for (bool extruder_is_used_in_filler_layers : storage.getExtrudersUsed(-1)) { if (extruder_is_used_in_filler_layers) { process_layer_starting_layer_nr = -Raft::getFillerLayerCount(); break; } - } + }*/ } run_multiple_producers_ordered_consumer( @@ -687,6 +687,8 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) layer_plan_buffer.handle(gcode_layer, gcode); last_planned_position = gcode_layer.getLastPlannedPositionOrStartingPosition(); + + setExtruder_addPrime(storage, gcode_layer, 0); } const coord_t interface_layer_height = interface_settings.get("raft_interface_thickness"); @@ -790,6 +792,8 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) layer_plan_buffer.handle(gcode_layer, gcode); last_planned_position = gcode_layer.getLastPlannedPositionOrStartingPosition(); + + setExtruder_addPrime(storage, gcode_layer, 0); } const coord_t surface_layer_height = surface_settings.get("raft_surface_thickness"); @@ -894,6 +898,8 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) } layer_plan_buffer.handle(gcode_layer, gcode); + + setExtruder_addPrime(storage, gcode_layer, 0); } } @@ -1014,7 +1020,7 @@ LayerPlan& FffGcodeWriter::processLayer(const SliceDataStorage& storage, LayerIn // later in the print a prime tower is needed. // - prime tower is already printed this layer (only applicable for more than 2 extruders). // The setExtruder_addPrime takes care of this. - if (extruder_nr != extruder_order.front() || extruder_order.size() == 1) + if (extruder_nr != extruder_order.front() || (extruder_order.size() == 1 && layer_nr >= 0) || extruder_nr == 0) { setExtruder_addPrime(storage, gcode_layer, extruder_nr); } @@ -1045,7 +1051,7 @@ LayerPlan& FffGcodeWriter::processLayer(const SliceDataStorage& storage, LayerIn // Always print a prime tower before switching extruder. Unless: // - The prime tower is already printed this layer (setExtruder_addPrime takes care of this). // - this is the last extruder of the layer, since the next layer will start with the same extruder. - if (extruder_nr != extruder_order.back()) + if (extruder_nr != extruder_order.back() && layer_nr >= 0) { setExtruder_addPrime(storage, gcode_layer, extruder_nr); } From e48316eba6edb6f07022bb5b0d69e04b1ac0dee5 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 25 Sep 2023 10:34:52 +0200 Subject: [PATCH 012/116] Better prime tower raft CURA-10993 --- src/FffGcodeWriter.cpp | 14 +++++++------- src/PrimeTower.cpp | 30 ++++++++++++++++++++---------- src/gcodeExport.cpp | 2 +- src/raft.cpp | 10 +++++++++- 4 files changed, 37 insertions(+), 19 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 5554355ba3..8f7d993811 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -143,28 +143,28 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep findLayerSeamsForSpiralize(storage, total_layers); } - // int process_layer_starting_layer_nr = 0; + int process_layer_starting_layer_nr = 0; const bool has_raft = scene.current_mesh_group->settings.get("adhesion_type") == EPlatformAdhesion::RAFT; if (has_raft) { processRaft(storage); // process filler layers to fill the airgap with helper object (support etc) so that they stick better to the raft. // only process the filler layers if there is anything to print in them. - /*for (bool extruder_is_used_in_filler_layers : storage.getExtrudersUsed(-1)) + for (bool extruder_is_used_in_filler_layers : storage.getExtrudersUsed(-1)) { if (extruder_is_used_in_filler_layers) { process_layer_starting_layer_nr = -Raft::getFillerLayerCount(); break; } - }*/ + } } run_multiple_producers_ordered_consumer( - // process_layer_starting_layer_nr, - -Raft::getTotalExtraLayers(), - // total_layers + Raft::getFillerLayerCount() - 1, - total_layers, + process_layer_starting_layer_nr, + //-Raft::getTotalExtraLayers(), + total_layers + Raft::getFillerLayerCount() - 1, + // total_layers, [&storage, total_layers, this](int layer_nr) { return &processLayer(storage, layer_nr, total_layers); diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 316be75b3a..9845eff054 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -149,22 +149,24 @@ void PrimeTower::generatePaths_denseInfill() else { // Generate the pattern for the first layer. - coord_t line_width_layer0 = line_width * scene.extruders[extruder_nr].settings.get("initial_layer_line_width_factor"); + const coord_t line_width_layer0 = scene.extruders[extruder_nr].settings.get("raft_base_line_width"); ExtrusionMoves& pattern_layer0 = pattern_per_extruder_layer0[extruder_nr]; // Generate a concentric infill pattern in the form insets for the prime tower's first layer instead of using // the infill pattern because the infill pattern tries to connect polygons in different insets which causes the // first layer of the prime tower to not stick well. - Polygons inset = outer_poly.offset(-(-cumulative_inset - line_width_layer0 / 2)); - /*while (! inset.empty()) + Polygons inset = outer_poly.offset(-cumulative_inset - line_width_layer0 / 2); + while (! inset.empty()) { pattern_layer0.polygons.add(inset); inset = inset.offset(-line_width_layer0); - }*/ + } + + Polygons outset = outer_poly.offset(cumulative_inset + line_width_layer0 / 2); for (int i = 0; i < 15; ++i) { - pattern_layer0.polygons.add(inset); - inset = inset.offset(line_width_layer0); + pattern_layer0.polygons.add(outset); + outset = outset.offset(line_width_layer0); } } cumulative_inset += wall_nr * line_width; @@ -230,19 +232,27 @@ void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_la void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t extruder_nr) const { - const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; + const GCodePathConfig& config + = gcode_layer.getLayerNr() < 0 ? gcode_layer.configs_storage.raft_base_config : gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; - const ExtrusionMoves& pattern = pattern_per_extruder[extruder_nr]; - gcode_layer.addPolygonsByOptimizer(pattern.polygons, config); - gcode_layer.addLinesByOptimizer(pattern.lines, config, SpaceFillType::Lines); // if (gcode_layer.getLayerNr() == -static_cast(Raft::getTotalExtraLayers())) if (gcode_layer.getLayerNr() < 0 && extruder_nr == 0) { + const GCodePathConfig& config = gcode_layer.configs_storage.raft_base_config; + const ExtrusionMoves& pattern0 = pattern_per_extruder_layer0[extruder_nr]; gcode_layer.addPolygonsByOptimizer(pattern0.polygons, config); gcode_layer.addLinesByOptimizer(pattern0.lines, config, SpaceFillType::Lines); } + else + { + const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; + + const ExtrusionMoves& pattern = pattern_per_extruder[extruder_nr]; + gcode_layer.addPolygonsByOptimizer(pattern.polygons, config); + gcode_layer.addLinesByOptimizer(pattern.lines, config, SpaceFillType::Lines); + } } void PrimeTower::subtractFromSupport(SliceDataStorage& storage) diff --git a/src/gcodeExport.cpp b/src/gcodeExport.cpp index caff200811..799ac84e0c 100644 --- a/src/gcodeExport.cpp +++ b/src/gcodeExport.cpp @@ -1498,7 +1498,7 @@ void GCodeExport::writeTemperatureCommand(const size_t extruder, const Temperatu *output_stream << " T" << extruder; } #ifdef ASSERT_INSANE_OUTPUT - assert(temperature >= 0); + // assert(temperature >= 0); #endif // ASSERT_INSANE_OUTPUT *output_stream << " S" << PrecisionedDouble{ 1, temperature } << new_line; if (extruder != current_extruder && always_write_active_tool) diff --git a/src/raft.cpp b/src/raft.cpp index 16134f55bc..384958afc4 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -113,7 +113,15 @@ coord_t Raft::getFillerLayerHeight() const coord_t normal_layer_height = mesh_group_settings.get("layer_height"); return normal_layer_height; } - return round_divide(getZdiffBetweenRaftAndLayer0(), getFillerLayerCount()); + + if (getFillerLayerCount() != 0) + { + return round_divide(getZdiffBetweenRaftAndLayer0(), getFillerLayerCount()); + } + else + { + return mesh_group_settings.get("layer_height"); + } } From 9bcfe21624ebe5ac0f3c4f6e9460bade96a0ba69 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 25 Sep 2023 13:49:16 +0200 Subject: [PATCH 013/116] Better prime tower raft and fixed supports into raft CURA-10993 --- include/PrimeTower.h | 1 + src/FffGcodeWriter.cpp | 4 +-- src/PrimeTower.cpp | 79 +++++++++++++++++++++++++++++++++++++----- src/gcodeExport.cpp | 2 +- 4 files changed, 74 insertions(+), 12 deletions(-) diff --git a/include/PrimeTower.h b/include/PrimeTower.h index c0e50685bf..c2909295d8 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -41,6 +41,7 @@ class PrimeTower std::vector pattern_per_extruder; //!< For each extruder the pattern to print on all layers of the prime tower. std::vector pattern_per_extruder_layer0; //!< For each extruder the pattern to print on the first layer + std::vector pattern_per_extruder_layer_raft; //!< For each extruder the pattern to print on the raft layers public: bool enabled; //!< Whether the prime tower is enabled. diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 8f7d993811..bd29bcef24 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -163,8 +163,8 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep run_multiple_producers_ordered_consumer( process_layer_starting_layer_nr, //-Raft::getTotalExtraLayers(), - total_layers + Raft::getFillerLayerCount() - 1, - // total_layers, + // total_layers + Raft::getFillerLayerCount() - 1, + total_layers, [&storage, total_layers, this](int layer_nr) { return &processLayer(storage, layer_nr, total_layers); diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 9845eff054..b0bf9e853e 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -117,6 +117,7 @@ void PrimeTower::generatePaths_denseInfill() const coord_t layer_height = mesh_group_settings.get("layer_height"); pattern_per_extruder.resize(extruder_count); pattern_per_extruder_layer0.resize(extruder_count); + pattern_per_extruder_layer_raft.resize(extruder_count); coord_t cumulative_inset = 0; // Each tower shape is going to be printed inside the other. This is the inset we're doing for each extruder. for (size_t extruder_nr : extruder_order) @@ -150,7 +151,7 @@ void PrimeTower::generatePaths_denseInfill() { // Generate the pattern for the first layer. const coord_t line_width_layer0 = scene.extruders[extruder_nr].settings.get("raft_base_line_width"); - ExtrusionMoves& pattern_layer0 = pattern_per_extruder_layer0[extruder_nr]; + ExtrusionMoves& pattern_layer_raft = pattern_per_extruder_layer_raft[extruder_nr]; // Generate a concentric infill pattern in the form insets for the prime tower's first layer instead of using // the infill pattern because the infill pattern tries to connect polygons in different insets which causes the @@ -158,16 +159,29 @@ void PrimeTower::generatePaths_denseInfill() Polygons inset = outer_poly.offset(-cumulative_inset - line_width_layer0 / 2); while (! inset.empty()) { - pattern_layer0.polygons.add(inset); + pattern_layer_raft.polygons.add(inset); inset = inset.offset(-line_width_layer0); } Polygons outset = outer_poly.offset(cumulative_inset + line_width_layer0 / 2); for (int i = 0; i < 15; ++i) { - pattern_layer0.polygons.add(outset); + pattern_layer_raft.polygons.add(outset); outset = outset.offset(line_width_layer0); } + + // Generate the pattern for the raft layers + ExtrusionMoves& pattern_layer0 = pattern_per_extruder_layer0[extruder_nr]; + + // Generate a concentric infill pattern in the form insets for the prime tower's first layer instead of using + // the infill pattern because the infill pattern tries to connect polygons in different insets which causes the + // first layer of the prime tower to not stick well. + outset = outer_poly.offset(cumulative_inset + line_width / 2); + for (int i = 0; i < 15; ++i) + { + pattern_layer0.polygons.add(outset); + outset = outset.offset(line_width); + } } cumulative_inset += wall_nr * line_width; } @@ -235,24 +249,71 @@ void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t ext const GCodePathConfig& config = gcode_layer.getLayerNr() < 0 ? gcode_layer.configs_storage.raft_base_config : gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; - - // if (gcode_layer.getLayerNr() == -static_cast(Raft::getTotalExtraLayers())) - if (gcode_layer.getLayerNr() < 0 && extruder_nr == 0) + if (gcode_layer.getLayerNr() == -Raft::getTotalExtraLayers() && extruder_nr == 0) { + // Specific case for first layer => very high adhesion const GCodePathConfig& config = gcode_layer.configs_storage.raft_base_config; - const ExtrusionMoves& pattern0 = pattern_per_extruder_layer0[extruder_nr]; - gcode_layer.addPolygonsByOptimizer(pattern0.polygons, config); - gcode_layer.addLinesByOptimizer(pattern0.lines, config, SpaceFillType::Lines); + const ExtrusionMoves& pattern_raft = pattern_per_extruder_layer_raft[extruder_nr]; + gcode_layer.addPolygonsByOptimizer(pattern_raft.polygons, config); + gcode_layer.addLinesByOptimizer(pattern_raft.lines, config, SpaceFillType::Lines); } else { const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; + // Actual prime pattern + const ExtrusionMoves& pattern = pattern_per_extruder[extruder_nr]; + gcode_layer.addPolygonsByOptimizer(pattern.polygons, config); + gcode_layer.addLinesByOptimizer(pattern.lines, config, SpaceFillType::Lines); + + if (gcode_layer.getLayerNr() < 0 && extruder_nr == 0) + { + const ExtrusionMoves& pattern0 = pattern_per_extruder_layer0[extruder_nr]; + gcode_layer.addPolygonsByOptimizer(pattern0.polygons, config); + gcode_layer.addLinesByOptimizer(pattern0.lines, config, SpaceFillType::Lines); + } + } + + /* + if (gcode_layer.getLayerNr() > -static_cast(Raft::getTotalExtraLayers())) + { + const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; + + // Actual prime pattern const ExtrusionMoves& pattern = pattern_per_extruder[extruder_nr]; gcode_layer.addPolygonsByOptimizer(pattern.polygons, config); gcode_layer.addLinesByOptimizer(pattern.lines, config, SpaceFillType::Lines); + + if (gcode_layer.getLayerNr() < 0 && extruder_nr == 0) + { + const ExtrusionMoves& pattern0 = pattern_per_extruder_layer0[extruder_nr]; + gcode_layer.addPolygonsByOptimizer(pattern0.polygons, config); + gcode_layer.addLinesByOptimizer(pattern0.lines, config, SpaceFillType::Lines); + } } +*/ + + // if (gcode_layer.getLayerNr() == -static_cast(Raft::getTotalExtraLayers())) + /*if (gcode_layer.getLayerNr() < 0 && extruder_nr == 0) + { + if (gcode_layer.getLayerNr() == -Raft::getTotalExtraLayers()) + { + const GCodePathConfig& config = gcode_layer.configs_storage.raft_base_config; + + const ExtrusionMoves& pattern0 = pattern_per_extruder_layer0[extruder_nr]; + gcode_layer.addPolygonsByOptimizer(pattern0.polygons, config); + gcode_layer.addLinesByOptimizer(pattern0.lines, config, SpaceFillType::Lines); + } + else + { + const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; + + const ExtrusionMoves& pattern_raft = pattern_per_extruder_layer_raft[extruder_nr]; + gcode_layer.addPolygonsByOptimizer(pattern_raft.polygons, config); + gcode_layer.addLinesByOptimizer(pattern_raft.lines, config, SpaceFillType::Lines); + } + }*/ } void PrimeTower::subtractFromSupport(SliceDataStorage& storage) diff --git a/src/gcodeExport.cpp b/src/gcodeExport.cpp index 799ac84e0c..caff200811 100644 --- a/src/gcodeExport.cpp +++ b/src/gcodeExport.cpp @@ -1498,7 +1498,7 @@ void GCodeExport::writeTemperatureCommand(const size_t extruder, const Temperatu *output_stream << " T" << extruder; } #ifdef ASSERT_INSANE_OUTPUT - // assert(temperature >= 0); + assert(temperature >= 0); #endif // ASSERT_INSANE_OUTPUT *output_stream << " S" << PrecisionedDouble{ 1, temperature } << new_line; if (extruder != current_extruder && always_write_active_tool) From 1038eda887fa9b5b3b0158bdd104b61b53e944d7 Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Mon, 25 Sep 2023 11:49:57 +0000 Subject: [PATCH 014/116] Applied clang-format. --- include/PrimeTower.h | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/include/PrimeTower.h b/include/PrimeTower.h index c2909295d8..4bca473177 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -1,15 +1,15 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef PRIME_TOWER_H #define PRIME_TOWER_H -#include - #include "utils/polygon.h" // Polygons #include "utils/polygonUtils.h" -namespace cura +#include + +namespace cura { class SliceDataStorage; @@ -73,7 +73,7 @@ class PrimeTower /*! * Generate the prime tower area to be used on each layer - * + * * Fills \ref PrimeTower::inner_poly and sets \ref PrimeTower::middle */ void generateGroundpoly(); @@ -85,7 +85,7 @@ class PrimeTower /*! * Add path plans for the prime tower to the \p gcode_layer - * + * * \param storage where to get settings from; where to get the maximum height of the prime tower from * \param[in,out] gcode_layer Where to get the current extruder from; where to store the generated layer paths * \param prev_extruder The previous extruder with which paths were planned; from which extruder a switch was made @@ -102,10 +102,9 @@ class PrimeTower void subtractFromSupport(SliceDataStorage& storage); private: - /*! * \see WipeTower::generatePaths - * + * * Generate the extrude paths for each extruder on even and odd layers * Fill the ground poly with dense infill. */ @@ -139,8 +138,6 @@ class PrimeTower }; - - -}//namespace cura +} // namespace cura #endif // PRIME_TOWER_H From 43955a199c60077b74012d9a47297c694e5c2d91 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Mon, 25 Sep 2023 13:53:00 +0200 Subject: [PATCH 015/116] 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 235f6f587e..0721bd7628 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 26c7522af035fc5e629f72b398be78f8541f0a1f Mon Sep 17 00:00:00 2001 From: saumyaj3 Date: Mon, 25 Sep 2023 11:53:42 +0000 Subject: [PATCH 016/116] 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 0721bd7628..ef5d748533 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 e2203b07fd02668c1c7010c596ef84f6ff766b69 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Mon, 25 Sep 2023 13:55:28 +0200 Subject: [PATCH 017/116] 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 ef5d748533..68591de295 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 ec98763e4218ba9fd991d8396e1d4565d6116913 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 25 Sep 2023 16:45:49 +0200 Subject: [PATCH 018/116] Fix bad temperature crash CURA-10993 --- src/FffGcodeWriter.cpp | 12 ++++++------ src/PrimeTower.cpp | 40 ---------------------------------------- 2 files changed, 6 insertions(+), 46 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index bd29bcef24..7d96e81eb6 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -685,10 +685,10 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) raftLines.clear(); } + setExtruder_addPrime(storage, gcode_layer, 0); + layer_plan_buffer.handle(gcode_layer, gcode); last_planned_position = gcode_layer.getLastPlannedPositionOrStartingPosition(); - - setExtruder_addPrime(storage, gcode_layer, 0); } const coord_t interface_layer_height = interface_settings.get("raft_interface_thickness"); @@ -790,10 +790,10 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) raft_lines.clear(); } + setExtruder_addPrime(storage, gcode_layer, 0); + layer_plan_buffer.handle(gcode_layer, gcode); last_planned_position = gcode_layer.getLastPlannedPositionOrStartingPosition(); - - setExtruder_addPrime(storage, gcode_layer, 0); } const coord_t surface_layer_height = surface_settings.get("raft_surface_thickness"); @@ -897,9 +897,9 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) raft_lines.clear(); } - layer_plan_buffer.handle(gcode_layer, gcode); - setExtruder_addPrime(storage, gcode_layer, 0); + + layer_plan_buffer.handle(gcode_layer, gcode); } } diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index b0bf9e853e..3818d8e3f8 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -274,46 +274,6 @@ void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t ext gcode_layer.addLinesByOptimizer(pattern0.lines, config, SpaceFillType::Lines); } } - - /* - if (gcode_layer.getLayerNr() > -static_cast(Raft::getTotalExtraLayers())) - { - const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; - - // Actual prime pattern - const ExtrusionMoves& pattern = pattern_per_extruder[extruder_nr]; - gcode_layer.addPolygonsByOptimizer(pattern.polygons, config); - gcode_layer.addLinesByOptimizer(pattern.lines, config, SpaceFillType::Lines); - - if (gcode_layer.getLayerNr() < 0 && extruder_nr == 0) - { - const ExtrusionMoves& pattern0 = pattern_per_extruder_layer0[extruder_nr]; - gcode_layer.addPolygonsByOptimizer(pattern0.polygons, config); - gcode_layer.addLinesByOptimizer(pattern0.lines, config, SpaceFillType::Lines); - } - } -*/ - - // if (gcode_layer.getLayerNr() == -static_cast(Raft::getTotalExtraLayers())) - /*if (gcode_layer.getLayerNr() < 0 && extruder_nr == 0) - { - if (gcode_layer.getLayerNr() == -Raft::getTotalExtraLayers()) - { - const GCodePathConfig& config = gcode_layer.configs_storage.raft_base_config; - - const ExtrusionMoves& pattern0 = pattern_per_extruder_layer0[extruder_nr]; - gcode_layer.addPolygonsByOptimizer(pattern0.polygons, config); - gcode_layer.addLinesByOptimizer(pattern0.lines, config, SpaceFillType::Lines); - } - else - { - const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; - - const ExtrusionMoves& pattern_raft = pattern_per_extruder_layer_raft[extruder_nr]; - gcode_layer.addPolygonsByOptimizer(pattern_raft.polygons, config); - gcode_layer.addLinesByOptimizer(pattern_raft.lines, config, SpaceFillType::Lines); - } - }*/ } void PrimeTower::subtractFromSupport(SliceDataStorage& storage) From b996cd013d083fb6ca3b19a8ad5ea0952e2fe0be Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 26 Sep 2023 21:15:38 +0200 Subject: [PATCH 019/116] 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 020/116] 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 e9f015de3a91ddcdeefe9dacfd49495724134356 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 27 Sep 2023 15:36:29 +0200 Subject: [PATCH 021/116] Added a foot to prime tower to make it stronger CURA-10993 --- include/PrimeTower.h | 5 +- src/FffGcodeWriter.cpp | 6 +-- src/PrimeTower.cpp | 109 +++++++++++++++++++++-------------------- 3 files changed, 61 insertions(+), 59 deletions(-) diff --git a/include/PrimeTower.h b/include/PrimeTower.h index 4bca473177..5bb8192a82 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -40,8 +40,7 @@ class PrimeTower const unsigned int number_of_prime_tower_start_locations = 21; //!< The required size of \ref PrimeTower::wipe_locations std::vector pattern_per_extruder; //!< For each extruder the pattern to print on all layers of the prime tower. - std::vector pattern_per_extruder_layer0; //!< For each extruder the pattern to print on the first layer - std::vector pattern_per_extruder_layer_raft; //!< For each extruder the pattern to print on the raft layers + std::vector pattern_extra_brim_per_layer; //!< For each layer with an extra brim, the pattern to be added public: bool enabled; //!< Whether the prime tower is enabled. @@ -102,6 +101,8 @@ class PrimeTower void subtractFromSupport(SliceDataStorage& storage); private: + ExtrusionMoves generatePaths_extraBrim(const Polygons &outer_poly, coord_t extra_radius, coord_t line_width, bool add_inset); + /*! * \see WipeTower::generatePaths * diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 7d96e81eb6..7585677793 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -685,7 +685,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) raftLines.clear(); } - setExtruder_addPrime(storage, gcode_layer, 0); + setExtruder_addPrime(storage, gcode_layer, storage.primeTower.extruder_order.front()); layer_plan_buffer.handle(gcode_layer, gcode); last_planned_position = gcode_layer.getLastPlannedPositionOrStartingPosition(); @@ -790,7 +790,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) raft_lines.clear(); } - setExtruder_addPrime(storage, gcode_layer, 0); + setExtruder_addPrime(storage, gcode_layer, storage.primeTower.extruder_order.front()); layer_plan_buffer.handle(gcode_layer, gcode); last_planned_position = gcode_layer.getLastPlannedPositionOrStartingPosition(); @@ -897,7 +897,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) raft_lines.clear(); } - setExtruder_addPrime(storage, gcode_layer, 0); + setExtruder_addPrime(storage, gcode_layer, storage.primeTower.extruder_order.front()); layer_plan_buffer.handle(gcode_layer, gcode); } diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 3818d8e3f8..472edc4054 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -110,14 +110,45 @@ void PrimeTower::generatePaths(const SliceDataStorage& storage) } } +PrimeTower::ExtrusionMoves PrimeTower::generatePaths_extraBrim(const Polygons& outer_poly, coord_t extra_radius, coord_t line_width, bool add_inset) +{ + const Scene& scene = Application::getInstance().current_slice->scene; + const Settings& mesh_group_settings = scene.current_mesh_group->settings; + const coord_t tower_size = mesh_group_settings.get("prime_tower_size"); + + ExtrusionMoves pattern; + + if (add_inset) + { + Polygons inset = outer_poly.offset(-line_width / 2); + while (! inset.empty()) + { + pattern.polygons.add(inset); + inset = inset.offset(-line_width); + } + } + + int circles = 0; + Polygons outset = outer_poly.offset(line_width / 2); + while (outset.max() - outset.min() < (tower_size + extra_radius * 2)) + { + pattern.polygons.add(outset); + outset = outset.offset(line_width); + circles++; + } + + return pattern; +} + void PrimeTower::generatePaths_denseInfill() { + constexpr coord_t brim_extra_radius = 20000; + constexpr coord_t brim_extra_height = 20000; + const Scene& scene = Application::getInstance().current_slice->scene; const Settings& mesh_group_settings = scene.current_mesh_group->settings; const coord_t layer_height = mesh_group_settings.get("layer_height"); pattern_per_extruder.resize(extruder_count); - pattern_per_extruder_layer0.resize(extruder_count); - pattern_per_extruder_layer_raft.resize(extruder_count); coord_t cumulative_inset = 0; // Each tower shape is going to be printed inside the other. This is the inset we're doing for each extruder. for (size_t extruder_nr : extruder_order) @@ -143,44 +174,19 @@ void PrimeTower::generatePaths_denseInfill() } // Only the most inside extruder needs to fill the inside of the prime tower - if (false /*extruder_nr != extruder_order.back()*/) - { - pattern_per_extruder_layer0 = pattern_per_extruder; - } - else + if (extruder_nr == extruder_order.front()) { // Generate the pattern for the first layer. const coord_t line_width_layer0 = scene.extruders[extruder_nr].settings.get("raft_base_line_width"); - ExtrusionMoves& pattern_layer_raft = pattern_per_extruder_layer_raft[extruder_nr]; - - // Generate a concentric infill pattern in the form insets for the prime tower's first layer instead of using - // the infill pattern because the infill pattern tries to connect polygons in different insets which causes the - // first layer of the prime tower to not stick well. - Polygons inset = outer_poly.offset(-cumulative_inset - line_width_layer0 / 2); - while (! inset.empty()) - { - pattern_layer_raft.polygons.add(inset); - inset = inset.offset(-line_width_layer0); - } - - Polygons outset = outer_poly.offset(cumulative_inset + line_width_layer0 / 2); - for (int i = 0; i < 15; ++i) - { - pattern_layer_raft.polygons.add(outset); - outset = outset.offset(line_width_layer0); - } + ExtrusionMoves pattern_layer0 = generatePaths_extraBrim(outer_poly, brim_extra_radius, line_width_layer0, true); + pattern_extra_brim_per_layer.push_back(pattern_layer0); - // Generate the pattern for the raft layers - ExtrusionMoves& pattern_layer0 = pattern_per_extruder_layer0[extruder_nr]; - - // Generate a concentric infill pattern in the form insets for the prime tower's first layer instead of using - // the infill pattern because the infill pattern tries to connect polygons in different insets which causes the - // first layer of the prime tower to not stick well. - outset = outer_poly.offset(cumulative_inset + line_width / 2); - for (int i = 0; i < 15; ++i) + for (coord_t z = layer_height; z < brim_extra_height; z += layer_height) { - pattern_layer0.polygons.add(outset); - outset = outset.offset(line_width); + double brim_radius_factor = std::pow((1.0 - static_cast(z) / brim_extra_height), 4); + coord_t extra_radius = brim_extra_radius * brim_radius_factor; + ExtrusionMoves pattern = generatePaths_extraBrim(outer_poly, extra_radius, line_width, false); + pattern_extra_brim_per_layer.push_back(pattern); } } cumulative_inset += wall_nr * line_width; @@ -246,33 +252,28 @@ void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_la void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t extruder_nr) const { - const GCodePathConfig& config - = gcode_layer.getLayerNr() < 0 ? gcode_layer.configs_storage.raft_base_config : gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; + LayerIndex absolute_layer_number = gcode_layer.getLayerNr() + Raft::getTotalExtraLayers(); + assert(absolute_layer_number >= 0); - if (gcode_layer.getLayerNr() == -Raft::getTotalExtraLayers() && extruder_nr == 0) - { - // Specific case for first layer => very high adhesion - const GCodePathConfig& config = gcode_layer.configs_storage.raft_base_config; - - const ExtrusionMoves& pattern_raft = pattern_per_extruder_layer_raft[extruder_nr]; - gcode_layer.addPolygonsByOptimizer(pattern_raft.polygons, config); - gcode_layer.addLinesByOptimizer(pattern_raft.lines, config, SpaceFillType::Lines); - } - else + if (absolute_layer_number > 0) { + // Actual prime pattern const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; - // Actual prime pattern const ExtrusionMoves& pattern = pattern_per_extruder[extruder_nr]; gcode_layer.addPolygonsByOptimizer(pattern.polygons, config); gcode_layer.addLinesByOptimizer(pattern.lines, config, SpaceFillType::Lines); + } - if (gcode_layer.getLayerNr() < 0 && extruder_nr == 0) - { - const ExtrusionMoves& pattern0 = pattern_per_extruder_layer0[extruder_nr]; - gcode_layer.addPolygonsByOptimizer(pattern0.polygons, config); - gcode_layer.addLinesByOptimizer(pattern0.lines, config, SpaceFillType::Lines); - } + if (absolute_layer_number < pattern_extra_brim_per_layer.size() && extruder_nr == extruder_order.front()) + { + // Specific case for first layer => very high adhesion + const GCodePathConfig& config + = absolute_layer_number == 0 ? gcode_layer.configs_storage.raft_base_config : gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; + + const ExtrusionMoves& pattern = pattern_extra_brim_per_layer[absolute_layer_number]; + gcode_layer.addPolygonsByOptimizer(pattern.polygons, config); + gcode_layer.addLinesByOptimizer(pattern.lines, config, SpaceFillType::Lines); } } From f832ec814da6d7d0e817460f65b4bfa74d13f5bb Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Fri, 29 Sep 2023 11:32:03 +0200 Subject: [PATCH 022/116] 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 68591de295..9a404fa292 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 f063b5ab7df6747b7c3092beec8ea90d042aa05b Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 3 Oct 2023 12:24:18 +0200 Subject: [PATCH 023/116] 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 235f6f587e..2af62a6824 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 873800b9a36cb736a5c21acfbbc1e436c9bbab87 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 3 Oct 2023 19:39:58 +0200 Subject: [PATCH 024/116] 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 235f6f587e..fd80cd7d04 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -2833,10 +2833,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 a70793c1a98825020a66d3d72176ad5412cf5868 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 5 Oct 2023 09:54:12 +0200 Subject: [PATCH 025/116] 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 3bce9f8c2eb62b581cd18aa9c9a273616a3af439 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 5 Oct 2023 11:48:49 +0200 Subject: [PATCH 026/116] 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 3787b2c73369052182ea2b359f372f38f5dc5fe5 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 5 Oct 2023 12:45:17 +0200 Subject: [PATCH 027/116] 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 fe5ebfcc08..5cde325a69 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 08dd09abf6ef354c5581fc68be8c2943ce3e06bd Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Thu, 5 Oct 2023 10:47:34 +0000 Subject: [PATCH 028/116] 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 5cde325a69..1c592da8ad 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 d24323d14ba1ed4f8d90e17cf35956ca8a575b48 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Thu, 5 Oct 2023 15:17:34 +0200 Subject: [PATCH 029/116] 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 fe5ebfcc08..300ea26147 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3050,7 +3050,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 65ad30f6630b5d65e4e4905dae5c96eee57ac79b Mon Sep 17 00:00:00 2001 From: saumyaj3 Date: Thu, 5 Oct 2023 13:18:20 +0000 Subject: [PATCH 030/116] 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 54389a88290b86aacc9c162ca1e3339f6a0edd1a Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 5 Oct 2023 17:18:08 +0200 Subject: [PATCH 031/116] 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 fe5ebfcc08..07f961484e 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 317dab031139972d9f07b2b6d11b9a2252c5409e Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Thu, 5 Oct 2023 15:18:51 +0000 Subject: [PATCH 032/116] 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 9dbcdf80ea06fbdee18769fce327e4a524170e83 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Fri, 6 Oct 2023 10:54:26 +0200 Subject: [PATCH 033/116] 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 27e3c92f3e786a30db78e37e6a1480d3e4c0f743 Mon Sep 17 00:00:00 2001 From: saumyaj3 Date: Fri, 6 Oct 2023 08:56:34 +0000 Subject: [PATCH 034/116] 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 a383339eae365892aa7d3cf7db3c1ddbdf537cfb Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 6 Oct 2023 13:07:14 +0200 Subject: [PATCH 035/116] 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 6311be84cfdccd3ba9c7815b7a325c86866a65e1 Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Fri, 6 Oct 2023 11:12:44 +0000 Subject: [PATCH 036/116] 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 c562a43aab7fb36007d7cbaa15b1471cfac37576 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 9 Oct 2023 10:38:33 +0200 Subject: [PATCH 037/116] 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 00b71215d5d80f81a9b9ae4b5531beb593e4bd96 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 9 Oct 2023 10:52:13 +0200 Subject: [PATCH 038/116] 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 edd9b398369e06a4b90a6b5de9532febcfc11954 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 9 Oct 2023 15:26:34 +0200 Subject: [PATCH 039/116] 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 0c757cb7aabc8a4cba0948e009d3848dd4d47138 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 9 Oct 2023 15:44:51 +0200 Subject: [PATCH 040/116] 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 47cc9ba3419b519ea29d48b847139b5deb8a3221 Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Mon, 9 Oct 2023 13:45:37 +0000 Subject: [PATCH 041/116] 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 b3ff78c015312b6155cddafa9fb1f62fe037ad9b Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 10 Oct 2023 10:40:09 +0200 Subject: [PATCH 042/116] 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 0503a4c7a2e554bf8f2e9cb3e0e3824df0a54fa8 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 10 Oct 2023 10:40:52 +0200 Subject: [PATCH 043/116] 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 9cf7083257b9f9911ee45b76c7bab22b5e95eb4e Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 10 Oct 2023 10:42:59 +0200 Subject: [PATCH 044/116] 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 ae608cdaf5c6516a10c67c4c4b54416eece04107 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 10 Oct 2023 11:05:34 +0200 Subject: [PATCH 045/116] loosen deps version --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index 2556e86c45..383f5631f9 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 5f3a1f4cfb5c22d370a8a194eb6c0c7cc6a38632 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 10 Oct 2023 17:02:47 +0200 Subject: [PATCH 046/116] Basically working parameterizable prime tower with base CURA-10783 --- include/PrimeTower.h | 7 ++- include/SkirtBrim.h | 9 ---- src/FffGcodeWriter.cpp | 14 ----- src/PrimeTower.cpp | 109 ++++++++++++++++++++++++++------------- src/SkirtBrim.cpp | 49 ++---------------- src/raft.cpp | 16 +++--- src/sliceDataStorage.cpp | 9 +++- 7 files changed, 97 insertions(+), 116 deletions(-) diff --git a/include/PrimeTower.h b/include/PrimeTower.h index 5bb8192a82..fe29030ee2 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -40,13 +40,14 @@ class PrimeTower const unsigned int number_of_prime_tower_start_locations = 21; //!< The required size of \ref PrimeTower::wipe_locations std::vector pattern_per_extruder; //!< For each extruder the pattern to print on all layers of the prime tower. - std::vector pattern_extra_brim_per_layer; //!< For each layer with an extra brim, the pattern to be added + std::vector> pattern_extra_brim_per_layer; //!< For each layer of each extruder with an extra brim, the pattern to be added public: bool enabled; //!< Whether the prime tower is enabled. bool would_have_actual_tower; //!< Whether there is an actual tower. bool multiple_extruders_on_first_layer; //!< Whether multiple extruders are allowed on the first layer of the prime tower (e.g. when a raft is there) Polygons outer_poly; //!< The outline of the outermost prime tower. + Polygons footprint; //!< The outline of the prime tower on layer 0 /* * In which order, from outside to inside, will we be printing the prime @@ -101,7 +102,9 @@ class PrimeTower void subtractFromSupport(SliceDataStorage& storage); private: - ExtrusionMoves generatePaths_extraBrim(const Polygons &outer_poly, coord_t extra_radius, coord_t line_width, bool add_inset); + ExtrusionMoves generatePaths_base(const Polygons &outer_poly, coord_t extra_radius, coord_t line_width); + + ExtrusionMoves generatePaths_inset(const Polygons &outer_poly, coord_t line_width, coord_t initial_inset); /*! * \see WipeTower::generatePaths diff --git a/include/SkirtBrim.h b/include/SkirtBrim.h index aefbd5bdd6..05f10a17e4 100644 --- a/include/SkirtBrim.h +++ b/include/SkirtBrim.h @@ -118,15 +118,6 @@ class SkirtBrim */ std::vector generateBrimOffsetPlan(std::vector& starting_outlines); - /*! - * In case that the models have skirt 'adhesion', but the prime tower has a brim, the covered areas are different. - * - * Since the output of this function will need to be handled differently than the rest of the adhesion lines, have a separate function. - * Specifically, for skirt an additional 'approximate convex hull' is applied to the initial 'covered area', which is detrimental to brim. - * \return An ordered list of offsets of the prime-tower to perform in the order in which they are to be performed. - */ - std::vector generatePrimeTowerBrimForSkirtAdhesionOffsetPlan(); - /*! * Generate the primary skirt/brim of the one skirt_brim_extruder or of all extruders simultaneously. * diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 71ebbdef42..f8dabab971 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -164,8 +164,6 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep run_multiple_producers_ordered_consumer( process_layer_starting_layer_nr, - //-Raft::getTotalExtraLayers(), - // total_layers + Raft::getFillerLayerCount() - 1, total_layers, [&storage, total_layers, this](int layer_nr) { @@ -687,8 +685,6 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) raftLines.clear(); } - setExtruder_addPrime(storage, gcode_layer, storage.primeTower.extruder_order.front()); - layer_plan_buffer.handle(gcode_layer, gcode); last_planned_position = gcode_layer.getLastPlannedPositionOrStartingPosition(); } @@ -735,11 +731,6 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) std::vector raft_outline_paths; const coord_t small_offset = gcode_layer.configs_storage.raft_interface_config.getLineWidth() / 2; // Do this manually because of micron-movement created in corners when insetting a polygon that was offset with round joint type. - if (storage.primeRaftOutline.area() > 0) - { - raft_outline_paths.emplace_back(storage.primeRaftOutline.offset(-small_offset)); - raft_outline_paths.back() = Simplify(interface_settings).polygon(raft_outline_paths.back()); // Remove those micron-movements. - } raft_outline_paths.emplace_back(storage.raftOutline.offset(-small_offset)); raft_outline_paths.back() = Simplify(interface_settings).polygon(raft_outline_paths.back()); // Remove those micron-movements. const coord_t infill_outline_width = gcode_layer.configs_storage.raft_interface_config.getLineWidth(); @@ -841,11 +832,6 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) std::vector raft_outline_paths; const coord_t small_offset = gcode_layer.configs_storage.raft_interface_config.getLineWidth() / 2; // Do this manually because of micron-movement created in corners when insetting a polygon that was offset with round joint type. - if (storage.primeRaftOutline.area() > 0) - { - raft_outline_paths.emplace_back(storage.primeRaftOutline.offset(-small_offset)); - raft_outline_paths.back() = Simplify(interface_settings).polygon(raft_outline_paths.back()); // Remove those micron-movements. - } raft_outline_paths.emplace_back(storage.raftOutline.offset(-small_offset)); raft_outline_paths.back() = Simplify(interface_settings).polygon(raft_outline_paths.back()); // Remove those micron-movements. const coord_t infill_outline_width = gcode_layer.configs_storage.raft_interface_config.getLineWidth(); diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 472edc4054..49de8b3db1 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -97,6 +97,18 @@ void PrimeTower::generateGroundpoly() middle = Point(x - tower_size / 2, y + tower_size / 2); post_wipe_point = Point(x - tower_size / 2, y + tower_size / 2); + + const bool base_enabled = mesh_group_settings.get("prime_tower_brim_enable"); + const coord_t base_extra_radius = mesh_group_settings.get("prime_tower_base_size"); + const coord_t base_height = mesh_group_settings.get("prime_tower_base_height"); + if (base_enabled && base_extra_radius > 0 && base_height > 0) + { + footprint = outer_poly.offset(base_extra_radius); + } + else + { + footprint = outer_poly; + } } void PrimeTower::generatePaths(const SliceDataStorage& storage) @@ -110,7 +122,7 @@ void PrimeTower::generatePaths(const SliceDataStorage& storage) } } -PrimeTower::ExtrusionMoves PrimeTower::generatePaths_extraBrim(const Polygons& outer_poly, coord_t extra_radius, coord_t line_width, bool add_inset) +PrimeTower::ExtrusionMoves PrimeTower::generatePaths_base(const Polygons& outer_poly, coord_t extra_radius, coord_t line_width) { const Scene& scene = Application::getInstance().current_slice->scene; const Settings& mesh_group_settings = scene.current_mesh_group->settings; @@ -118,16 +130,6 @@ PrimeTower::ExtrusionMoves PrimeTower::generatePaths_extraBrim(const Polygons& o ExtrusionMoves pattern; - if (add_inset) - { - Polygons inset = outer_poly.offset(-line_width / 2); - while (! inset.empty()) - { - pattern.polygons.add(inset); - inset = inset.offset(-line_width); - } - } - int circles = 0; Polygons outset = outer_poly.offset(line_width / 2); while (outset.max() - outset.min() < (tower_size + extra_radius * 2)) @@ -140,15 +142,34 @@ PrimeTower::ExtrusionMoves PrimeTower::generatePaths_extraBrim(const Polygons& o return pattern; } -void PrimeTower::generatePaths_denseInfill() +PrimeTower::ExtrusionMoves PrimeTower::generatePaths_inset(const Polygons& outer_poly, coord_t line_width, coord_t initial_inset) { - constexpr coord_t brim_extra_radius = 20000; - constexpr coord_t brim_extra_height = 20000; + const Scene& scene = Application::getInstance().current_slice->scene; + const Settings& mesh_group_settings = scene.current_mesh_group->settings; + + ExtrusionMoves pattern; + + Polygons inset = outer_poly.offset(-(initial_inset + line_width / 2)); + while (! inset.empty()) + { + pattern.polygons.add(inset); + inset = inset.offset(-line_width); + } + + return pattern; +} +void PrimeTower::generatePaths_denseInfill() +{ const Scene& scene = Application::getInstance().current_slice->scene; const Settings& mesh_group_settings = scene.current_mesh_group->settings; const coord_t layer_height = mesh_group_settings.get("layer_height"); + const bool base_enabled = mesh_group_settings.get("prime_tower_brim_enable"); + const coord_t base_extra_radius = scene.settings.get("prime_tower_base_size"); + const coord_t base_height = scene.settings.get("prime_tower_base_height"); + const int magnitude = scene.settings.get("prime_tower_base_curve_magnitude"); pattern_per_extruder.resize(extruder_count); + pattern_extra_brim_per_layer.resize(extruder_count); coord_t cumulative_inset = 0; // Each tower shape is going to be printed inside the other. This is the inset we're doing for each extruder. for (size_t extruder_nr : extruder_order) @@ -173,23 +194,33 @@ void PrimeTower::generatePaths_denseInfill() } } - // Only the most inside extruder needs to fill the inside of the prime tower - if (extruder_nr == extruder_order.front()) + // The most outside extruder is used for the base + if (base_enabled && extruder_nr == extruder_order.front()) { - // Generate the pattern for the first layer. - const coord_t line_width_layer0 = scene.extruders[extruder_nr].settings.get("raft_base_line_width"); - ExtrusionMoves pattern_layer0 = generatePaths_extraBrim(outer_poly, brim_extra_radius, line_width_layer0, true); - pattern_extra_brim_per_layer.push_back(pattern_layer0); - - for (coord_t z = layer_height; z < brim_extra_height; z += layer_height) + for (coord_t z = 0; z < base_height; z += layer_height) { - double brim_radius_factor = std::pow((1.0 - static_cast(z) / brim_extra_height), 4); - coord_t extra_radius = brim_extra_radius * brim_radius_factor; - ExtrusionMoves pattern = generatePaths_extraBrim(outer_poly, extra_radius, line_width, false); - pattern_extra_brim_per_layer.push_back(pattern); + double brim_radius_factor = std::pow((1.0 - static_cast(z) / base_height), magnitude); + coord_t extra_radius = base_extra_radius * brim_radius_factor; + ExtrusionMoves pattern = generatePaths_base(outer_poly, extra_radius, line_width); + if (pattern.polygons.empty() && pattern.lines.empty()) + { + break; + } + pattern_extra_brim_per_layer[extruder_nr].push_back(pattern); } } + cumulative_inset += wall_nr * line_width; + + // Only the most inside extruder needs to fill the inside of the prime tower + if (extruder_nr == extruder_order.back()) + { + ExtrusionMoves pattern = generatePaths_inset(outer_poly, line_width, cumulative_inset); + if (! pattern.polygons.empty() || ! pattern.lines.empty()) + { + pattern_extra_brim_per_layer[extruder_nr].push_back(pattern); + } + } } } @@ -215,7 +246,7 @@ void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_la } const LayerIndex layer_nr = gcode_layer.getLayerNr(); - if (/*layer_nr < 0 ||*/ layer_nr > storage.max_print_height_second_to_last_extruder + 1) + if (layer_nr > storage.max_print_height_second_to_last_extruder + 1) { return; } @@ -252,26 +283,30 @@ void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_la void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t extruder_nr) const { - LayerIndex absolute_layer_number = gcode_layer.getLayerNr() + Raft::getTotalExtraLayers(); - assert(absolute_layer_number >= 0); + const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; + const ExtruderTrain& base_train = mesh_group_settings.get("raft_base_extruder_nr"); + const bool adhesion_raft = base_train.settings.get("adhesion_type") == EPlatformAdhesion::RAFT; + LayerIndex absolute_layer_number = gcode_layer.getLayerNr(); + if (adhesion_raft) + { + absolute_layer_number += Raft::getTotalExtraLayers(); + } - if (absolute_layer_number > 0) + if (! adhesion_raft || absolute_layer_number > 0) { // Actual prime pattern const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; - const ExtrusionMoves& pattern = pattern_per_extruder[extruder_nr]; gcode_layer.addPolygonsByOptimizer(pattern.polygons, config); gcode_layer.addLinesByOptimizer(pattern.lines, config, SpaceFillType::Lines); } - if (absolute_layer_number < pattern_extra_brim_per_layer.size() && extruder_nr == extruder_order.front()) + const std::vector& pattern_extra_brim = pattern_extra_brim_per_layer[extruder_nr]; + if (absolute_layer_number < pattern_extra_brim.size()) { - // Specific case for first layer => very high adhesion - const GCodePathConfig& config - = absolute_layer_number == 0 ? gcode_layer.configs_storage.raft_base_config : gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; - - const ExtrusionMoves& pattern = pattern_extra_brim_per_layer[absolute_layer_number]; + // Extra rings for stronger base + const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; + const ExtrusionMoves& pattern = pattern_extra_brim[absolute_layer_number]; gcode_layer.addPolygonsByOptimizer(pattern.polygons, config); gcode_layer.addLinesByOptimizer(pattern.lines, config, SpaceFillType::Lines); } diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 94761b0717..2ec4d932c2 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -110,39 +110,15 @@ std::vector SkirtBrim::generateBrimOffsetPlan(std::vector SkirtBrim::generatePrimeTowerBrimForSkirtAdhesionOffsetPlan() -{ - std::vector prime_brim_offsets; - - const Settings& global_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; - const bool prime_tower_brim_enable = global_settings.get("prime_tower_brim_enable"); - if (adhesion_type == EPlatformAdhesion::SKIRT && prime_tower_brim_enable && storage.primeTower.enabled) - { - const int extruder_nr = storage.primeTower.extruder_order[0]; - const ExtruderTrain& extruder = extruders[extruder_nr]; - int line_count = extruder.settings.get("brim_line_count"); - coord_t gap = extruder.settings.get("brim_gap"); - for (int line_idx = 0; line_idx < line_count; line_idx++) - { - const bool is_last = line_idx == line_count - 1; - coord_t offset = gap + line_widths[extruder_nr] / 2 + line_widths[extruder_nr] * line_idx; - prime_brim_offsets.emplace_back(&storage.primeTower.outer_poly, external_polys_only[extruder_nr], offset, offset, line_idx, extruder_nr, is_last); - } - } - - std::sort(prime_brim_offsets.begin(), prime_brim_offsets.end(), OffsetSorter); - return prime_brim_offsets; -} - void SkirtBrim::generate() { std::vector starting_outlines(extruder_count); std::vector all_brim_offsets = generateBrimOffsetPlan(starting_outlines); - std::vector prime_brim_offsets_for_skirt = generatePrimeTowerBrimForSkirtAdhesionOffsetPlan(); constexpr LayerIndex layer_nr = 0; constexpr bool include_support = true; - Polygons covered_area = storage.getLayerOutlines(layer_nr, include_support, /*include_prime_tower*/ true, /*external_polys_only*/ false); + const bool include_prime_tower = adhesion_type == EPlatformAdhesion::SKIRT; + Polygons covered_area = storage.getLayerOutlines(layer_nr, include_support, include_prime_tower, /*external_polys_only*/ false); std::vector allowed_areas_per_extruder(extruder_count); for (int extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++) @@ -161,14 +137,6 @@ void SkirtBrim::generate() } } - // Note that the brim generated here for the prime-tower is _only_ when the rest if the model uses skirt. - // If everything uses brim to begin with, _including_ the prime-tower, it's not generated here, but along the rest. - if (! prime_brim_offsets_for_skirt.empty()) - { - // Note that his ignores the returned lengths: Less 'correct' in a sense, will be predictable for the user. - generatePrimaryBrim(prime_brim_offsets_for_skirt, covered_area, allowed_areas_per_extruder); - } - // Apply 'approximate convex hull' if the adhesion is skirt _after_ any skirt but also prime-tower-brim adhesion. // Otherwise, the now expanded convex hull covered areas will mess with that brim. Fortunately this does not mess // with the other area calculation above, since they are either itself a simple/convex shape or relevant for brim. @@ -406,12 +374,7 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) if (skirt_around_prime_tower_brim) { - const int prime_tower_brim_extruder_nr = storage.primeTower.extruder_order[0]; - const ExtruderTrain& prime_tower_brim_extruder = extruders[prime_tower_brim_extruder_nr]; - int line_count = prime_tower_brim_extruder.settings.get("brim_line_count"); - coord_t tower_gap = prime_tower_brim_extruder.settings.get("brim_gap"); - coord_t brim_width = tower_gap + line_count * line_widths[prime_tower_brim_extruder_nr]; - first_layer_outline = first_layer_outline.unionPolygons(storage.primeTower.outer_poly.offset(brim_width)); + first_layer_outline = first_layer_outline.unionPolygons(storage.primeTower.footprint); } Polygons shields; @@ -435,7 +398,7 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) else { // add brim underneath support by removing support where there's brim around the model constexpr bool include_support = false; // Include manually below. - constexpr bool include_prime_tower = false; // Include manually below. + constexpr bool include_prime_tower = false; // Not included. constexpr bool external_outlines_only = false; // Remove manually below. first_layer_outline = storage.getLayerOutlines(layer_nr, include_support, include_prime_tower, external_outlines_only, extruder_nr); first_layer_outline = first_layer_outline.unionPolygons(); // To guard against overlapping outlines, which would produce holes according to the even-odd rule. @@ -480,10 +443,6 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) first_layer_outline.add(support_layer.support_bottom); first_layer_outline.add(support_layer.support_roof); } - if (storage.primeTower.enabled && global_settings.get("prime_tower_brim_enable") && (extruder_nr == -1 || int(storage.primeTower.extruder_order[0]) == extruder_nr)) - { - first_layer_outline.add(storage.primeTower.outer_poly); // don't remove parts of the prime tower, but make a brim for it - } } constexpr coord_t join_distance = 20; first_layer_outline = first_layer_outline.offset(join_distance).offset(-join_distance); // merge adjacent models into single polygon diff --git a/src/raft.cpp b/src/raft.cpp index 384958afc4..bee9cc643b 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -66,14 +66,14 @@ void Raft::generate(SliceDataStorage& storage) } } - // storage.primeRaftOutline = storage.primeTower.outer_poly.offset(distance, ClipperLib::jtRound); - // NOTE: the raft doesn't take the prime tower brim into account, because it's (currently) not being printed when printing a raft - // if (settings.get("raft_remove_inside_corners")) - //{ - // storage.primeRaftOutline = storage.primeRaftOutline.unionPolygons(storage.raftOutline); - // storage.primeRaftOutline.makeConvex(); - // } - // storage.primeRaftOutline = storage.primeRaftOutline.difference(storage.raftOutline); // In case of overlaps. + const coord_t prime_tower_distance = settings.get("prime_tower_base_size"); + storage.primeRaftOutline = storage.primeTower.outer_poly.offset(prime_tower_distance, ClipperLib::jtRound); + if (settings.get("raft_remove_inside_corners")) + { + storage.primeRaftOutline = storage.primeRaftOutline.unionPolygons(storage.raftOutline); + storage.primeRaftOutline.makeConvex(); + } + storage.primeRaftOutline = storage.primeRaftOutline.difference(storage.raftOutline); // In case of overlaps. } coord_t Raft::getTotalThickness() diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index 4533fbb8be..e5ba324ccb 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -333,7 +333,14 @@ Polygons { if (primeTower.enabled) { - total.add(primeTower.outer_poly); + if (layer_nr == 0) + { + total.add(primeTower.footprint); + } + else + { + total.add(primeTower.outer_poly); + } } } return total; From 1f8df4ce8be6663901d5c2bb2697455fae12a80e Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 10 Oct 2023 17:03:15 +0200 Subject: [PATCH 047/116] Fix dark floating-point bug --- src/LayerPlanBuffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LayerPlanBuffer.cpp b/src/LayerPlanBuffer.cpp index 6551543bdc..b5bede2665 100644 --- a/src/LayerPlanBuffer.cpp +++ b/src/LayerPlanBuffer.cpp @@ -429,7 +429,7 @@ void LayerPlanBuffer::insertFinalPrintTempCommand(std::vector& ex return; } - assert((time_window >= 0 || last_extruder_plan.estimates.material == 0) && "Time window should always be positive if we actually extrude"); + assert((time_window >= -0.001 || last_extruder_plan.estimates.material == 0) && "Time window should always be positive if we actually extrude"); // ,layer change . // : ,precool command ,layer change . From 90f8a8f59b09dfc96049c206ecb705f781b21726 Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Tue, 10 Oct 2023 15:04:01 +0000 Subject: [PATCH 048/116] Applied clang-format. --- include/PrimeTower.h | 4 +-- include/SkirtBrim.h | 82 +++++++++++++++++++++----------------------- 2 files changed, 41 insertions(+), 45 deletions(-) diff --git a/include/PrimeTower.h b/include/PrimeTower.h index fe29030ee2..bdbc36bc0e 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -102,9 +102,9 @@ class PrimeTower void subtractFromSupport(SliceDataStorage& storage); private: - ExtrusionMoves generatePaths_base(const Polygons &outer_poly, coord_t extra_radius, coord_t line_width); + ExtrusionMoves generatePaths_base(const Polygons& outer_poly, coord_t extra_radius, coord_t line_width); - ExtrusionMoves generatePaths_inset(const Polygons &outer_poly, coord_t line_width, coord_t initial_inset); + ExtrusionMoves generatePaths_inset(const Polygons& outer_poly, coord_t line_width, coord_t initial_inset); /*! * \see WipeTower::generatePaths diff --git a/include/SkirtBrim.h b/include/SkirtBrim.h index 05f10a17e4..fa41df0999 100644 --- a/include/SkirtBrim.h +++ b/include/SkirtBrim.h @@ -1,17 +1,17 @@ -//Copyright (c) 2023 UltiMaker -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2023 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef SKIRT_BRIM_H #define SKIRT_BRIM_H -#include "utils/Coord_t.h" #include "ExtruderTrain.h" #include "settings/EnumSettings.h" #include "sliceDataStorage.h" +#include "utils/Coord_t.h" #include -namespace cura +namespace cura { class Polygons; @@ -27,26 +27,25 @@ class SkirtBrim */ struct Offset { - Offset - ( + Offset( const std::variant& reference_outline_or_index, const bool external_only, const coord_t offset_value, const coord_t total_offset, const size_t inset_idx, const int extruder_nr, - const bool is_last - ) : - reference_outline_or_index(reference_outline_or_index), - external_only(external_only), - offset_value(offset_value), - total_offset(total_offset), - inset_idx(inset_idx), - extruder_nr(extruder_nr), - is_last(is_last) - {} - - std::variant reference_outline_or_index; + const bool is_last) + : reference_outline_or_index(reference_outline_or_index) + , external_only(external_only) + , offset_value(offset_value) + , total_offset(total_offset) + , inset_idx(inset_idx) + , extruder_nr(extruder_nr) + , is_last(is_last) + { + } + + std::variant reference_outline_or_index; bool external_only; //!< Wether to only offset outward from the reference polygons coord_t offset_value; //!< Distance by which to offset from the reference coord_t total_offset; //!< Total distance from the model @@ -58,15 +57,12 @@ class SkirtBrim /*! * Defines an order on offsets (potentially from different extruders) based on how far the offset is from the original outline. */ - static inline const auto OffsetSorter - { - [](const Offset& a, const Offset& b) - { - // Use extruder_nr in case both extruders have the same offset settings. - return a.total_offset != b.total_offset ? a.total_offset < b.total_offset : a.extruder_nr < b.extruder_nr; - } - }; - + static inline const auto OffsetSorter{ [](const Offset& a, const Offset& b) + { + // Use extruder_nr in case both extruders have the same offset settings. + return a.total_offset != b.total_offset ? a.total_offset < b.total_offset : a.extruder_nr < b.extruder_nr; + } }; + SliceDataStorage& storage; //!< Where to retrieve settings and store brim lines. const EPlatformAdhesion adhesion_type; //!< Whether we are generating brim, skirt, or raft const bool has_ooze_shield; //!< Whether the meshgroup has an ooze shield @@ -85,17 +81,17 @@ class SkirtBrim public: /*! * Precomputes some values used in several functions when calling \ref generate - * + * * \param storage Storage containing the parts at the first layer. */ SkirtBrim(SliceDataStorage& storage); /*! * Generate skirt or brim (depending on parameters). - * + * * When \p distance > 0 and \p count == 1 a skirt is generated, which has * slightly different configuration. Otherwise, a brim is generated. - * + * * \param storage Storage containing the parts at the first layer. * \param first_layer_outline The outline to generate skirt or brim around. * \param distance The distance of the first outset from the parts at the first @@ -108,7 +104,7 @@ class SkirtBrim private: /*! * Plan the offsets which we will be going to perform and put them in the right order. - * + * * In order for brims of different materials to grow toward the middle, * we need to perform the offsets alternatingly. * We therefore first create all planned Offset objects, @@ -120,7 +116,7 @@ class SkirtBrim /*! * Generate the primary skirt/brim of the one skirt_brim_extruder or of all extruders simultaneously. - * + * * \param[in,out] all_brim_offsets The offsets to perform. Adjusted when the minimal length constraint isn't met yet. * \param[in,out] covered_area The area of the first layer covered by model or generated brim lines. * \param[in,out] allowed_areas_per_extruder The difference between the machine bed area (offsetted by the nozzle offset) and the covered_area. @@ -130,9 +126,9 @@ class SkirtBrim /*! * Generate the brim inside the ooze shield and draft shield - * + * * \warning Adjusts brim_covered_area - * + * * \param storage Storage containing the parts at the first layer. * \param[in,out] brim_covered_area The area that was covered with brim before (in) and after (out) adding the shield brims * \param[in,out] allowed_areas_per_extruder The difference between the machine areas and the \p covered_area @@ -154,10 +150,10 @@ class SkirtBrim /*! * The disallowed area around the internal holes of parts with other parts inside which would get an external brim. - * + * * In order to prevent the external_only brim of a part inside another part to overlap with the internal holes of the outer part, * we generate a disallowed area around those internal hole polygons. - * + * * \param outline The full layer outlines * \param extruder_nr The extruder for which to compute disallowed areas * \return The disallowed areas @@ -166,9 +162,9 @@ class SkirtBrim /*! * Generate a brim line with offset parameters given by \p offset from the \p starting_outlines and store it in the \ref storage. - * + * * \warning Has side effects on \p covered_area, \p allowed_areas_per_extruder and \p total_length - * + * * \param offset The parameters with which to perform the offset * \param[in,out] covered_area The total area covered by the brims (and models) on the first layer. * \param[in,out] allowed_areas_per_extruder The difference between the machine areas and the \p covered_area @@ -179,11 +175,11 @@ class SkirtBrim /*! * Generate a skirt of extruders which don't yet comply with the minimum length requirement. - * + * * This skirt goes directly adjacent to all primary brims. - * + * * The skirt is stored in storage.skirt_brim. - * + * * \param[in,out] covered_area The total area covered by the brims (and models) on the first layer. * \param[in,out] allowed_areas_per_extruder The difference between the machine areas and the \p covered_area * \param[in,out] total_length The total length of the brim lines for each extruder. @@ -196,6 +192,6 @@ class SkirtBrim */ void generateSupportBrim(); }; -}//namespace cura +} // namespace cura -#endif //SKIRT_BRIM_H +#endif // SKIRT_BRIM_H 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 049/116] 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 2dada4ceabe4c600ba3fad0caad640a8329c3ee6 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 12 Oct 2023 15:41:32 +0200 Subject: [PATCH 050/116] Properly handle overlapping brims/rafts CURA-10783 --- include/PrimeTower.h | 21 ++- include/sliceDataStorage.h | 2 - src/FffGcodeWriter.cpp | 252 ++++++++++++++++++------------------ src/FffPolygonGenerator.cpp | 4 +- src/PrimeTower.cpp | 77 +++++------ src/SkirtBrim.cpp | 15 ++- src/TreeModelVolumes.cpp | 2 +- src/raft.cpp | 10 -- src/sliceDataStorage.cpp | 9 +- 9 files changed, 196 insertions(+), 196 deletions(-) diff --git a/include/PrimeTower.h b/include/PrimeTower.h index bdbc36bc0e..9133d3007a 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -4,6 +4,7 @@ #ifndef PRIME_TOWER_H #define PRIME_TOWER_H +#include "settings/types/LayerIndex.h" #include "utils/polygon.h" // Polygons #include "utils/polygonUtils.h" @@ -42,12 +43,20 @@ class PrimeTower std::vector pattern_per_extruder; //!< For each extruder the pattern to print on all layers of the prime tower. std::vector> pattern_extra_brim_per_layer; //!< For each layer of each extruder with an extra brim, the pattern to be added + Polygons outer_poly; //!< The outline of the outermost prime tower. + + struct BasePolygon + { + Polygons polygons; + size_t extra_rings; + }; + + std::vector outer_poly_base; //!< The outline of the prime tower for layers having a base + public: bool enabled; //!< Whether the prime tower is enabled. bool would_have_actual_tower; //!< Whether there is an actual tower. bool multiple_extruders_on_first_layer; //!< Whether multiple extruders are allowed on the first layer of the prime tower (e.g. when a raft is there) - Polygons outer_poly; //!< The outline of the outermost prime tower. - Polygons footprint; //!< The outline of the prime tower on layer 0 /* * In which order, from outside to inside, will we be printing the prime @@ -101,10 +110,14 @@ class PrimeTower */ void subtractFromSupport(SliceDataStorage& storage); + const Polygons &getOuterPoly(const LayerIndex &layer_nr) const; + + const Polygons &getGroundPoly() const; + private: - ExtrusionMoves generatePaths_base(const Polygons& outer_poly, coord_t extra_radius, coord_t line_width); + static ExtrusionMoves generatePaths_base(const Polygons &inset, size_t rings, coord_t line_width); - ExtrusionMoves generatePaths_inset(const Polygons& outer_poly, coord_t line_width, coord_t initial_inset); + static ExtrusionMoves generatePaths_inset(const Polygons& outer_poly, coord_t line_width, coord_t initial_inset); /*! * \see WipeTower::generatePaths diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 9b0661ed36..c3313e801a 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -333,8 +333,6 @@ class SliceDataStorage : public NoCopy std::vector skirt_brim[MAX_EXTRUDERS]; //!< Skirt/brim polygons per extruder, ordered from inner to outer polygons. Polygons support_brim; //!< brim lines for support, going from the edge of the support inward. \note Not ordered by inset. Polygons raftOutline; // Storage for the outline of the raft. Will be filled with lines when the GCode is generated. - Polygons primeRaftOutline; // ... the raft underneath the prime-tower will have to be printed first, if there is one. (When the raft has top layers with a different extruder - // for example.) int max_print_height_second_to_last_extruder; //!< Used in multi-extrusion: the layer number beyond which all models are printed with the same extruder std::vector max_print_height_per_extruder; //!< For each extruder the highest layer number at which it is used. diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index f8dabab971..0deaaff908 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -621,69 +621,65 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) const coord_t max_resolution = base_settings.get("meshfix_maximum_resolution"); const coord_t max_deviation = base_settings.get("meshfix_maximum_deviation"); - std::vector raft_outline_paths; - if (storage.primeRaftOutline.area() > 0) + Polygons raft_outline_path = storage.raftOutline; + if (storage.primeTower.enabled) { - raft_outline_paths.emplace_back(storage.primeRaftOutline); + raft_outline_path = raft_outline_path.unionPolygons(storage.primeTower.getOuterPoly(layer_nr)); } - raft_outline_paths.emplace_back(storage.raftOutline); - for (const Polygons& raft_outline_path : raft_outline_paths) + Infill infill_comp( + EFillMethod::LINES, + zig_zaggify_infill, + connect_polygons, + raft_outline_path, + gcode_layer.configs_storage.raft_base_config.getLineWidth(), + line_spacing, + fill_overlap, + infill_multiplier, + fill_angle, + 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); + std::vector raft_paths; + infill_comp.generate(raft_paths, raft_polygons, raftLines, base_settings, layer_nr, SectionType::ADHESION); + if (! raft_paths.empty()) { - Infill infill_comp( - EFillMethod::LINES, - zig_zaggify_infill, - connect_polygons, - raft_outline_path, - gcode_layer.configs_storage.raft_base_config.getLineWidth(), - line_spacing, - fill_overlap, - infill_multiplier, - fill_angle, - 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); - std::vector raft_paths; - infill_comp.generate(raft_paths, raft_polygons, raftLines, base_settings, layer_nr, SectionType::ADHESION); - if (! raft_paths.empty()) - { - const GCodePathConfig& config = gcode_layer.configs_storage.raft_base_config; - const ZSeamConfig z_seam_config(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); - InsetOrderOptimizer wall_orderer( - *this, - storage, - gcode_layer, - base_settings, - base_extruder_nr, - config, - config, - config, - config, - retract_before_outer_wall, - wipe_dist, - wipe_dist, - base_extruder_nr, - base_extruder_nr, - z_seam_config, - raft_paths); - wall_orderer.addToLayer(); - } - gcode_layer.addLinesByOptimizer(raftLines, gcode_layer.configs_storage.raft_base_config, SpaceFillType::Lines); - - raft_polygons.clear(); - raftLines.clear(); + const GCodePathConfig& config = gcode_layer.configs_storage.raft_base_config; + const ZSeamConfig z_seam_config(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); + InsetOrderOptimizer wall_orderer( + *this, + storage, + gcode_layer, + base_settings, + base_extruder_nr, + config, + config, + config, + config, + retract_before_outer_wall, + wipe_dist, + wipe_dist, + base_extruder_nr, + base_extruder_nr, + z_seam_config, + raft_paths); + wall_orderer.addToLayer(); } + gcode_layer.addLinesByOptimizer(raftLines, gcode_layer.configs_storage.raft_base_config, SpaceFillType::Lines); + + raft_polygons.clear(); + raftLines.clear(); layer_plan_buffer.handle(gcode_layer, gcode); last_planned_position = gcode_layer.getLastPlannedPositionOrStartingPosition(); @@ -728,11 +724,11 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) Application::getInstance().communication->sendLayerComplete(layer_nr, z, interface_layer_height); - std::vector raft_outline_paths; + Polygons raft_outline_path; const coord_t small_offset = gcode_layer.configs_storage.raft_interface_config.getLineWidth() / 2; // Do this manually because of micron-movement created in corners when insetting a polygon that was offset with round joint type. - raft_outline_paths.emplace_back(storage.raftOutline.offset(-small_offset)); - raft_outline_paths.back() = Simplify(interface_settings).polygon(raft_outline_paths.back()); // Remove those micron-movements. + raft_outline_path = storage.raftOutline.offset(-small_offset); + raft_outline_path = Simplify(interface_settings).polygon(raft_outline_path); // Remove those micron-movements. const coord_t infill_outline_width = gcode_layer.configs_storage.raft_interface_config.getLineWidth(); Polygons raft_lines; AngleDegrees fill_angle = (num_surface_layers + num_interface_layers - raft_interface_layer) % 2 ? 45 : 135; // 90 degrees rotated from the first top layer. @@ -749,40 +745,42 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) constexpr int zag_skip_count = 0; constexpr coord_t pocket_size = 0; - for (const Polygons& raft_outline_path : raft_outline_paths) + if (storage.primeTower.enabled) { - Infill infill_comp( - EFillMethod::ZIG_ZAG, - zig_zaggify_infill, - connect_polygons, - raft_outline_path, - infill_outline_width, - interface_line_spacing, - fill_overlap, - infill_multiplier, - fill_angle, - z, - extra_infill_shift, - interface_max_resolution, - interface_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); - std::vector raft_paths; // Should remain empty, since we have no walls. - infill_comp.generate(raft_paths, raft_polygons, raft_lines, interface_settings, layer_nr, SectionType::ADHESION); - gcode_layer.addLinesByOptimizer(raft_lines, gcode_layer.configs_storage.raft_interface_config, SpaceFillType::Lines, false, 0, 1.0, last_planned_position); - - raft_polygons.clear(); - raft_lines.clear(); + raft_outline_path = raft_outline_path.difference(storage.primeTower.getOuterPoly(layer_nr)); } + Infill infill_comp( + EFillMethod::ZIG_ZAG, + zig_zaggify_infill, + connect_polygons, + raft_outline_path, + infill_outline_width, + interface_line_spacing, + fill_overlap, + infill_multiplier, + fill_angle, + z, + extra_infill_shift, + interface_max_resolution, + interface_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); + std::vector raft_paths; // Should remain empty, since we have no walls. + infill_comp.generate(raft_paths, raft_polygons, raft_lines, interface_settings, layer_nr, SectionType::ADHESION); + gcode_layer.addLinesByOptimizer(raft_lines, gcode_layer.configs_storage.raft_interface_config, SpaceFillType::Lines, false, 0, 1.0, last_planned_position); + + raft_polygons.clear(); + raft_lines.clear(); + setExtruder_addPrime(storage, gcode_layer, storage.primeTower.extruder_order.front()); layer_plan_buffer.handle(gcode_layer, gcode); @@ -829,11 +827,11 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) Application::getInstance().communication->sendLayerComplete(layer_nr, z, surface_layer_height); - std::vector raft_outline_paths; + Polygons raft_outline_path; const coord_t small_offset = gcode_layer.configs_storage.raft_interface_config.getLineWidth() / 2; // Do this manually because of micron-movement created in corners when insetting a polygon that was offset with round joint type. - raft_outline_paths.emplace_back(storage.raftOutline.offset(-small_offset)); - raft_outline_paths.back() = Simplify(interface_settings).polygon(raft_outline_paths.back()); // Remove those micron-movements. + raft_outline_path = storage.raftOutline.offset(-small_offset); + raft_outline_path = Simplify(interface_settings).polygon(raft_outline_path); // Remove those micron-movements. const coord_t infill_outline_width = gcode_layer.configs_storage.raft_interface_config.getLineWidth(); Polygons raft_lines; AngleDegrees fill_angle @@ -851,40 +849,42 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) constexpr size_t zag_skip_count = 0; constexpr coord_t pocket_size = 0; - for (const Polygons& raft_outline_path : raft_outline_paths) + if (storage.primeTower.enabled) { - Infill infill_comp( - EFillMethod::ZIG_ZAG, - zig_zaggify_infill, - connect_polygons, - raft_outline_path, - infill_outline_width, - surface_line_spacing, - fill_overlap, - infill_multiplier, - fill_angle, - z, - extra_infill_shift, - surface_max_resolution, - surface_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); - std::vector raft_paths; // Should remain empty, since we have no walls. - infill_comp.generate(raft_paths, raft_polygons, raft_lines, surface_settings, layer_nr, SectionType::ADHESION); - gcode_layer.addLinesByOptimizer(raft_lines, gcode_layer.configs_storage.raft_surface_config, SpaceFillType::Lines, false, 0, 1.0, last_planned_position); - - raft_polygons.clear(); - raft_lines.clear(); + raft_outline_path = raft_outline_path.difference(storage.primeTower.getOuterPoly(layer_nr)); } + Infill infill_comp( + EFillMethod::ZIG_ZAG, + zig_zaggify_infill, + connect_polygons, + raft_outline_path, + infill_outline_width, + surface_line_spacing, + fill_overlap, + infill_multiplier, + fill_angle, + z, + extra_infill_shift, + surface_max_resolution, + surface_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); + std::vector raft_paths; // Should remain empty, since we have no walls. + infill_comp.generate(raft_paths, raft_polygons, raft_lines, surface_settings, layer_nr, SectionType::ADHESION); + gcode_layer.addLinesByOptimizer(raft_lines, gcode_layer.configs_storage.raft_surface_config, SpaceFillType::Lines, false, 0, 1.0, last_planned_position); + + raft_polygons.clear(); + raft_lines.clear(); + setExtruder_addPrime(storage, gcode_layer, storage.primeTower.extruder_order.front()); layer_plan_buffer.handle(gcode_layer, gcode); diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index daff0196eb..640a563284 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -985,7 +985,7 @@ void FffPolygonGenerator::processOozeShield(SliceDataStorage& storage) } for (LayerIndex layer_nr = 0; layer_nr <= storage.max_print_height_second_to_last_extruder; layer_nr++) { - storage.oozeShield[layer_nr] = storage.oozeShield[layer_nr].difference(storage.primeTower.outer_poly.offset(max_line_width / 2)); + storage.oozeShield[layer_nr] = storage.oozeShield[layer_nr].difference(storage.primeTower.getOuterPoly(layer_nr).offset(max_line_width / 2)); } } } @@ -1035,7 +1035,7 @@ void FffPolygonGenerator::processDraftShield(SliceDataStorage& storage) max_line_width = std::max(max_line_width, extruders[extruder_nr].settings.get("skirt_brim_line_width")); } } - storage.draft_protection_shield = storage.draft_protection_shield.difference(storage.primeTower.outer_poly.offset(max_line_width / 2)); + storage.draft_protection_shield = storage.draft_protection_shield.difference(storage.primeTower.getGroundPoly().offset(max_line_width / 2)); } } diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 49de8b3db1..39c6ae3fe2 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -87,7 +87,8 @@ void PrimeTower::generateGroundpoly() return; } - const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; + const Scene& scene = Application::getInstance().current_slice->scene; + const Settings& mesh_group_settings = scene.current_mesh_group->settings; const coord_t tower_size = mesh_group_settings.get("prime_tower_size"); const coord_t x = mesh_group_settings.get("prime_tower_position_x"); @@ -97,18 +98,6 @@ void PrimeTower::generateGroundpoly() middle = Point(x - tower_size / 2, y + tower_size / 2); post_wipe_point = Point(x - tower_size / 2, y + tower_size / 2); - - const bool base_enabled = mesh_group_settings.get("prime_tower_brim_enable"); - const coord_t base_extra_radius = mesh_group_settings.get("prime_tower_base_size"); - const coord_t base_height = mesh_group_settings.get("prime_tower_base_height"); - if (base_enabled && base_extra_radius > 0 && base_height > 0) - { - footprint = outer_poly.offset(base_extra_radius); - } - else - { - footprint = outer_poly; - } } void PrimeTower::generatePaths(const SliceDataStorage& storage) @@ -122,21 +111,15 @@ void PrimeTower::generatePaths(const SliceDataStorage& storage) } } -PrimeTower::ExtrusionMoves PrimeTower::generatePaths_base(const Polygons& outer_poly, coord_t extra_radius, coord_t line_width) +PrimeTower::ExtrusionMoves PrimeTower::generatePaths_base(const Polygons& inset, size_t rings, coord_t line_width) { - const Scene& scene = Application::getInstance().current_slice->scene; - const Settings& mesh_group_settings = scene.current_mesh_group->settings; - const coord_t tower_size = mesh_group_settings.get("prime_tower_size"); - ExtrusionMoves pattern; - int circles = 0; - Polygons outset = outer_poly.offset(line_width / 2); - while (outset.max() - outset.min() < (tower_size + extra_radius * 2)) + Polygons path = inset.offset(line_width / 2); + for (size_t ring = 0; ring < rings; ++ring) { - pattern.polygons.add(outset); - outset = outset.offset(line_width); - circles++; + pattern.polygons.add(path); + path = path.offset(line_width); } return pattern; @@ -167,7 +150,9 @@ void PrimeTower::generatePaths_denseInfill() const bool base_enabled = mesh_group_settings.get("prime_tower_brim_enable"); const coord_t base_extra_radius = scene.settings.get("prime_tower_base_size"); const coord_t base_height = scene.settings.get("prime_tower_base_height"); - const int magnitude = scene.settings.get("prime_tower_base_curve_magnitude"); + const int base_curve_magnitude = mesh_group_settings.get("prime_tower_base_curve_magnitude"); + const coord_t line_width = scene.extruders[extruder_order.front()].settings.get("prime_tower_line_width"); + pattern_per_extruder.resize(extruder_count); pattern_extra_brim_per_layer.resize(extruder_count); @@ -195,18 +180,21 @@ void PrimeTower::generatePaths_denseInfill() } // The most outside extruder is used for the base - if (base_enabled && extruder_nr == extruder_order.front()) + if (extruder_nr == extruder_order.front() && base_enabled && base_extra_radius > 0 && base_height > 0) { for (coord_t z = 0; z < base_height; z += layer_height) { - double brim_radius_factor = std::pow((1.0 - static_cast(z) / base_height), magnitude); + double brim_radius_factor = std::pow((1.0 - static_cast(z) / base_height), base_curve_magnitude); coord_t extra_radius = base_extra_radius * brim_radius_factor; - ExtrusionMoves pattern = generatePaths_base(outer_poly, extra_radius, line_width); - if (pattern.polygons.empty() && pattern.lines.empty()) + size_t extra_rings = extra_radius / line_width; + if (extra_rings == 0) { break; } - pattern_extra_brim_per_layer[extruder_nr].push_back(pattern); + extra_radius = line_width * extra_rings; + outer_poly_base.push_back(outer_poly.offset(extra_radius)); + + pattern_extra_brim_per_layer[extruder_nr].push_back(generatePaths_base(outer_poly, extra_rings, line_width)); } } @@ -283,14 +271,9 @@ void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_la void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t extruder_nr) const { - const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; - const ExtruderTrain& base_train = mesh_group_settings.get("raft_base_extruder_nr"); - const bool adhesion_raft = base_train.settings.get("adhesion_type") == EPlatformAdhesion::RAFT; - LayerIndex absolute_layer_number = gcode_layer.getLayerNr(); - if (adhesion_raft) - { - absolute_layer_number += Raft::getTotalExtraLayers(); - } + const size_t raft_total_extra_layers = Raft::getTotalExtraLayers(); + const bool adhesion_raft = raft_total_extra_layers > 0; + LayerIndex absolute_layer_number = gcode_layer.getLayerNr() + raft_total_extra_layers; if (! adhesion_raft || absolute_layer_number > 0) { @@ -324,6 +307,24 @@ void PrimeTower::subtractFromSupport(SliceDataStorage& storage) } } +const Polygons& PrimeTower::getOuterPoly(const LayerIndex& layer_nr) const +{ + const LayerIndex absolute_layer_nr = layer_nr + Raft::getTotalExtraLayers(); + if (absolute_layer_nr < outer_poly_base.size()) + { + return outer_poly_base[absolute_layer_nr]; + } + else + { + return outer_poly; + } +} + +const Polygons& PrimeTower::getGroundPoly() const +{ + return getOuterPoly(-Raft::getTotalExtraLayers()); +} + void PrimeTower::gotoStartLocation(LayerPlan& gcode_layer, const int extruder_nr) const { int current_start_location_idx = ((((extruder_nr + 1) * gcode_layer.getLayerNr()) % number_of_prime_tower_start_locations) + number_of_prime_tower_start_locations) diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 2ec4d932c2..522e0994f5 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -118,6 +118,7 @@ void SkirtBrim::generate() constexpr LayerIndex layer_nr = 0; constexpr bool include_support = true; const bool include_prime_tower = adhesion_type == EPlatformAdhesion::SKIRT; + const bool has_prime_tower = storage.primeTower.enabled; Polygons covered_area = storage.getLayerOutlines(layer_nr, include_support, include_prime_tower, /*external_polys_only*/ false); std::vector allowed_areas_per_extruder(extruder_count); @@ -135,6 +136,11 @@ void SkirtBrim::generate() // so that the brim lines don't overlap with the holes by half the line width allowed_areas_per_extruder[extruder_nr] = allowed_areas_per_extruder[extruder_nr].difference(getInternalHoleExclusionArea(covered_area, extruder_nr)); } + + if (has_prime_tower) + { + allowed_areas_per_extruder[extruder_nr] = allowed_areas_per_extruder[extruder_nr].difference(storage.primeTower.getGroundPoly()); + } } // Apply 'approximate convex hull' if the adhesion is skirt _after_ any skirt but also prime-tower-brim adhesion. @@ -344,12 +350,12 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) const int primary_line_count = line_count[reference_extruder_nr]; const bool external_only = adhesion_type == EPlatformAdhesion::SKIRT || external_polys_only[reference_extruder_nr]; // Whether to include holes or not. Skirt doesn't have any holes. + const bool has_prime_tower = storage.primeTower.enabled; const LayerIndex layer_nr = 0; if (adhesion_type == EPlatformAdhesion::SKIRT) { constexpr bool include_support = true; - const bool skirt_around_prime_tower_brim = storage.primeTower.enabled && global_settings.get("prime_tower_brim_enable"); - const bool include_prime_tower = ! skirt_around_prime_tower_brim; // include manually otherwise + const bool include_prime_tower = ! has_prime_tower; // include manually otherwise first_layer_outline = Polygons(); int skirt_height = 0; @@ -371,10 +377,9 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) } } - - if (skirt_around_prime_tower_brim) + if (has_prime_tower) { - first_layer_outline = first_layer_outline.unionPolygons(storage.primeTower.footprint); + first_layer_outline = first_layer_outline.unionPolygons(storage.primeTower.getGroundPoly()); } Polygons shields; diff --git a/src/TreeModelVolumes.cpp b/src/TreeModelVolumes.cpp index 6ddcef2c93..aea31de82c 100644 --- a/src/TreeModelVolumes.cpp +++ b/src/TreeModelVolumes.cpp @@ -150,7 +150,7 @@ TreeModelVolumes::TreeModelVolumes( if (storage.primeTower.enabled) { - anti_overhang_[layer_idx].add(storage.primeTower.outer_poly); + anti_overhang_[layer_idx].add(storage.primeTower.getGroundPoly()); } anti_overhang_[layer_idx] = anti_overhang_[layer_idx].unionPolygons(); }); diff --git a/src/raft.cpp b/src/raft.cpp index bee9cc643b..af8daafde0 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -8,7 +8,6 @@ #include "Slice.h" #include "settings/EnumSettings.h" //For EPlatformAdhesion. #include "sliceDataStorage.h" -#include "support.h" #include "utils/math.h" #include @@ -65,15 +64,6 @@ void Raft::generate(SliceDataStorage& storage) return; } } - - const coord_t prime_tower_distance = settings.get("prime_tower_base_size"); - storage.primeRaftOutline = storage.primeTower.outer_poly.offset(prime_tower_distance, ClipperLib::jtRound); - if (settings.get("raft_remove_inside_corners")) - { - storage.primeRaftOutline = storage.primeRaftOutline.unionPolygons(storage.raftOutline); - storage.primeRaftOutline.makeConvex(); - } - storage.primeRaftOutline = storage.primeRaftOutline.difference(storage.raftOutline); // In case of overlaps. } coord_t Raft::getTotalThickness() diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index e5ba324ccb..c560a2b675 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -333,14 +333,7 @@ Polygons { if (primeTower.enabled) { - if (layer_nr == 0) - { - total.add(primeTower.footprint); - } - else - { - total.add(primeTower.outer_poly); - } + total.add(primeTower.getOuterPoly(layer_nr)); } } return total; From 23080f9069ad7046a43643fb391d1f121fbe0d1b Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Thu, 12 Oct 2023 13:44:20 +0000 Subject: [PATCH 051/116] Applied clang-format. --- include/PrimeTower.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/PrimeTower.h b/include/PrimeTower.h index 9133d3007a..63a84a254f 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -110,12 +110,12 @@ class PrimeTower */ void subtractFromSupport(SliceDataStorage& storage); - const Polygons &getOuterPoly(const LayerIndex &layer_nr) const; + const Polygons& getOuterPoly(const LayerIndex& layer_nr) const; - const Polygons &getGroundPoly() const; + const Polygons& getGroundPoly() const; private: - static ExtrusionMoves generatePaths_base(const Polygons &inset, size_t rings, coord_t line_width); + static ExtrusionMoves generatePaths_base(const Polygons& inset, size_t rings, coord_t line_width); static ExtrusionMoves generatePaths_inset(const Polygons& outer_poly, coord_t line_width, coord_t initial_inset); From 01c239b7dc965d98f06c1009e70c8741184d1fd6 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 13 Oct 2023 07:43:29 +0200 Subject: [PATCH 052/116] Fixed prime tower overlapping support CURA-10783 --- src/PrimeTower.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 39c6ae3fe2..5166fe5bc1 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -297,10 +297,10 @@ void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t ext void PrimeTower::subtractFromSupport(SliceDataStorage& storage) { - const Polygons outside_polygon = outer_poly.getOutsidePolygons(); - AABB outside_polygon_boundary_box(outside_polygon); for (size_t layer = 0; layer <= (size_t)storage.max_print_height_second_to_last_extruder + 1 && layer < storage.support.supportLayers.size(); layer++) { + const Polygons outside_polygon = getOuterPoly(layer).getOutsidePolygons(); + AABB outside_polygon_boundary_box(outside_polygon); SupportLayer& support_layer = storage.support.supportLayers[layer]; // take the differences of the support infill parts and the prime tower area support_layer.excludeAreasFromSupportInfillAreas(outside_polygon, outside_polygon_boundary_box); From c874b2b3cd38384fe8bb2443ad451e3c82e3a8e3 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 13 Oct 2023 10:54:08 +0200 Subject: [PATCH 053/116] Code documentation and cleaning CURA-10783 --- include/PrimeTower.h | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/include/PrimeTower.h b/include/PrimeTower.h index 63a84a254f..2201ce7544 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -41,17 +41,10 @@ class PrimeTower const unsigned int number_of_prime_tower_start_locations = 21; //!< The required size of \ref PrimeTower::wipe_locations std::vector pattern_per_extruder; //!< For each extruder the pattern to print on all layers of the prime tower. - std::vector> pattern_extra_brim_per_layer; //!< For each layer of each extruder with an extra brim, the pattern to be added + std::vector> pattern_extra_brim_per_layer; //!< For each layer of each extruder, the extra pattern to be added for adhesion and/or strength Polygons outer_poly; //!< The outline of the outermost prime tower. - - struct BasePolygon - { - Polygons polygons; - size_t extra_rings; - }; - - std::vector outer_poly_base; //!< The outline of the prime tower for layers having a base + std::vector outer_poly_base; //!< The outline of the layers having extra width for the base public: bool enabled; //!< Whether the prime tower is enabled. @@ -110,17 +103,46 @@ class PrimeTower */ void subtractFromSupport(SliceDataStorage& storage); + /*! + * Get the outer polygon for the given layer, which may be the priming polygon only, or a larger polygon for layers with a base + * + * \param[in] layer_nr The index of the layer + * \return The outer polygon for the prime tower at the given layer + */ const Polygons& getOuterPoly(const LayerIndex& layer_nr) const; + /*! + * Get the outer polygon for the very first layer, which may be the priming polygon only, or a larger polygon if there is a base + */ const Polygons& getGroundPoly() const; private: + /*! + * \see PrimeTower::generatePaths + * + * Generate extra rings around the actual prime rings for a stronger base + * + * \param inset The inner circle of the rings to start generating the rings from + * \param rings The number of rings to add + * \param line_width The actual line width to distance the rings from each other + * \return The generated rings paths + */ static ExtrusionMoves generatePaths_base(const Polygons& inset, size_t rings, coord_t line_width); + /*! + * \see PrimeTower::generatePaths + * + * Generate extra rings inside the given circle for a better adhesion on the first layer + * + * \param outer_poly The outer polygon to start generating the rings from + * \param line_width The actual line width to distance the rings from each other + * \param initial_inset The inset distance to be added to the first generated ring + * \return The generated rings paths + */ static ExtrusionMoves generatePaths_inset(const Polygons& outer_poly, coord_t line_width, coord_t initial_inset); /*! - * \see WipeTower::generatePaths + * \see PrimeTower::generatePaths * * Generate the extrude paths for each extruder on even and odd layers * Fill the ground poly with dense infill. From 0400d0a03fe2ccf534650f3938f1b7c0fc270715 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 13 Oct 2023 11:01:23 +0200 Subject: [PATCH 054/116] Revert dirty fix which does not seem necessary anymore CURA-10783 --- src/LayerPlanBuffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LayerPlanBuffer.cpp b/src/LayerPlanBuffer.cpp index b5bede2665..6551543bdc 100644 --- a/src/LayerPlanBuffer.cpp +++ b/src/LayerPlanBuffer.cpp @@ -429,7 +429,7 @@ void LayerPlanBuffer::insertFinalPrintTempCommand(std::vector& ex return; } - assert((time_window >= -0.001 || last_extruder_plan.estimates.material == 0) && "Time window should always be positive if we actually extrude"); + assert((time_window >= 0 || last_extruder_plan.estimates.material == 0) && "Time window should always be positive if we actually extrude"); // ,layer change . // : ,precool command ,layer change . From 466a1cbfca6ffef0c0a400847bb2dd6e1cceec07 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 13 Oct 2023 11:38:18 +0200 Subject: [PATCH 055/116] More code documentation CURA-10783 --- src/FffGcodeWriter.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 0deaaff908..8c16b8d8bc 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -624,6 +624,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) Polygons raft_outline_path = storage.raftOutline; if (storage.primeTower.enabled) { + // Base layer is shared with prime tower base raft_outline_path = raft_outline_path.unionPolygons(storage.primeTower.getOuterPoly(layer_nr)); } @@ -747,6 +748,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) if (storage.primeTower.enabled) { + // Interface layer excludes prime tower base raft_outline_path = raft_outline_path.difference(storage.primeTower.getOuterPoly(layer_nr)); } @@ -851,6 +853,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) if (storage.primeTower.enabled) { + // Surface layers exclude prime tower base raft_outline_path = raft_outline_path.difference(storage.primeTower.getOuterPoly(layer_nr)); } From 9eab6b4f413dc76e1eab21bc5315214f172f1097 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 13 Oct 2023 11:38:46 +0200 Subject: [PATCH 056/116] Removed useless dirty fix CURA-10783 --- src/raft.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/raft.cpp b/src/raft.cpp index af8daafde0..665cc833f5 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -104,14 +104,7 @@ coord_t Raft::getFillerLayerHeight() return normal_layer_height; } - if (getFillerLayerCount() != 0) - { - return round_divide(getZdiffBetweenRaftAndLayer0(), getFillerLayerCount()); - } - else - { - return mesh_group_settings.get("layer_height"); - } + return round_divide(getZdiffBetweenRaftAndLayer0(), getFillerLayerCount()); } From ae0dcd24b522b1d4984c23fbff33b97c2d2a1e20 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 13 Oct 2023 13:51:02 +0200 Subject: [PATCH 057/116] Re-set dirty crash fix CURA-10783 --- src/LayerPlanBuffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LayerPlanBuffer.cpp b/src/LayerPlanBuffer.cpp index 6551543bdc..b5bede2665 100644 --- a/src/LayerPlanBuffer.cpp +++ b/src/LayerPlanBuffer.cpp @@ -429,7 +429,7 @@ void LayerPlanBuffer::insertFinalPrintTempCommand(std::vector& ex return; } - assert((time_window >= 0 || last_extruder_plan.estimates.material == 0) && "Time window should always be positive if we actually extrude"); + assert((time_window >= -0.001 || last_extruder_plan.estimates.material == 0) && "Time window should always be positive if we actually extrude"); // ,layer change . // : ,precool command ,layer change . From 9e958a99e1e33fc559a776754450342b2cad723f Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 13 Oct 2023 14:39:25 +0200 Subject: [PATCH 058/116] Force prime tower base for raft CURA-10783 --- src/PrimeTower.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 5166fe5bc1..fa291fedc4 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -149,7 +149,8 @@ void PrimeTower::generatePaths_denseInfill() const coord_t layer_height = mesh_group_settings.get("layer_height"); const bool base_enabled = mesh_group_settings.get("prime_tower_brim_enable"); const coord_t base_extra_radius = scene.settings.get("prime_tower_base_size"); - const coord_t base_height = scene.settings.get("prime_tower_base_height"); + const bool has_raft = mesh_group_settings.get("adhesion_type") == EPlatformAdhesion::RAFT; + const coord_t base_height = std::max(scene.settings.get("prime_tower_base_height"), has_raft ? layer_height : 0); const int base_curve_magnitude = mesh_group_settings.get("prime_tower_base_curve_magnitude"); const coord_t line_width = scene.extruders[extruder_order.front()].settings.get("prime_tower_line_width"); @@ -180,7 +181,7 @@ void PrimeTower::generatePaths_denseInfill() } // The most outside extruder is used for the base - if (extruder_nr == extruder_order.front() && base_enabled && base_extra_radius > 0 && base_height > 0) + if (extruder_nr == extruder_order.front() && (base_enabled || has_raft) && base_extra_radius > 0 && base_height > 0) { for (coord_t z = 0; z < base_height; z += layer_height) { From ad1aa1972ad9e33d86f66baee47478cb6e68d9c7 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 3 Oct 2023 12:24:18 +0200 Subject: [PATCH 059/116] 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 060/116] 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 061/116] 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 062/116] 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 063/116] 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 064/116] 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 065/116] 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 066/116] 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 067/116] 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 068/116] 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 069/116] 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 070/116] 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 071/116] 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 072/116] 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 073/116] 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 074/116] 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 075/116] 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 076/116] 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 077/116] 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 078/116] 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 079/116] 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 080/116] 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 081/116] 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 082/116] 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 083/116] 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 084/116] 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 085/116] 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 086/116] 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 087/116] 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 088/116] 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 089/116] 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 090/116] 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 115f0b98e582764561b2a50180e15c39be46da5f Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Mon, 16 Oct 2023 11:04:56 +0200 Subject: [PATCH 091/116] Fix roofing visualisation bug CURA-11140 --- src/settings/MeshPathConfigs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/settings/MeshPathConfigs.cpp b/src/settings/MeshPathConfigs.cpp index aa71d89e07..d91595ce37 100644 --- a/src/settings/MeshPathConfigs.cpp +++ b/src/settings/MeshPathConfigs.cpp @@ -38,7 +38,7 @@ MeshPathConfigs::MeshPathConfigs(const SliceMeshStorage& mesh, const coord_t lay .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, + , insetX_roofing_config{ .type = PrintFeatureType::InnerWall, .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]), From 3bea2989ad1c0b2cb4e8a5cec651fbba6bbacb28 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 17 Oct 2023 15:52:37 +0200 Subject: [PATCH 092/116] 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 093/116] 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 094/116] 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 095/116] 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 096/116] 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 097/116] 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 098/116] 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 099/116] 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 9e1e888d4e6d7f49b9db2e55ea79504fb5527fdb Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 18 Oct 2023 13:13:49 +0200 Subject: [PATCH 100/116] Code cleaning/readability CURA-10783 --- .clang-format | 6 +++--- include/PrimeTower.h | 15 ++++++++++----- include/SkirtBrim.h | 4 ++-- src/PrimeTower.cpp | 20 ++++++++++---------- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/.clang-format b/.clang-format index 5d90caa166..e5f6fc2257 100644 --- a/.clang-format +++ b/.clang-format @@ -59,11 +59,11 @@ ForEachMacros: IncludeBlocks: Regroup IncludeCategories: - Priority: 2 - Regex: ^<(scripta|spdlog|range|fmt|Arcus|agrpc|grpc|boost)/ + Regex: '^<(scripta|spdlog|range|fmt|Arcus|agrpc|grpc|boost)/.*' - Priority: 3 - Regex: ^(<|"(gtest|gmock|isl|json)/) + Regex: '^((<|")(gtest|gmock|isl|json)/)' - Priority: 1 - Regex: .* + Regex: '^<.*' IncludeIsMainRegex: (Test)?$ IndentCaseLabels: false IndentWidth: 4 diff --git a/include/PrimeTower.h b/include/PrimeTower.h index 2201ce7544..0ae2350b6a 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -4,11 +4,12 @@ #ifndef PRIME_TOWER_H #define PRIME_TOWER_H +#include + #include "settings/types/LayerIndex.h" #include "utils/polygon.h" // Polygons #include "utils/polygonUtils.h" -#include namespace cura { @@ -30,7 +31,11 @@ class PrimeTower Polygons polygons; Polygons lines; }; - unsigned int extruder_count; //!< Number of extruders + + using MovesByExtruder = std::vector; + using MovesByLayer = std::vector; + + size_t extruder_count; //!< Number of extruders bool wipe_from_middle; //!< Whether to wipe on the inside of the hollow prime tower Point middle; //!< The middle of the prime tower @@ -40,8 +45,8 @@ class PrimeTower std::vector prime_tower_start_locations; //!< The differernt locations where to pre-wipe the active nozzle const unsigned int number_of_prime_tower_start_locations = 21; //!< The required size of \ref PrimeTower::wipe_locations - std::vector pattern_per_extruder; //!< For each extruder the pattern to print on all layers of the prime tower. - std::vector> pattern_extra_brim_per_layer; //!< For each layer of each extruder, the extra pattern to be added for adhesion and/or strength + MovesByExtruder prime_moves; //!< For each extruder, the moves to be processed for actual priming. + MovesByLayer base_extra_moves; //!< For each layer and each extruder, the extra moves to be processed for better adhesion/strength Polygons outer_poly; //!< The outline of the outermost prime tower. std::vector outer_poly_base; //!< The outline of the layers having extra width for the base @@ -58,7 +63,7 @@ class PrimeTower * This is the spatial order from outside to inside. This is NOT the actual * order in time in which they are printed. */ - std::vector extruder_order; + std::vector extruder_order; /*! * \brief Creates a prime tower instance that will determine where and how diff --git a/include/SkirtBrim.h b/include/SkirtBrim.h index fa41df0999..896e4aac45 100644 --- a/include/SkirtBrim.h +++ b/include/SkirtBrim.h @@ -4,13 +4,13 @@ #ifndef SKIRT_BRIM_H #define SKIRT_BRIM_H +#include + #include "ExtruderTrain.h" #include "settings/EnumSettings.h" #include "sliceDataStorage.h" #include "utils/Coord_t.h" -#include - namespace cura { diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index fa291fedc4..a9c1461cf1 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -3,6 +3,9 @@ #include "PrimeTower.h" +#include +#include + #include "Application.h" //To get settings. #include "ExtruderTrain.h" #include "LayerPlan.h" @@ -14,9 +17,6 @@ #include "raft.h" #include "sliceDataStorage.h" -#include -#include - #define CIRCLE_RESOLUTION 32 // The number of vertices in each circle. @@ -154,8 +154,8 @@ void PrimeTower::generatePaths_denseInfill() const int base_curve_magnitude = mesh_group_settings.get("prime_tower_base_curve_magnitude"); const coord_t line_width = scene.extruders[extruder_order.front()].settings.get("prime_tower_line_width"); - pattern_per_extruder.resize(extruder_count); - pattern_extra_brim_per_layer.resize(extruder_count); + prime_moves.resize(extruder_count); + base_extra_moves.resize(extruder_count); coord_t cumulative_inset = 0; // Each tower shape is going to be printed inside the other. This is the inset we're doing for each extruder. for (size_t extruder_nr : extruder_order) @@ -164,7 +164,7 @@ void PrimeTower::generatePaths_denseInfill() const coord_t required_volume = MM3_2INT(scene.extruders[extruder_nr].settings.get("prime_tower_min_volume")); const Ratio flow = scene.extruders[extruder_nr].settings.get("prime_tower_flow"); coord_t current_volume = 0; - ExtrusionMoves& pattern = pattern_per_extruder[extruder_nr]; + ExtrusionMoves& pattern = prime_moves[extruder_nr]; // Create the walls of the prime tower. unsigned int wall_nr = 0; @@ -195,7 +195,7 @@ void PrimeTower::generatePaths_denseInfill() extra_radius = line_width * extra_rings; outer_poly_base.push_back(outer_poly.offset(extra_radius)); - pattern_extra_brim_per_layer[extruder_nr].push_back(generatePaths_base(outer_poly, extra_rings, line_width)); + base_extra_moves[extruder_nr].push_back(generatePaths_base(outer_poly, extra_rings, line_width)); } } @@ -207,7 +207,7 @@ void PrimeTower::generatePaths_denseInfill() ExtrusionMoves pattern = generatePaths_inset(outer_poly, line_width, cumulative_inset); if (! pattern.polygons.empty() || ! pattern.lines.empty()) { - pattern_extra_brim_per_layer[extruder_nr].push_back(pattern); + base_extra_moves[extruder_nr].push_back(pattern); } } } @@ -280,12 +280,12 @@ void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t ext { // Actual prime pattern const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; - const ExtrusionMoves& pattern = pattern_per_extruder[extruder_nr]; + const ExtrusionMoves& pattern = prime_moves[extruder_nr]; gcode_layer.addPolygonsByOptimizer(pattern.polygons, config); gcode_layer.addLinesByOptimizer(pattern.lines, config, SpaceFillType::Lines); } - const std::vector& pattern_extra_brim = pattern_extra_brim_per_layer[extruder_nr]; + const std::vector& pattern_extra_brim = base_extra_moves[extruder_nr]; if (absolute_layer_number < pattern_extra_brim.size()) { // Extra rings for stronger base From e58f31c3cfbe331dfa1910e913e05642ba5932a7 Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Wed, 18 Oct 2023 11:14:33 +0000 Subject: [PATCH 101/116] Applied clang-format. --- include/sliceDataStorage.h | 8 ++++---- src/FffGcodeWriter.cpp | 24 ++++++++++++------------ src/FffPolygonGenerator.cpp | 4 ++-- src/LayerPlanBuffer.cpp | 4 ++-- src/SkirtBrim.cpp | 4 ++-- src/TreeModelVolumes.cpp | 10 +++++----- src/raft.cpp | 4 ++-- src/sliceDataStorage.cpp | 4 ++-- 8 files changed, 31 insertions(+), 31 deletions(-) diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index c3313e801a..6a362522ef 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -4,6 +4,10 @@ #ifndef SLICE_DATA_STORAGE_H #define SLICE_DATA_STORAGE_H +#include +#include +#include + #include "PrimeTower.h" #include "RetractionConfig.h" #include "SupportInfillPart.h" @@ -18,10 +22,6 @@ #include "utils/NoCopy.h" #include "utils/polygon.h" -#include -#include -#include - // libArachne #include "utils/ExtrusionLine.h" diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 78a541c00e..db904f0e3a 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3,6 +3,18 @@ #include "FffGcodeWriter.h" +#include +#include // numeric_limits +#include +#include +#include +#include + +#include +#include +#include +#include + #include "Application.h" #include "ExtruderTrain.h" #include "FffProcessor.h" @@ -21,18 +33,6 @@ #include "utils/math.h" #include "utils/orderOptimizer.h" -#include -#include -#include -#include - -#include -#include // numeric_limits -#include -#include -#include -#include - namespace cura { diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index 640a563284..3b1a5e4c38 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -1,14 +1,14 @@ // Copyright (c) 2023 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher -#include - #include #include #include // ifstream.good() #include // multimap (ordered map allowing duplicate keys) #include +#include + // Code smell: Order of the includes is important here, probably due to some forward declarations which might be masking some undefined behaviours // clang-format off #include "Application.h" diff --git a/src/LayerPlanBuffer.cpp b/src/LayerPlanBuffer.cpp index b5bede2665..d5a033a136 100644 --- a/src/LayerPlanBuffer.cpp +++ b/src/LayerPlanBuffer.cpp @@ -3,6 +3,8 @@ #include "LayerPlanBuffer.h" +#include + #include "Application.h" //To flush g-code through the communication channel. #include "ExtruderTrain.h" #include "FffProcessor.h" @@ -11,8 +13,6 @@ #include "communication/Communication.h" //To flush g-code through the communication channel. #include "gcodeExport.h" -#include - namespace cura { diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 522e0994f5..4b77b449d3 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -3,6 +3,8 @@ #include "SkirtBrim.h" +#include + #include "Application.h" #include "ExtruderTrain.h" #include "Slice.h" @@ -13,8 +15,6 @@ #include "utils/PolylineStitcher.h" #include "utils/Simplify.h" //Simplifying the brim/skirt at every inset. -#include - namespace cura { diff --git a/src/TreeModelVolumes.cpp b/src/TreeModelVolumes.cpp index aea31de82c..4604967baf 100644 --- a/src/TreeModelVolumes.cpp +++ b/src/TreeModelVolumes.cpp @@ -3,6 +3,11 @@ #include "TreeModelVolumes.h" +#include +#include +#include +#include + #include "TreeSupport.h" #include "TreeSupportEnums.h" #include "progress/Progress.h" @@ -10,11 +15,6 @@ #include "utils/ThreadPool.h" #include "utils/algorithm.h" -#include -#include -#include -#include - namespace cura { diff --git a/src/raft.cpp b/src/raft.cpp index 665cc833f5..e13836b43f 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -3,6 +3,8 @@ #include "raft.h" +#include + #include "Application.h" //To get settings. #include "ExtruderTrain.h" #include "Slice.h" @@ -10,8 +12,6 @@ #include "sliceDataStorage.h" #include "utils/math.h" -#include - namespace cura { diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index c560a2b675..b9b978d557 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -3,6 +3,8 @@ #include "sliceDataStorage.h" +#include + #include "Application.h" //To get settings. #include "ExtruderTrain.h" #include "FffProcessor.h" //To create a mesh group with if none is provided. @@ -14,8 +16,6 @@ #include "raft.h" #include "utils/math.h" //For PI. -#include - namespace cura { From 87fbc0aca0dfd1a90eee2d36c20ef98aa7b62460 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 19 Oct 2023 10:15:45 +0200 Subject: [PATCH 102/116] Moved and optimized generic geometric methods --- include/PrimeTower.h | 32 +--- include/utils/polygonUtils.h | 330 ++++++++++++++++++++++------------- src/PrimeTower.cpp | 53 ++---- src/utils/polygonUtils.cpp | 44 ++++- 4 files changed, 251 insertions(+), 208 deletions(-) diff --git a/include/PrimeTower.h b/include/PrimeTower.h index 0ae2350b6a..a493cfb3be 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -26,13 +26,7 @@ class LayerPlan; class PrimeTower { private: - struct ExtrusionMoves - { - Polygons polygons; - Polygons lines; - }; - - using MovesByExtruder = std::vector; + using MovesByExtruder = std::vector; using MovesByLayer = std::vector; size_t extruder_count; //!< Number of extruders @@ -122,30 +116,6 @@ class PrimeTower const Polygons& getGroundPoly() const; private: - /*! - * \see PrimeTower::generatePaths - * - * Generate extra rings around the actual prime rings for a stronger base - * - * \param inset The inner circle of the rings to start generating the rings from - * \param rings The number of rings to add - * \param line_width The actual line width to distance the rings from each other - * \return The generated rings paths - */ - static ExtrusionMoves generatePaths_base(const Polygons& inset, size_t rings, coord_t line_width); - - /*! - * \see PrimeTower::generatePaths - * - * Generate extra rings inside the given circle for a better adhesion on the first layer - * - * \param outer_poly The outer polygon to start generating the rings from - * \param line_width The actual line width to distance the rings from each other - * \param initial_inset The inset distance to be added to the first generated ring - * \return The generated rings paths - */ - static ExtrusionMoves generatePaths_inset(const Polygons& outer_poly, coord_t line_width, coord_t initial_inset); - /*! * \see PrimeTower::generatePaths * diff --git a/include/utils/polygonUtils.h b/include/utils/polygonUtils.h index 13786e71c7..c4ea2c2db6 100644 --- a/include/utils/polygonUtils.h +++ b/include/utils/polygonUtils.h @@ -1,20 +1,20 @@ -//Copyright (c) 2021 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2021 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef UTILS_POLYGON_UTILS_H #define UTILS_POLYGON_UTILS_H #include // function #include -#include #include // unique_ptr +#include -#include "polygon.h" -#include "SparsePointGridInclusive.h" -#include "SparseLineGrid.h" #include "PolygonsPointIndex.h" +#include "SparseLineGrid.h" +#include "SparsePointGridInclusive.h" +#include "polygon.h" -namespace cura +namespace cura { /*! @@ -26,10 +26,23 @@ struct ClosestPolygonPoint ConstPolygonPointer poly; //!< Polygon in which the result was found (or nullptr if no result was found) unsigned int poly_idx; //!< The index of the polygon in some Polygons where ClosestPolygonPoint::poly can be found unsigned int point_idx; //!< Index to the first point in the polygon of the line segment on which the result was found - ClosestPolygonPoint(Point p, int pos, ConstPolygonRef poly) : location(p), poly(poly), poly_idx(NO_INDEX), point_idx(pos) {}; - ClosestPolygonPoint(Point p, int pos, ConstPolygonRef poly, int poly_idx) : location(p), poly(poly), poly_idx(poly_idx), point_idx(pos) {}; - ClosestPolygonPoint(ConstPolygonRef poly) : poly(poly), poly_idx(NO_INDEX), point_idx(NO_INDEX) {}; - ClosestPolygonPoint() : poly_idx(NO_INDEX), point_idx(NO_INDEX) {}; + ClosestPolygonPoint(Point p, int pos, ConstPolygonRef poly) + : location(p) + , poly(poly) + , poly_idx(NO_INDEX) + , point_idx(pos){}; + ClosestPolygonPoint(Point p, int pos, ConstPolygonRef poly, int poly_idx) + : location(p) + , poly(poly) + , poly_idx(poly_idx) + , point_idx(pos){}; + ClosestPolygonPoint(ConstPolygonRef poly) + : poly(poly) + , poly_idx(NO_INDEX) + , point_idx(NO_INDEX){}; + ClosestPolygonPoint() + : poly_idx(NO_INDEX) + , point_idx(NO_INDEX){}; Point p() const { // conformity with other classes return location; @@ -50,7 +63,7 @@ struct ClosestPolygonPoint namespace std { -template <> +template<> struct hash { size_t operator()(const cura::ClosestPolygonPoint& cpp) const @@ -58,12 +71,12 @@ struct hash return std::hash()(cpp.p()); } }; -}//namespace std +} // namespace std namespace std { -template +template struct hash> { size_t operator()(const std::pair& pair) const @@ -71,7 +84,7 @@ struct hash> return 31 * std::hash()(pair.first) + 59 * std::hash()(pair.second); } }; -}//namespace std +} // namespace std namespace cura @@ -88,18 +101,18 @@ struct GivenDistPoint typedef SparseLineGrid LocToLineGrid; -class PolygonUtils +class PolygonUtils { public: static const std::function no_penalty_function; //!< Function always returning zero /*! * compute the length of a segment of a polygon - * + * * if \p end == \p start then the full polygon is taken - * + * * \warning assumes that start and end lie on the same polygon! - * + * * \param start The start vertex of the segment * \param end the end vertex of the segment * \return the total length of all the line segments in between the two vertices. @@ -108,12 +121,12 @@ class PolygonUtils /*! * Generate evenly spread out dots along a segment of a polygon - * + * * Start at a distance from \p start and end at a distance from \p end, * unless \p end == \p start; then that point is in the result - * + * * \warning Assumes that start and end lie on the same polygon! - * + * * \param start The start vertex of the segment * \param end the end vertex of the segment * \param n_dots number of dots to spread out @@ -131,48 +144,54 @@ class PolygonUtils /*! * Whether a polygon intersects with a line-segment. If true, the closest collision point to 'b' is stored in the result. */ - static bool lineSegmentPolygonsIntersection(const Point& a, const Point& b, const Polygons& current_outlines, const LocToLineGrid& outline_locator, Point& result, const coord_t within_max_dist); + static bool lineSegmentPolygonsIntersection( + const Point& a, + const Point& b, + const Polygons& current_outlines, + const LocToLineGrid& outline_locator, + Point& result, + const coord_t within_max_dist); /*! * Get the normal of a boundary point, pointing outward. * Only the direction is set. * Nothing is said about the length of the vector returned. - * + * * \param poly The polygon. * \param point_idx The index of the point in the polygon. */ static Point getVertexInwardNormal(ConstPolygonRef poly, unsigned int point_idx); /*! - * Get a point from the \p poly with a given \p offset. - * - * \param poly The polygon. - * \param point_idx The index of the point in the polygon. - * \param offset The distance the point has to be moved outward from the polygon. - * \return A point at the given distance inward from the point on the boundary polygon. - */ + * Get a point from the \p poly with a given \p offset. + * + * \param poly The polygon. + * \param point_idx The index of the point in the polygon. + * \param offset The distance the point has to be moved outward from the polygon. + * \return A point at the given distance inward from the point on the boundary polygon. + */ static Point getBoundaryPointWithOffset(ConstPolygonRef poly, unsigned int point_idx, int64_t offset); /*! * Move a point away from the boundary by looking at the boundary normal of the nearest vert. - * + * * \param point_on_boundary The object holding the point on the boundary along with the information of which line segment the point is on. * \param offset The distance the point has to be moved inward from the polygon. */ static Point moveInsideDiagonally(ClosestPolygonPoint point_on_boundary, int64_t inset); /*! - * Moves the point \p from onto the nearest polygon or leaves the point as-is, when the comb boundary is not within the root of \p max_dist2 distance. - * Given a \p distance more than zero, the point will end up inside, and conversely outside. - * When the point is already in/outside by more than \p distance, \p from is unaltered, but the polygon is returned. - * When the point is in/outside by less than \p distance, \p from is moved to the correct place. - * - * \param polygons The polygons onto which to move the point - * \param from[in,out] The point to move. - * \param distance The distance by which to move the point. - * \param max_dist2 The squared maximal allowed distance from the point to the nearest polygon. - * \return The index to the polygon onto which we have moved the point. - */ + * Moves the point \p from onto the nearest polygon or leaves the point as-is, when the comb boundary is not within the root of \p max_dist2 distance. + * Given a \p distance more than zero, the point will end up inside, and conversely outside. + * When the point is already in/outside by more than \p distance, \p from is unaltered, but the polygon is returned. + * When the point is in/outside by less than \p distance, \p from is moved to the correct place. + * + * \param polygons The polygons onto which to move the point + * \param from[in,out] The point to move. + * \param distance The distance by which to move the point. + * \param max_dist2 The squared maximal allowed distance from the point to the nearest polygon. + * \return The index to the polygon onto which we have moved the point. + */ static unsigned int moveInside(const Polygons& polygons, Point& from, int distance = 0, int64_t max_dist2 = std::numeric_limits::max()); /** @@ -198,11 +217,11 @@ class PolygonUtils * Given a \p distance more than zero, the point will end up inside, and conversely outside. * When the point is already in/outside by more than \p distance, \p from is unaltered, but the polygon is returned. * When the point is in/outside by less than \p distance, \p from is moved to the correct place. - * + * * \warning If \p loc_to_line_grid is used, it's best to have all and only \p polygons in there. * If \p from is not closest to \p polygons this function may * return a ClosestPolygonPoint on a polygon in \p loc_to_line_grid which is not in \p polygons. - * + * * \param polygons The polygons onto which to move the point * \param from[in,out] The point to move. * \param distance The distance by which to move the point. @@ -212,18 +231,25 @@ class PolygonUtils * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The point on the polygon closest to \p from */ - static ClosestPolygonPoint moveInside2(const Polygons& polygons, Point& from, const int distance = 0, const int64_t max_dist2 = std::numeric_limits::max(), const Polygons* loc_to_line_polygons = nullptr, const LocToLineGrid* loc_to_line_grid = nullptr, const std::function& penalty_function = no_penalty_function); + static ClosestPolygonPoint moveInside2( + const Polygons& polygons, + Point& from, + const int distance = 0, + const int64_t max_dist2 = std::numeric_limits::max(), + const Polygons* loc_to_line_polygons = nullptr, + const LocToLineGrid* loc_to_line_grid = nullptr, + const std::function& penalty_function = no_penalty_function); /*! * Moves the point \p from onto the nearest segment of \p polygon or leaves the point as-is, when the comb boundary is not within the root of \p max_dist2 distance. * Given a \p distance more than zero, the point will end up inside, and conversely outside. * When the point is already in/outside by more than \p distance, \p from is unaltered, but the polygon is returned. * When the point is in/outside by less than \p distance, \p from is moved to the correct place. - * + * * \warning When a \p loc_to_line is given this function only considers nearby elements. * Even when the penalty function favours elements farther away. * Also using the \p loc_to_line_grid automatically considers \p all_polygons - * + * * \param loc_to_line_polygons All polygons which are present in the \p loc_to_line_grid of which \p polygon is an element * \param polygon The polygon onto which to move the point * \param from[in,out] The point to move. @@ -233,16 +259,23 @@ class PolygonUtils * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The point on the polygon closest to \p from */ - static ClosestPolygonPoint moveInside2(const Polygons& loc_to_line_polygons, ConstPolygonRef polygon, Point& from, const int distance = 0, const int64_t max_dist2 = std::numeric_limits::max(), const LocToLineGrid* loc_to_line_grid = nullptr, const std::function& penalty_function = no_penalty_function); + static ClosestPolygonPoint moveInside2( + const Polygons& loc_to_line_polygons, + ConstPolygonRef polygon, + Point& from, + const int distance = 0, + const int64_t max_dist2 = std::numeric_limits::max(), + const LocToLineGrid* loc_to_line_grid = nullptr, + const std::function& penalty_function = no_penalty_function); /*! * The opposite of moveInside. - * + * * Moves the point \p from onto the nearest polygon or leaves the point as-is, when the comb boundary is not within \p distance. * Given a \p distance more than zero, the point will end up outside, and conversely inside. * When the point is already in/outside by more than \p distance, \p from is unaltered, but the polygon is returned. * When the point is in/outside by less than \p distance, \p from is moved to the correct place. - * + * * \param polygons The polygons onto which to move the point * \param from[in,out] The point to move. * \param distance The distance by which to move the point. @@ -251,23 +284,23 @@ class PolygonUtils * \return The index to the polygon onto which we have moved the point. */ static unsigned int moveOutside(const Polygons& polygons, Point& from, int distance = 0, int64_t max_dist2 = std::numeric_limits::max()); - + /*! * Compute a point at a distance from a point on the boundary in orthogonal direction to the boundary. * Given a \p distance more than zero, the point will end up inside, and conversely outside. - * + * * \param cpp The object holding the point on the boundary along with the information of which line segment the point is on. * \param distance The distance by which to move the point. * \return A point at a \p distance from the point in \p cpp orthogonal to the boundary there. */ static Point moveInside(const ClosestPolygonPoint& cpp, const int distance); - + /*! * The opposite of moveInside. - * + * * Compute a point at a distance from a point on the boundary in orthogonal direction to the boundary. * Given a \p distance more than zero, the point will end up outside, and conversely inside. - * + * * \param cpp The object holding the point on the boundary along with the information of which line segment the point is on. * \param distance The distance by which to move the point. * \return A point at a \p distance from the point in \p cpp orthogonal to the boundary there. @@ -279,15 +312,15 @@ class PolygonUtils * Given a \p distance more than zero, the point will end up inside, and conversely outside. * When the point is already in/outside by more than \p distance, \p from is unaltered, but the polygon is returned. * When the point is in/outside by less than \p distance, \p from is moved to the correct place. - * + * * \warning May give false positives. - * Some checking is done to make sure we end up inside the polygon, + * Some checking is done to make sure we end up inside the polygon, * but it might still be the case that we end up outside: * when the closest point on the boundary is very close to another polygon - * + * * \warning When using a \p loc_to_line_grid which contains more polygons than just \p polygons, * the results is only correct if \p from is already closest to \p polygons, rather than other polygons in the \p loc_to_line_grid. - * + * * \param polygons The polygons onto which to move the point * \param from[in,out] The point to move. * \param preferred_dist_inside The preferred distance from the boundary to the point @@ -297,22 +330,29 @@ class PolygonUtils * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The point on the polygon closest to \p from */ - static ClosestPolygonPoint ensureInsideOrOutside(const Polygons& polygons, Point& from, int preferred_dist_inside, int64_t max_dist2 = std::numeric_limits::max(), const Polygons* loc_to_line_polygons = nullptr, const LocToLineGrid* loc_to_line_grid = nullptr, const std::function& penalty_function = no_penalty_function); + static ClosestPolygonPoint ensureInsideOrOutside( + const Polygons& polygons, + Point& from, + int preferred_dist_inside, + int64_t max_dist2 = std::numeric_limits::max(), + const Polygons* loc_to_line_polygons = nullptr, + const LocToLineGrid* loc_to_line_grid = nullptr, + const std::function& penalty_function = no_penalty_function); /*! * Moves the point \p from onto the nearest polygon or leaves the point as-is, when the comb boundary is not within \p distance. * Given a \p distance more than zero, the point will end up inside, and conversely outside. * When the point is already in/outside by more than \p distance, \p from is unaltered, but the polygon is returned. * When the point is in/outside by less than \p distance, \p from is moved to the correct place. - * + * * \warning May give false positives. - * Some checking is done to make sure we end up inside the polygon, + * Some checking is done to make sure we end up inside the polygon, * but it might still be the case that we end up outside: * when the closest point on the boundary is very close to another polygon - * + * * \warning When using a \p loc_to_line_grid which contains more polygons than just \p polygons, * the results is only correct if \p from is already closest to \p polygons, rather than other polygons in the \p loc_to_line_grid. - * + * * \param polygons The polygons onto which to move the point * \param from[in,out] The point to move. * \param closest_polygon_point The point on \p polygons closest to \p from @@ -322,49 +362,56 @@ class PolygonUtils * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The point on the polygon closest to \p from */ - static ClosestPolygonPoint ensureInsideOrOutside(const Polygons& polygons, Point& from, const ClosestPolygonPoint& closest_polygon_point, int preferred_dist_inside, const Polygons* loc_to_line_polygons = nullptr, const LocToLineGrid* loc_to_line_grid = nullptr, const std::function& penalty_function = no_penalty_function); + static ClosestPolygonPoint ensureInsideOrOutside( + const Polygons& polygons, + Point& from, + const ClosestPolygonPoint& closest_polygon_point, + int preferred_dist_inside, + const Polygons* loc_to_line_polygons = nullptr, + const LocToLineGrid* loc_to_line_grid = nullptr, + const std::function& penalty_function = no_penalty_function); /*! - * - * \warning Assumes \p poly1_result and \p poly2_result have their pos and poly fields initialized! - */ + * + * \warning Assumes \p poly1_result and \p poly2_result have their pos and poly fields initialized! + */ static void walkToNearestSmallestConnection(ClosestPolygonPoint& poly1_result, ClosestPolygonPoint& poly2_result); /*! - * Find the nearest closest point on a polygon from a given index. - * - * \param from The point from which to get the smallest distance. - * \param polygon The polygon on which to find the point with the smallest distance. - * \param start_idx The index of the point in the polygon from which to start looking. - * \return The nearest point from \p start_idx going along the \p polygon (in both directions) with a locally minimal distance to \p from. - */ + * Find the nearest closest point on a polygon from a given index. + * + * \param from The point from which to get the smallest distance. + * \param polygon The polygon on which to find the point with the smallest distance. + * \param start_idx The index of the point in the polygon from which to start looking. + * \return The nearest point from \p start_idx going along the \p polygon (in both directions) with a locally minimal distance to \p from. + */ static ClosestPolygonPoint findNearestClosest(Point from, ConstPolygonRef polygon, int start_idx); /*! - * Find the nearest closest point on a polygon from a given index walking in one direction along the polygon. - * - * \param from The point from which to get the smallest distance. - * \param polygon The polygon on which to find the point with the smallest distance. - * \param start_idx The index of the point in the polygon from which to start looking. - * \param direction The direction to walk: 1 for walking along the \p polygon, -1 for walking in opposite direction - * \return The nearest point from \p start_idx going along the \p polygon with a locally minimal distance to \p from. - */ + * Find the nearest closest point on a polygon from a given index walking in one direction along the polygon. + * + * \param from The point from which to get the smallest distance. + * \param polygon The polygon on which to find the point with the smallest distance. + * \param start_idx The index of the point in the polygon from which to start looking. + * \param direction The direction to walk: 1 for walking along the \p polygon, -1 for walking in opposite direction + * \return The nearest point from \p start_idx going along the \p polygon with a locally minimal distance to \p from. + */ static ClosestPolygonPoint findNearestClosest(const Point from, ConstPolygonRef polygon, int start_idx, int direction); /*! * Find the point closest to \p from in all polygons in \p polygons. - * + * * \note The penalty term is applied to the *squared* distance score - * + * * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. */ static ClosestPolygonPoint findClosest(Point from, const Polygons& polygons, const std::function& penalty_function = no_penalty_function); - + /*! * Find the point closest to \p from in the polygon \p polygon. - * + * * \note The penalty term is applied to the *squared* distance score - * + * * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. */ static ClosestPolygonPoint findClosest(Point from, ConstPolygonRef polygon, const std::function& penalty_function = no_penalty_function); @@ -387,9 +434,9 @@ class PolygonUtils /*! * Create a SparsePointGridInclusive mapping from locations to line segments occurring in the \p polygons - * + * * \warning The caller of this function is responsible for deleting the returned object - * + * * \param polygons The polygons for which to create the mapping * \param square_size The cell size used to bundle line segments (also used to chop up lines so that multiple cells contain the same long line) * \return A bucket grid mapping spatial locations to poly-point indices into \p polygons @@ -398,57 +445,63 @@ class PolygonUtils /*! * Find the line segment closest to a given point \p from within a cell-block of a size defined in the SparsePointGridInclusive \p loc_to_line - * + * * \note The penalty term is applied to the *squared* distance score. * Note also that almost only nearby points are considered even when the penalty function would favour points farther away. - * + * * \param from The location to find a polygon edge close to * \param polygons The polygons for which the \p loc_to_line has been built up - * \param loc_to_line A SparsePointGridInclusive mapping locations to starting vertices of line segmetns of the \p polygons + * \param loc_to_line A SparsePointGridInclusive mapping locations to starting vertices of line segmetns of the \p polygons * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The nearest point on the polygon if the polygon was within a distance equal to the cell_size of the SparsePointGridInclusive */ - static std::optional findClose(Point from, const Polygons& polygons, const LocToLineGrid& loc_to_line, const std::function& penalty_function = no_penalty_function); + static std::optional + findClose(Point from, const Polygons& polygons, const LocToLineGrid& loc_to_line, const std::function& penalty_function = no_penalty_function); /*! * Find the line segment closest to any point on \p from within cell-blocks of a size defined in the SparsePointGridInclusive \p destination_loc_to_line - * + * * \note The penalty term is applied to the *squared* distance score. * Note also that almost only nearby points are considered even when the penalty function would favour points farther away. - * + * * \param from The polygon for which to find a polygon edge close to * \param destination The polygons for which the \p destination_loc_to_line has been built up - * \param destination_loc_to_line A SparsePointGridInclusive mapping locations to starting vertices of line segments of the \p destination + * \param destination_loc_to_line A SparsePointGridInclusive mapping locations to starting vertices of line segments of the \p destination * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. - * \return A collection of near crossing from the \p from polygon to the \p destination polygon. Each element in the sollection is a pair with as first a cpp in the \p from polygon and as second a cpp in the \p destination polygon. + * \return A collection of near crossing from the \p from polygon to the \p destination polygon. Each element in the sollection is a pair with as first a cpp in the \p from + * polygon and as second a cpp in the \p destination polygon. */ - static std::vector> findClose(ConstPolygonRef from, const Polygons& destination, const LocToLineGrid& destination_loc_to_line, const std::function& penalty_function = no_penalty_function); + static std::vector> findClose( + ConstPolygonRef from, + const Polygons& destination, + const LocToLineGrid& destination_loc_to_line, + const std::function& penalty_function = no_penalty_function); /*! * Checks whether a given line segment collides with polygons as given in a loc_to_line grid. - * + * * If the line segment doesn't intersect with any edge of the polygon, but * merely touches it, a collision is also reported. For instance, a * collision is reported when the an endpoint of the line is exactly on the * polygon, and when the line coincides with an edge. - * + * * \param[in] from The start point * \param[in] to The end point - * \param[in] loc_to_line A SparsePointGridInclusive mapping locations to starting vertices of line segmetns of the \p polygons + * \param[in] loc_to_line A SparsePointGridInclusive mapping locations to starting vertices of line segmetns of the \p polygons * \param[out] collision_result (optional) The polygons segment intersecting with the line segment * \return whether the line segment collides with the boundary of the polygons */ static bool polygonCollidesWithLineSegment(const Point from, const Point to, const LocToLineGrid& loc_to_line, PolygonsPointIndex* collision_result = nullptr); /*! - * Find the next point (going along the direction of the polygon) with a distance \p dist from the point \p from within the \p poly. - * Returns whether another point could be found within the \p poly which can be found before encountering the point at index \p start_idx. - * The point \p from and the polygon \p poly are assumed to lie on the same plane. - * - * \param from The point from whitch to find a point on the polygon satisfying the conditions - * \param start_idx the index of the prev poly point on the poly. - * \param poly_start_idx The index of the point in the polygon which is to be handled as the start of the polygon. No point further than this point will be the result. - */ + * Find the next point (going along the direction of the polygon) with a distance \p dist from the point \p from within the \p poly. + * Returns whether another point could be found within the \p poly which can be found before encountering the point at index \p start_idx. + * The point \p from and the polygon \p poly are assumed to lie on the same plane. + * + * \param from The point from whitch to find a point on the polygon satisfying the conditions + * \param start_idx the index of the prev poly point on the poly. + * \param poly_start_idx The index of the point in the polygon which is to be handled as the start of the polygon. No point further than this point will be the result. + */ static bool getNextPointWithDistance(Point from, int64_t dist, ConstPolygonRef poly, int start_idx, int poly_start_idx, GivenDistPoint& result); /*! @@ -458,10 +511,10 @@ class PolygonUtils /*! * Get the point on a polygon which intersects a line parallel to a line going through the starting point and through another point. - * + * * Note that the looking direction \p forward doesn't neccesarily determine on which side of the line we cross a parallel line. * Depending on the geometry of the polygon the next intersection may be left or right of the input line. - * + * * \param start The starting point of the search and the starting point of the line * \param line_to The end point of the line * \param dist The distance from the parallel line to the line defined by the previous two parameters @@ -474,12 +527,12 @@ class PolygonUtils * Checks whether a given line segment collides with a given polygon(s). * The transformed_startPoint and transformed_endPoint should have the same * Y coordinate. - * + * * If the line segment doesn't intersect with any edge of the polygon, but * merely touches it, a collision is also reported. For instance, a * collision is reported when the an endpoint of the line is exactly on the * polygon, and when the line coincides with an edge. - * + * * \param poly The polygon * \param transformed_startPoint The start point transformed such that it is * on the same horizontal line as the end point @@ -494,12 +547,12 @@ class PolygonUtils /*! * Checks whether a given line segment collides with a given polygon(s). - * + * * If the line segment doesn't intersect with any edge of the polygon, but * merely touches it, a collision is also reported. For instance, a * collision is reported when the an endpoint of the line is exactly on the * polygon, and when the line coincides with an edge. - * + * * \param poly The polygon * \param startPoint The start point * \param endPoint The end point @@ -512,12 +565,12 @@ class PolygonUtils * Checks whether a given line segment collides with a given polygon(s). * The transformed_startPoint and transformed_endPoint should have the same * Y coordinate. - * + * * If the line segment doesn't intersect with any edge of the polygon, but * merely touches it, a collision is also reported. For instance, a * collision is reported when the an endpoint of the line is exactly on the * polygon, and when the line coincides with an edge. - * + * * \param poly The polygon * \param transformed_startPoint The start point transformed such that it is * on the same horizontal line as the end point @@ -532,12 +585,12 @@ class PolygonUtils /*! * Checks whether a given line segment collides with a given polygon(s). - * + * * If the line segment doesn't intersect with any edge of the polygon, but * merely touches it, a collision is also reported. For instance, a * collision is reported when the an endpoint of the line is exactly on the * polygon, and when the line coincides with an edge. - * + * * \param poly The polygon * \param startPoint The start point * \param endPoint The end point @@ -573,7 +626,11 @@ class PolygonUtils * \param[in] possible_adjacent_polys The vector of polygons we are testing. * \param[in] max_gap Polygons must be closer together than this distance to be considered adjacent. */ - static void findAdjacentPolygons(std::vector& adjacent_poly_indices, const ConstPolygonRef& poly, const std::vector& possible_adjacent_polys, const coord_t max_gap); + static void findAdjacentPolygons( + std::vector& adjacent_poly_indices, + const ConstPolygonRef& poly, + const std::vector& possible_adjacent_polys, + const coord_t max_gap); /*! * Calculate the Hamming Distance between two polygons relative to their own @@ -619,10 +676,31 @@ class PolygonUtils */ static Polygons clipPolygonWithAABB(const Polygons& src, const AABB& aabb); + /*! + * Generate a few outset polygons around the given base, according to the given line width + * + * \param inner_poly The inner polygon to start generating the outset from + * \param count The number of outer polygons to add + * \param line_width The actual line width to distance the polygons from each other (and from the base) + * \return The generated outset polygons + */ + static Polygons generateOutset(const Polygons& inner_poly, size_t count, coord_t line_width); + + /*! + * Generate inset polygons inside the given base, until there is no space left, according to the given line width + * + * \param outer_poly The outer polygon to start generating the inset from + * \param line_width The actual line width to distance the polygons from each other (and from the base) + * \param initial_inset The inset distance to be added to the first generated polygon + * \return The generated inset polygons + */ + static Polygons generateInset(const Polygons& outer_poly, coord_t line_width, coord_t initial_inset = 0); + private: /*! - * Helper function for PolygonUtils::moveInside2: moves a point \p from which was moved onto \p closest_polygon_point towards inside/outside when it's not already inside/outside by enough distance. - * + * Helper function for PolygonUtils::moveInside2: moves a point \p from which was moved onto \p closest_polygon_point towards inside/outside when it's not already + * inside/outside by enough distance. + * * \param closest_polygon_point The ClosestPolygonPoint we have to move inside * \param distance The distance by which to move the point. * \param from[in,out] The point to move. @@ -633,6 +711,6 @@ class PolygonUtils }; -}//namespace cura +} // namespace cura -#endif//POLYGON_OPTIMIZER_H +#endif // POLYGON_OPTIMIZER_H diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index a9c1461cf1..7374d836a7 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -111,37 +111,6 @@ void PrimeTower::generatePaths(const SliceDataStorage& storage) } } -PrimeTower::ExtrusionMoves PrimeTower::generatePaths_base(const Polygons& inset, size_t rings, coord_t line_width) -{ - ExtrusionMoves pattern; - - Polygons path = inset.offset(line_width / 2); - for (size_t ring = 0; ring < rings; ++ring) - { - pattern.polygons.add(path); - path = path.offset(line_width); - } - - return pattern; -} - -PrimeTower::ExtrusionMoves PrimeTower::generatePaths_inset(const Polygons& outer_poly, coord_t line_width, coord_t initial_inset) -{ - const Scene& scene = Application::getInstance().current_slice->scene; - const Settings& mesh_group_settings = scene.current_mesh_group->settings; - - ExtrusionMoves pattern; - - Polygons inset = outer_poly.offset(-(initial_inset + line_width / 2)); - while (! inset.empty()) - { - pattern.polygons.add(inset); - inset = inset.offset(-line_width); - } - - return pattern; -} - void PrimeTower::generatePaths_denseInfill() { const Scene& scene = Application::getInstance().current_slice->scene; @@ -164,7 +133,7 @@ void PrimeTower::generatePaths_denseInfill() const coord_t required_volume = MM3_2INT(scene.extruders[extruder_nr].settings.get("prime_tower_min_volume")); const Ratio flow = scene.extruders[extruder_nr].settings.get("prime_tower_flow"); coord_t current_volume = 0; - ExtrusionMoves& pattern = prime_moves[extruder_nr]; + Polygons& pattern = prime_moves[extruder_nr]; // Create the walls of the prime tower. unsigned int wall_nr = 0; @@ -172,7 +141,7 @@ void PrimeTower::generatePaths_denseInfill() { // Create a new polygon with an offset from the outer polygon. Polygons polygons = outer_poly.offset(-cumulative_inset - wall_nr * line_width - line_width / 2); - pattern.polygons.add(polygons); + pattern.add(polygons); current_volume += polygons.polygonLength() * line_width * layer_height * flow; if (polygons.empty()) // Don't continue. We won't ever reach the required volume because it doesn't fit. { @@ -195,7 +164,7 @@ void PrimeTower::generatePaths_denseInfill() extra_radius = line_width * extra_rings; outer_poly_base.push_back(outer_poly.offset(extra_radius)); - base_extra_moves[extruder_nr].push_back(generatePaths_base(outer_poly, extra_rings, line_width)); + base_extra_moves[extruder_nr].push_back(PolygonUtils::generateOutset(outer_poly, extra_rings, line_width)); } } @@ -204,8 +173,8 @@ void PrimeTower::generatePaths_denseInfill() // Only the most inside extruder needs to fill the inside of the prime tower if (extruder_nr == extruder_order.back()) { - ExtrusionMoves pattern = generatePaths_inset(outer_poly, line_width, cumulative_inset); - if (! pattern.polygons.empty() || ! pattern.lines.empty()) + Polygons pattern = PolygonUtils::generateInset(outer_poly, line_width, cumulative_inset); + if (! pattern.empty()) { base_extra_moves[extruder_nr].push_back(pattern); } @@ -280,19 +249,17 @@ void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t ext { // Actual prime pattern const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; - const ExtrusionMoves& pattern = prime_moves[extruder_nr]; - gcode_layer.addPolygonsByOptimizer(pattern.polygons, config); - gcode_layer.addLinesByOptimizer(pattern.lines, config, SpaceFillType::Lines); + const Polygons& pattern = prime_moves[extruder_nr]; + gcode_layer.addPolygonsByOptimizer(pattern, config); } - const std::vector& pattern_extra_brim = base_extra_moves[extruder_nr]; + const std::vector& pattern_extra_brim = base_extra_moves[extruder_nr]; if (absolute_layer_number < pattern_extra_brim.size()) { // Extra rings for stronger base const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; - const ExtrusionMoves& pattern = pattern_extra_brim[absolute_layer_number]; - gcode_layer.addPolygonsByOptimizer(pattern.polygons, config); - gcode_layer.addLinesByOptimizer(pattern.lines, config, SpaceFillType::Lines); + const Polygons& pattern = pattern_extra_brim[absolute_layer_number]; + gcode_layer.addPolygonsByOptimizer(pattern, config); } } diff --git a/src/utils/polygonUtils.cpp b/src/utils/polygonUtils.cpp index 0a8f627d53..d1f4debe21 100644 --- a/src/utils/polygonUtils.cpp +++ b/src/utils/polygonUtils.cpp @@ -3,22 +3,22 @@ #include "utils/polygonUtils.h" -#include "infill.h" -#include "utils/SparsePointGridInclusive.h" -#include "utils/linearAlg2D.h" - -#include - #include #include #include #include +#include + +#include "infill.h" +#include "utils/SparsePointGridInclusive.h" +#include "utils/linearAlg2D.h" + #ifdef DEBUG +#include + #include "utils/AABB.h" #include "utils/SVG.h" - -#include #endif namespace cura @@ -1607,4 +1607,32 @@ Polygons PolygonUtils::clipPolygonWithAABB(const Polygons& src, const AABB& aabb return out; } +Polygons PolygonUtils::generateOutset(const Polygons& inner_poly, size_t count, coord_t line_width) +{ + Polygons outset; + + Polygons current_outset; + for (size_t index = 0; index < count; ++index) + { + current_outset = index == 0 ? inner_poly.offset(line_width / 2) : current_outset.offset(line_width); + outset.add(current_outset); + } + + return outset; +} + +Polygons PolygonUtils::generateInset(const Polygons& outer_poly, coord_t line_width, coord_t initial_inset) +{ + Polygons inset; + + Polygons current_inset = outer_poly.offset(-(initial_inset + line_width / 2)); + while (! current_inset.empty()) + { + inset.add(current_inset); + current_inset = current_inset.offset(-line_width); + } + + return inset; +} + } // namespace cura From 3a7f8c336f7317075870e85d0af0962be72b96ae Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 23 Oct 2023 11:26:39 +0200 Subject: [PATCH 103/116] Moved target machine name to end of header CURA-11158 --- src/gcodeExport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gcodeExport.cpp b/src/gcodeExport.cpp index caff200811..2ef08a0474 100644 --- a/src/gcodeExport.cpp +++ b/src/gcodeExport.cpp @@ -266,7 +266,6 @@ std::string GCodeExport::getFileHeader( break; default: prefix << ";FLAVOR:" << flavorToString(flavor) << new_line; - prefix << ";TARGET_MACHINE.NAME:" << transliterate(machine_name) << new_line; prefix << ";TIME:" << ((print_time) ? static_cast(*print_time) : 6666) << new_line; if (flavor == EGCodeFlavor::ULTIGCODE) { @@ -309,6 +308,7 @@ std::string GCodeExport::getFileHeader( prefix << ";MAXX:" << INT2MM(total_bounding_box.max.x) << new_line; prefix << ";MAXY:" << INT2MM(total_bounding_box.max.y) << new_line; prefix << ";MAXZ:" << INT2MM(total_bounding_box.max.z) << new_line; + prefix << ";TARGET_MACHINE.NAME:" << transliterate(machine_name) << new_line; } return prefix.str(); From 21ee7634cb7293337d3d1d0239d3b91a96863c3c Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 23 Oct 2023 11:32:35 +0200 Subject: [PATCH 104/116] Update unit-tests accordingly CURA-11158 --- tests/GCodeExportTest.cpp | 66 ++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/tests/GCodeExportTest.cpp b/tests/GCodeExportTest.cpp index 134a48b503..3fb07c9be9 100644 --- a/tests/GCodeExportTest.cpp +++ b/tests/GCodeExportTest.cpp @@ -2,6 +2,7 @@ // CuraEngine is released under the terms of the AGPLv3 or higher #include "gcodeExport.h" // The unit under test. + #include "Application.h" // To set up a slice with settings. #include "RetractionConfig.h" // For extruder switch tests. #include "Slice.h" // To set up a slice with settings. @@ -9,6 +10,7 @@ #include "arcus/MockCommunication.h" // To prevent calls to any missing Communication class. #include "utils/Coord_t.h" #include "utils/Date.h" // To check the Griffin header. + #include // NOLINTBEGIN(*-magic-numbers) @@ -101,12 +103,13 @@ TEST_F(GCodeExportTest, CommentMultiLine) "You can honestly say\n" "You made on that day\n" "A Chilean chinchilla's chin chilly"); - EXPECT_EQ(std::string(";If you catch a chinchilla in Chile\n" - ";And cut off its beard, willy-nilly\n" - ";You can honestly say\n" - ";You made on that day\n" - ";A Chilean chinchilla's chin chilly\n"), - output.str()) + EXPECT_EQ( + std::string(";If you catch a chinchilla in Chile\n" + ";And cut off its beard, willy-nilly\n" + ";You can honestly say\n" + ";You made on that day\n" + ";A Chilean chinchilla's chin chilly\n"), + output.str()) << "Each line must be preceded by a semicolon."; } @@ -115,10 +118,11 @@ TEST_F(GCodeExportTest, CommentMultiple) gcode.writeComment("Thunderbolt and lightning"); gcode.writeComment("Very very frightening me"); gcode.writeComment(" - Galileo (1638)"); - EXPECT_EQ(std::string(";Thunderbolt and lightning\n" - ";Very very frightening me\n" - "; - Galileo (1638)\n"), - output.str()) + EXPECT_EQ( + std::string(";Thunderbolt and lightning\n" + ";Very very frightening me\n" + "; - Galileo (1638)\n"), + output.str()) << "Semicolon before each line, and newline in between."; } @@ -328,9 +332,10 @@ TEST_F(GCodeExportTest, HeaderUltiGCode) std::string result = gcode.getFileHeader(extruder_is_used, &print_time, filament_used); - EXPECT_EQ(result, - ";FLAVOR:UltiGCode\n;TARGET_MACHINE.NAME:Your favourite 3D printer\n;TIME:1337\n;MATERIAL:100\n;MATERIAL2:200\n;NOZZLE_DIAMETER:0.4\n;MINX:0\n;MINY:0\n;MINZ:0\n;MAXX:1\n;" - "MAXY:1\n;MAXZ:1\n"); + EXPECT_EQ( + result, + ";FLAVOR:UltiGCode\n;TIME:1337\n;MATERIAL:100\n;MATERIAL2:200\n;NOZZLE_DIAMETER:0.4\n;MINX:0\n;MINY:0\n;MINZ:0\n;MAXX:1\n;" + "MAXY:1\n;MAXZ:1\n;TARGET_MACHINE.NAME:Your favourite 3D printer\n"); } TEST_F(GCodeExportTest, HeaderRepRap) @@ -347,9 +352,10 @@ TEST_F(GCodeExportTest, HeaderRepRap) std::string result = gcode.getFileHeader(extruder_is_used, &print_time, filament_used); - EXPECT_EQ(result, - ";FLAVOR:RepRap\n;TARGET_MACHINE.NAME:Your favourite 3D printer\n;TIME:1337\n;Filament used: 0.02m, 0.05m\n;Layer height: " - "0.123\n;MINX:0\n;MINY:0\n;MINZ:0\n;MAXX:1\n;MAXY:1\n;MAXZ:1\n"); + EXPECT_EQ( + result, + ";FLAVOR:RepRap\n;TIME:1337\n;Filament used: 0.02m, 0.05m\n;Layer height: " + "0.123\n;MINX:0\n;MINY:0\n;MINZ:0\n;MAXX:1\n;MAXY:1\n;MAXZ:1\n;TARGET_MACHINE.NAME:Your favourite 3D printer\n"); } TEST_F(GCodeExportTest, HeaderMarlin) @@ -366,9 +372,10 @@ TEST_F(GCodeExportTest, HeaderMarlin) std::string result = gcode.getFileHeader(extruder_is_used, &print_time, filament_used); - EXPECT_EQ(result, - ";FLAVOR:Marlin\n;TARGET_MACHINE.NAME:Your favourite 3D printer\n;TIME:1337\n;Filament used: 0.02m, 0.05m\n;Layer height: " - "0.123\n;MINX:0\n;MINY:0\n;MINZ:0\n;MAXX:1\n;MAXY:1\n;MAXZ:1\n"); + EXPECT_EQ( + result, + ";FLAVOR:Marlin\n;TIME:1337\n;Filament used: 0.02m, 0.05m\n;Layer height: " + "0.123\n;MINX:0\n;MINY:0\n;MINZ:0\n;MAXX:1\n;MAXY:1\n;MAXZ:1\n;TARGET_MACHINE.NAME:Your favourite 3D printer\n"); } TEST_F(GCodeExportTest, HeaderMarlinVolumetric) @@ -383,9 +390,10 @@ TEST_F(GCodeExportTest, HeaderMarlinVolumetric) std::string result = gcode.getFileHeader(extruder_is_used, &print_time, filament_used); - EXPECT_EQ(result, - ";FLAVOR:Marlin(Volumetric)\n;TARGET_MACHINE.NAME:Your favourite 3D printer\n;TIME:1337\n;Filament used: 100mm3, 200mm3\n;Layer height: " - "0.123\n;MINX:0\n;MINY:0\n;MINZ:0\n;MAXX:1\n;MAXY:1\n;MAXZ:1\n"); + EXPECT_EQ( + result, + ";FLAVOR:Marlin(Volumetric)\n;TIME:1337\n;Filament used: 100mm3, 200mm3\n;Layer height: " + "0.123\n;MINX:0\n;MINY:0\n;MINZ:0\n;MAXX:1\n;MAXY:1\n;MAXZ:1\n;TARGET_MACHINE.NAME:Your favourite 3D printer\n"); } /* @@ -405,8 +413,9 @@ TEST_F(GCodeExportTest, EVsMmVolumetric) "area of the filament to convert the volume to a length."; constexpr double mm_input = 33.0; - EXPECT_EQ(gcode.mmToE(mm_input), mm_input * filament_area) << "Since the input mm is linear but the E output must be volumetric, we need to multiply by the cross-sectional area to convert " - "length to volume."; + EXPECT_EQ(gcode.mmToE(mm_input), mm_input * filament_area) + << "Since the input mm is linear but the E output must be volumetric, we need to multiply by the cross-sectional area to convert " + "length to volume."; constexpr double e_input = 100.0; EXPECT_EQ(gcode.eToMm3(e_input, 0), e_input) << "Since the E is volumetric and mm3 is also volumetric, the output needs to be the same."; @@ -431,8 +440,9 @@ TEST_F(GCodeExportTest, EVsMmLinear) } constexpr double mm3_input = 33.0; - EXPECT_EQ(gcode.mm3ToE(mm3_input), mm3_input / filament_area) << "Since the input mm3 is volumetric but the E output must be linear, we need to divide by the cross-sectional area to convert " - "volume to length."; + EXPECT_EQ(gcode.mm3ToE(mm3_input), mm3_input / filament_area) + << "Since the input mm3 is volumetric but the E output must be linear, we need to divide by the cross-sectional area to convert " + "volume to length."; constexpr double e_input = 100.0; EXPECT_EQ(gcode.eToMm3(e_input, 0), e_input * filament_area) << "Since the input E is linear but the output must be volumetric, we " @@ -492,7 +502,7 @@ TEST_F(GCodeExportTest, WriteZHopStartCustomSpeed) Application::getInstance().current_slice->scene.extruders[gcode.current_extruder].settings.add("speed_z_hop", "1"); // 60mm/min. gcode.current_layer_z = 2000; constexpr coord_t hop_height = 3000; - constexpr Velocity speed { 4.0 }; // 240 mm/min. + constexpr Velocity speed{ 4.0 }; // 240 mm/min. gcode.writeZhopStart(hop_height, speed); EXPECT_EQ(std::string("G1 F240 Z5\n"), output.str()) << "Custom provided speed should be used."; } @@ -520,7 +530,7 @@ TEST_F(GCodeExportTest, WriteZHopEndCustomSpeed) Application::getInstance().current_slice->scene.extruders[gcode.current_extruder].settings.add("speed_z_hop", "1"); gcode.current_layer_z = 2000; gcode.is_z_hopped = 3000; - constexpr Velocity speed { 4.0 }; // 240 mm/min. + constexpr Velocity speed{ 4.0 }; // 240 mm/min. gcode.writeZhopEnd(speed); EXPECT_EQ(std::string("G1 F240 Z2\n"), output.str()) << "Custom provided speed should be used."; } From 7bc776566b8272796e04d5a363d8c5f4d75950b7 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Mon, 23 Oct 2023 18:12:59 +0200 Subject: [PATCH 105/116] Extruder is explicitely set for evry part of raft. CURA-11205 --- src/FffGcodeWriter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 777bf12978..ec0e28c326 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -725,6 +725,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) gcode_layer.setIsInside(true); current_extruder_nr = interface_extruder_nr; + gcode_layer.setExtruder(current_extruder_nr); Application::getInstance().communication->sendLayerComplete(layer_nr, z, interface_layer_height); @@ -829,7 +830,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) // make sure that we are using the correct extruder to print raft current_extruder_nr = surface_extruder_nr; - + gcode_layer.setExtruder(current_extruder_nr); Application::getInstance().communication->sendLayerComplete(layer_nr, z, surface_layer_height); std::vector raft_outline_paths; From f11ed7c34c52cea64c804cada44b4d8533ed2caf Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 24 Oct 2023 16:23:07 +0200 Subject: [PATCH 106/116] Base curve magnitude is now a float CURA-10783 --- src/PrimeTower.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 7374d836a7..3883822adc 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -120,7 +120,7 @@ void PrimeTower::generatePaths_denseInfill() const coord_t base_extra_radius = scene.settings.get("prime_tower_base_size"); const bool has_raft = mesh_group_settings.get("adhesion_type") == EPlatformAdhesion::RAFT; const coord_t base_height = std::max(scene.settings.get("prime_tower_base_height"), has_raft ? layer_height : 0); - const int base_curve_magnitude = mesh_group_settings.get("prime_tower_base_curve_magnitude"); + const double base_curve_magnitude = mesh_group_settings.get("prime_tower_base_curve_magnitude"); const coord_t line_width = scene.extruders[extruder_order.front()].settings.get("prime_tower_line_width"); prime_moves.resize(extruder_count); From e78f42c19bb46e314432f3e074dbdfa0e7f03976 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 24 Oct 2023 22:14:11 +0200 Subject: [PATCH 107/116] 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 108/116] 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 3493ae63097e8fe9a0f4664a2df07818633c704a Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Wed, 25 Oct 2023 10:13:21 +0200 Subject: [PATCH 109/116] Set version to 5.5.0 Contributes to CURA-11218 --- conanfile.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conanfile.py b/conanfile.py index 383f5631f9..7dc2e8b0c8 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.5.0" def export_sources(self): copy(self, "CMakeLists.txt", self.recipe_folder, self.export_sources_folder) @@ -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") self.requires("clipper/6.4.2") self.requires("boost/1.82.0") self.requires("rapidjson/1.1.0") From 1609f0e97096d2877d299ce040c33e317b3e5fe7 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 25 Oct 2023 15:35:36 +0200 Subject: [PATCH 110/116] 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 111/116] (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 112/116] 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 113/116] 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 114/116] 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; From c35eebd528636b5e5d2214afd5868a18560d2186 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 27 Oct 2023 12:25:45 +0200 Subject: [PATCH 115/116] Handle specific prime tower raft line spacing CURA-11233 --- src/FffGcodeWriter.cpp | 129 ++++++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 54 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index d35b38d169..44c98715dd 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -611,6 +611,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) const size_t wall_line_count = base_settings.get("raft_base_wall_count"); const coord_t small_area_width = 0; // A raft never has a small region due to the large horizontal expansion. const coord_t line_spacing = base_settings.get("raft_base_line_spacing"); + const coord_t line_spacing_prime_tower = base_settings.get("prime_tower_raft_base_line_spacing"); const Point& infill_origin = Point(); constexpr bool skip_stitching = false; constexpr bool connected_zigzags = false; @@ -621,66 +622,86 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) const coord_t max_resolution = base_settings.get("meshfix_maximum_resolution"); const coord_t max_deviation = base_settings.get("meshfix_maximum_deviation"); - Polygons raft_outline_path = storage.raftOutline; + struct ParameterizedRaftPath + { + coord_t line_spacing; + Polygons outline; + }; + + std::vector raft_outline_paths; + raft_outline_paths.emplace_back(ParameterizedRaftPath{ line_spacing, storage.raftOutline }); if (storage.primeTower.enabled) { - // Base layer is shared with prime tower base - raft_outline_path = raft_outline_path.unionPolygons(storage.primeTower.getOuterPoly(layer_nr)); + const Polygons& raft_outline_prime_tower = storage.primeTower.getOuterPoly(layer_nr); + if (line_spacing_prime_tower == line_spacing) + { + // Base layer is shared with prime tower base + raft_outline_paths.front().outline = raft_outline_paths.front().outline.unionPolygons(raft_outline_prime_tower); + } + else + { + // Prime tower has a different line spacing, print them separately + raft_outline_paths.front().outline = raft_outline_paths.front().outline.difference(raft_outline_prime_tower); + raft_outline_paths.emplace_back(ParameterizedRaftPath{ line_spacing_prime_tower, raft_outline_prime_tower }); + } } - Infill infill_comp( - EFillMethod::LINES, - zig_zaggify_infill, - connect_polygons, - raft_outline_path, - gcode_layer.configs_storage.raft_base_config.getLineWidth(), - line_spacing, - fill_overlap, - infill_multiplier, - fill_angle, - 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); - std::vector raft_paths; - infill_comp.generate(raft_paths, raft_polygons, raftLines, base_settings, layer_nr, SectionType::ADHESION); - if (! raft_paths.empty()) + for (const ParameterizedRaftPath& raft_outline_path : raft_outline_paths) { - const GCodePathConfig& config = gcode_layer.configs_storage.raft_base_config; - const ZSeamConfig z_seam_config(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); - InsetOrderOptimizer wall_orderer( - *this, - storage, - gcode_layer, - base_settings, - base_extruder_nr, - config, - config, - config, - config, - retract_before_outer_wall, - wipe_dist, - wipe_dist, - base_extruder_nr, - base_extruder_nr, - z_seam_config, - raft_paths); - wall_orderer.addToLayer(); - } - gcode_layer.addLinesByOptimizer(raftLines, gcode_layer.configs_storage.raft_base_config, SpaceFillType::Lines); + Infill infill_comp( + EFillMethod::LINES, + zig_zaggify_infill, + connect_polygons, + raft_outline_path.outline, + gcode_layer.configs_storage.raft_base_config.getLineWidth(), + raft_outline_path.line_spacing, + fill_overlap, + infill_multiplier, + fill_angle, + 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); + std::vector raft_paths; + infill_comp.generate(raft_paths, raft_polygons, raftLines, base_settings, layer_nr, SectionType::ADHESION); + if (! raft_paths.empty()) + { + const GCodePathConfig& config = gcode_layer.configs_storage.raft_base_config; + const ZSeamConfig z_seam_config(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); + InsetOrderOptimizer wall_orderer( + *this, + storage, + gcode_layer, + base_settings, + base_extruder_nr, + config, + config, + config, + config, + retract_before_outer_wall, + wipe_dist, + wipe_dist, + base_extruder_nr, + base_extruder_nr, + z_seam_config, + raft_paths); + wall_orderer.addToLayer(); + } + gcode_layer.addLinesByOptimizer(raftLines, gcode_layer.configs_storage.raft_base_config, SpaceFillType::Lines); - raft_polygons.clear(); - raftLines.clear(); + raft_polygons.clear(); + raftLines.clear(); + } layer_plan_buffer.handle(gcode_layer, gcode); last_planned_position = gcode_layer.getLastPlannedPositionOrStartingPosition(); From ba8d5c2eeecbf84ab0ef86b24eb938c1b5f6973c Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 27 Oct 2023 15:25:27 +0200 Subject: [PATCH 116/116] Better management of extruder change during raft printing CURA-10783 --- src/FffGcodeWriter.cpp | 48 ++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index d35b38d169..3a39aed4a1 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -556,6 +556,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) const size_t base_extruder_nr = mesh_group_settings.get("raft_base_extruder_nr").extruder_nr; const size_t interface_extruder_nr = mesh_group_settings.get("raft_interface_extruder_nr").extruder_nr; const size_t surface_extruder_nr = mesh_group_settings.get("raft_surface_extruder_nr").extruder_nr; + const size_t prime_tower_extruder_nr = storage.primeTower.extruder_order.front(); coord_t z = 0; const LayerIndex initial_raft_layer_nr = -Raft::getTotalExtraLayers(); @@ -597,8 +598,6 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) = *new LayerPlan(storage, layer_nr, z, layer_height, base_extruder_nr, fan_speed_layer_time_settings_per_extruder_raft_base, comb_offset, line_width, avoid_distance); gcode_layer.setIsInside(true); - gcode_layer.setExtruder(base_extruder_nr); - Application::getInstance().communication->sendLayerComplete(layer_nr, z, layer_height); Polygons raftLines; @@ -696,6 +695,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) for (LayerIndex raft_interface_layer = 1; static_cast(raft_interface_layer) <= num_interface_layers; ++raft_interface_layer) { // raft interface layer + bool prime_tower_added_on_this_layer = ! storage.primeTower.enabled; const LayerIndex layer_nr = initial_raft_layer_nr + raft_interface_layer; z += interface_layer_height; @@ -719,10 +719,19 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) comb_offset, interface_line_width, interface_avoid_distance); - gcode_layer.setIsInside(true); - current_extruder_nr = interface_extruder_nr; - gcode_layer.setExtruder(current_extruder_nr); + if (! prime_tower_added_on_this_layer && current_extruder_nr == prime_tower_extruder_nr) + { + addPrimeTower(storage, gcode_layer, current_extruder_nr); + prime_tower_added_on_this_layer = true; + } + + gcode_layer.setIsInside(true); + if (interface_extruder_nr != current_extruder_nr) + { + setExtruder_addPrime(storage, gcode_layer, interface_extruder_nr); + current_extruder_nr = interface_extruder_nr; + } Application::getInstance().communication->sendLayerComplete(layer_nr, z, interface_layer_height); @@ -784,7 +793,11 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) raft_polygons.clear(); raft_lines.clear(); - setExtruder_addPrime(storage, gcode_layer, storage.primeTower.extruder_order.front()); + if (! prime_tower_added_on_this_layer) + { + setExtruder_addPrime(storage, gcode_layer, prime_tower_extruder_nr); + current_extruder_nr = prime_tower_extruder_nr; + } layer_plan_buffer.handle(gcode_layer, gcode); last_planned_position = gcode_layer.getLastPlannedPositionOrStartingPosition(); @@ -800,6 +813,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) for (LayerIndex raft_surface_layer = 1; static_cast(raft_surface_layer) <= num_surface_layers; raft_surface_layer++) { // raft surface layers + bool prime_tower_added_on_this_layer = ! storage.primeTower.enabled; const LayerIndex layer_nr = initial_raft_layer_nr + 1 + num_interface_layers + raft_surface_layer - 1; // +1: 1 base layer z += surface_layer_height; @@ -823,11 +837,21 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) comb_offset, surface_line_width, surface_avoid_distance); + + if (! prime_tower_added_on_this_layer && current_extruder_nr == prime_tower_extruder_nr) + { + addPrimeTower(storage, gcode_layer, current_extruder_nr); + prime_tower_added_on_this_layer = true; + } + gcode_layer.setIsInside(true); // make sure that we are using the correct extruder to print raft - current_extruder_nr = surface_extruder_nr; - gcode_layer.setExtruder(current_extruder_nr); + if (current_extruder_nr != surface_extruder_nr) + { + setExtruder_addPrime(storage, gcode_layer, surface_extruder_nr); + current_extruder_nr = surface_extruder_nr; + } Application::getInstance().communication->sendLayerComplete(layer_nr, z, surface_layer_height); Polygons raft_outline_path; @@ -889,7 +913,11 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) raft_polygons.clear(); raft_lines.clear(); - setExtruder_addPrime(storage, gcode_layer, storage.primeTower.extruder_order.front()); + if (! prime_tower_added_on_this_layer) + { + setExtruder_addPrime(storage, gcode_layer, prime_tower_extruder_nr); + current_extruder_nr = prime_tower_extruder_nr; + } layer_plan_buffer.handle(gcode_layer, gcode); } @@ -3620,8 +3648,6 @@ bool FffGcodeWriter::addSupportBottomsToGCode(const SliceDataStorage& storage, L void FffGcodeWriter::setExtruder_addPrime(const SliceDataStorage& storage, LayerPlan& gcode_layer, const size_t extruder_nr) const { - const size_t outermost_prime_tower_extruder = storage.primeTower.extruder_order[0]; - const size_t previous_extruder = gcode_layer.getExtruder(); const bool extruder_changed = gcode_layer.setExtruder(extruder_nr);