From 43955a199c60077b74012d9a47297c694e5c2d91 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Mon, 25 Sep 2023 13:53:00 +0200 Subject: [PATCH 01/27] 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 02/27] 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 03/27] 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 f832ec814da6d7d0e817460f65b4bfa74d13f5bb Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Fri, 29 Sep 2023 11:32:03 +0200 Subject: [PATCH 04/27] 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 05/27] 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 06/27] 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 07/27] 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 08/27] 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 09/27] 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 10/27] 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 11/27] 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 12/27] 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 13/27] 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 14/27] 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 15/27] 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 16/27] 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 17/27] 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 18/27] 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 19/27] 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 20/27] 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 21/27] 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 22/27] 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 23/27] 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 24/27] 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 25/27] 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 26/27] 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 27/27] 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")