From b4d1828d61f7230eb35ee32540dd7024c481357c Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 8 Aug 2023 17:22:41 +0200 Subject: [PATCH 01/10] Add setting to prevent the top layer from doing small-skin behaviour. Actually the other way around, so we don't have another negation you have to turn on to turn off (and so the default can be false I suppose). The idea is that recently, a feature was introduced where there should be walls instead of normal skin in small hard to reach places of the model. However, this is to be excluded in most cases for all the top-layer parts exposed to air on the buildplate. implements CURA-10829 --- include/infill.h | 3 ++- src/FffGcodeWriter.cpp | 4 +++- src/FffPolygonGenerator.cpp | 2 +- src/TopSurface.cpp | 2 +- src/infill.cpp | 7 ++++++- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/include/infill.h b/include/infill.h index 98276f4741..b3c915ff4c 100644 --- a/include/infill.h +++ b/include/infill.h @@ -130,7 +130,8 @@ class Infill SectionType section_type, const SierpinskiFillProvider* cross_fill_provider = nullptr, const LightningLayer* lightning_layer = nullptr, - const SliceMeshStorage* mesh = nullptr); + const SliceMeshStorage* mesh = nullptr, + 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. diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index fd836e57a8..8e56c40f74 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -2763,6 +2763,8 @@ void FffGcodeWriter::processSkinPrintFeature( constexpr bool skip_some_zags = false; constexpr int zag_skip_count = 0; constexpr coord_t pocket_size = 0; + const bool small_areas_on_surface = mesh.settings.get("small_skin_on_surface"); + const auto& exposed_to_air = mesh.layers[gcode_layer.getLayerNr()].top_surface.areas; Infill infill_comp( pattern, @@ -2788,7 +2790,7 @@ void FffGcodeWriter::processSkinPrintFeature( skip_some_zags, zag_skip_count, pocket_size); - infill_comp.generate(skin_paths, skin_polygons, skin_lines, mesh.settings, gcode_layer.getLayerNr(), SectionType::SKIN); + infill_comp.generate(skin_paths, skin_polygons, skin_lines, mesh.settings, gcode_layer.getLayerNr(), SectionType::SKIN, nullptr, nullptr, nullptr, small_areas_on_surface ? Polygons() : exposed_to_air); // add paths if (! skin_polygons.empty() || ! skin_lines.empty() || ! skin_paths.empty()) diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index 817e91ecde..8bd7c429fd 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -808,7 +808,7 @@ void FffPolygonGenerator::processSkinsAndInfill(SliceMeshStorage& mesh, const La SkinInfillAreaComputation skin_infill_area_computation(layer_nr, mesh, process_infill); skin_infill_area_computation.generateSkinsAndInfill(); - if (mesh.settings.get("ironing_enabled") && (! mesh.settings.get("ironing_only_highest_layer") || mesh.layer_nr_max_filled_layer == layer_nr)) + if (mesh.settings.get("ironing_enabled") && (! mesh.settings.get("ironing_only_highest_layer") || mesh.layer_nr_max_filled_layer == layer_nr) || ! mesh.settings.get("small_skin_on_surface")) { // Generate the top surface to iron over. mesh.layers[layer_nr].top_surface.setAreasFromMeshAndLayerNumber(mesh, layer_nr); diff --git a/src/TopSurface.cpp b/src/TopSurface.cpp index 86d546e4ad..35709cfc79 100644 --- a/src/TopSurface.cpp +++ b/src/TopSurface.cpp @@ -64,7 +64,7 @@ bool TopSurface::ironing(const SliceDataStorage& storage, const SliceMeshStorage const Ratio ironing_flow = mesh.settings.get("ironing_flow"); const bool enforce_monotonic_order = mesh.settings.get("ironing_monotonic"); constexpr size_t wall_line_count = 0; - const coord_t small_area_width = mesh.settings.get("min_even_wall_line_width") * 2; // Maximum width of a region that can still be filled with one wall. + const coord_t small_area_width = 0; // This shouldn't be on for ironing. const Point infill_origin = Point(); const bool skip_line_stitching = enforce_monotonic_order; diff --git a/src/infill.cpp b/src/infill.cpp index 812d2e45ba..f5c7e6cc26 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -87,7 +87,8 @@ void Infill::generate( SectionType section_type, const SierpinskiFillProvider* cross_fill_provider, const LightningLayer* lightning_trees, - const SliceMeshStorage* mesh) + const SliceMeshStorage* mesh, + const Polygons& prevent_small_exposed_to_air) { if (outer_contour.empty()) { @@ -110,6 +111,10 @@ void Infill::generate( inner_contour = inner_contour.offset(-small_area_width / 2); inner_contour.removeSmallAreas(to_small_length * to_small_length, true); inner_contour = inner_contour.offset(small_area_width / 2); + if (prevent_small_exposed_to_air.area() > 0) + { + inner_contour = inner_contour.unionPolygons(prevent_small_exposed_to_air).intersection(small_infill); + } inner_contour = Simplify(max_resolution, max_deviation, 0).polygon(inner_contour); small_infill = small_infill.difference(inner_contour); From 279d93877df5e8fc6db2b54d60a50f79856e4237 Mon Sep 17 00:00:00 2001 From: rburema Date: Tue, 8 Aug 2023 15:23:40 +0000 Subject: [PATCH 02/10] Applied clang-format. --- src/FffGcodeWriter.cpp | 12 +++- src/FffPolygonGenerator.cpp | 139 ++++++++++++++++++++++-------------- src/TopSurface.cpp | 93 ++++++++++++++++-------- 3 files changed, 161 insertions(+), 83 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 8e56c40f74..dc78114de1 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -2790,7 +2790,17 @@ void FffGcodeWriter::processSkinPrintFeature( skip_some_zags, zag_skip_count, pocket_size); - infill_comp.generate(skin_paths, skin_polygons, skin_lines, mesh.settings, gcode_layer.getLayerNr(), SectionType::SKIN, nullptr, nullptr, nullptr, small_areas_on_surface ? Polygons() : exposed_to_air); + infill_comp.generate( + skin_paths, + skin_polygons, + skin_lines, + mesh.settings, + gcode_layer.getLayerNr(), + SectionType::SKIN, + nullptr, + nullptr, + nullptr, + small_areas_on_surface ? Polygons() : exposed_to_air); // add paths if (! skin_polygons.empty() || ! skin_lines.empty() || ! skin_paths.empty()) diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index 8bd7c429fd..6d436fa28b 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" @@ -80,7 +80,9 @@ size_t FffPolygonGenerator::getDraftShieldLayerCount(const size_t total_layers) case DraftShieldHeightLimitation::FULL: return total_layers; case DraftShieldHeightLimitation::LIMITED: - return std::max((coord_t)0, (mesh_group_settings.get("draft_shield_height") - mesh_group_settings.get("layer_height_0")) / mesh_group_settings.get("layer_height") + 1); + return std::max( + (coord_t)0, + (mesh_group_settings.get("draft_shield_height") - mesh_group_settings.get("layer_height_0")) / mesh_group_settings.get("layer_height") + 1); default: spdlog::warn("A draft shield height limitation option was added without implementing the new option in getDraftShieldLayerCount."); return total_layers; @@ -128,9 +130,8 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe const auto variable_layer_height_max_variation = mesh_group_settings.get("adaptive_layer_height_variation"); const auto variable_layer_height_variation_step = mesh_group_settings.get("adaptive_layer_height_variation_step"); const auto adaptive_threshold = mesh_group_settings.get("adaptive_layer_height_threshold"); - adaptive_layer_heights = new AdaptiveLayerHeights(layer_thickness, variable_layer_height_max_variation, - variable_layer_height_variation_step, adaptive_threshold, - meshgroup); + adaptive_layer_heights + = new AdaptiveLayerHeights(layer_thickness, variable_layer_height_max_variation, variable_layer_height_variation_step, adaptive_threshold, meshgroup); // Get the amount of layers slice_layer_count = adaptive_layer_heights->getLayerCount(); @@ -174,7 +175,8 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe case SlicingTolerance::INCLUSIVE: if (mesh_height < initial_layer_thickness) { - slice_layer_count = std::max(slice_layer_count, (mesh_height > 0) ? 1 : 0); // If less than the initial layer height, it always has 1 layer unless the height is truly zero. + slice_layer_count + = std::max(slice_layer_count, (mesh_height > 0) ? 1 : 0); // If less than the initial layer height, it always has 1 layer unless the height is truly zero. } else { @@ -265,7 +267,8 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe } storage.support.supportLayers.resize(storage.print_layer_count); - storage.meshes.reserve(slicerList.size()); // causes there to be no resize in meshes so that the pointers in sliceMeshStorage._config to retraction_config don't get invalidated. + storage.meshes.reserve( + slicerList.size()); // causes there to be no resize in meshes so that the pointers in sliceMeshStorage._config to retraction_config don't get invalidated. for (unsigned int meshIdx = 0; meshIdx < slicerList.size(); meshIdx++) { Slicer* slicer = slicerList[meshIdx]; @@ -322,7 +325,8 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe if (has_raft) { const ExtruderTrain& train = mesh_group_settings.get("raft_surface_extruder_nr"); - layer.printZ += Raft::getTotalThickness() + train.settings.get("raft_airgap") - train.settings.get("layer_0_z_overlap"); // shift all layers (except 0) down + layer.printZ += Raft::getTotalThickness() + train.settings.get("raft_airgap") + - train.settings.get("layer_0_z_overlap"); // shift all layers (except 0) down if (layer_nr == 0) { @@ -386,7 +390,7 @@ void FffPolygonGenerator::slices2polygons(SliceDataStorage& storage, TimeKeeper& // only remove empty layers if we haven't generate support, because then support was added underneath the model. // for some materials it's better to print on support than on the build plate. const auto has_support = mesh_group_settings.get("support_enable") || mesh_group_settings.get("support_mesh"); - const auto remove_empty_first_layers = mesh_group_settings.get("remove_empty_first_layers") && !has_support; + const auto remove_empty_first_layers = mesh_group_settings.get("remove_empty_first_layers") && ! has_support; if (remove_empty_first_layers) { removeEmptyFirstLayers(storage, storage.print_layer_count); // changes storage.print_layer_count! @@ -438,7 +442,11 @@ void FffPolygonGenerator::slices2polygons(SliceDataStorage& storage, TimeKeeper& AreaSupport::generateSupportInfillFeatures(storage); } -void FffPolygonGenerator::processBasicWallsSkinInfill(SliceDataStorage& storage, const size_t mesh_order_idx, const std::vector& mesh_order, ProgressStageEstimator& inset_skin_progress_estimate) +void FffPolygonGenerator::processBasicWallsSkinInfill( + SliceDataStorage& storage, + const size_t mesh_order_idx, + const std::vector& mesh_order, + ProgressStageEstimator& inset_skin_progress_estimate) { size_t mesh_idx = mesh_order[mesh_order_idx]; SliceMeshStorage& mesh = storage.meshes[mesh_idx]; @@ -485,14 +493,15 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(SliceDataStorage& storage, } guarded_progress = { inset_skin_progress_estimate }; // walls - cura::parallel_for(0, - mesh_layer_count, - [&](size_t layer_number) - { - spdlog::debug("Processing insets for layer {} of {}", layer_number, mesh.layers.size()); - processWalls(mesh, layer_number); - guarded_progress++; - }); + cura::parallel_for( + 0, + mesh_layer_count, + [&](size_t layer_number) + { + spdlog::debug("Processing insets for layer {} of {}", layer_number, mesh.layers.size()); + processWalls(mesh, layer_number); + guarded_progress++; + }); ProgressEstimatorLinear* skin_estimator = new ProgressEstimatorLinear(mesh_layer_count); mesh_inset_skin_progress_estimator->nextStage(skin_estimator); @@ -527,17 +536,18 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(SliceDataStorage& storage, } guarded_progress.reset(); - cura::parallel_for(0, - mesh_layer_count, - [&](size_t layer_number) - { - spdlog::debug("Processing skins and infill layer {} of {}", layer_number, mesh.layers.size()); - if (! magic_spiralize || layer_number < mesh_max_initial_bottom_layer_count) // Only generate up/downskin and infill for the first X layers when spiralize is choosen. - { - processSkinsAndInfill(mesh, layer_number, process_infill); - } - guarded_progress++; - }); + cura::parallel_for( + 0, + mesh_layer_count, + [&](size_t layer_number) + { + spdlog::debug("Processing skins and infill layer {} of {}", layer_number, mesh.layers.size()); + if (! magic_spiralize || layer_number < mesh_max_initial_bottom_layer_count) // Only generate up/downskin and infill for the first X layers when spiralize is choosen. + { + processSkinsAndInfill(mesh, layer_number, process_infill); + } + guarded_progress++; + }); } void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, const size_t mesh_order_idx, const std::vector& mesh_order) @@ -667,13 +677,18 @@ void FffPolygonGenerator::processDerivedWallsSkinInfill(SliceMeshStorage& mesh) } // Pre-compute Cross Fractal - if (mesh.settings.get("infill_line_distance") > 0 && (mesh.settings.get("infill_pattern") == EFillMethod::CROSS || mesh.settings.get("infill_pattern") == EFillMethod::CROSS_3D)) + if (mesh.settings.get("infill_line_distance") > 0 + && (mesh.settings.get("infill_pattern") == EFillMethod::CROSS || mesh.settings.get("infill_pattern") == EFillMethod::CROSS_3D)) { const std::string cross_subdivision_spec_image_file = mesh.settings.get("cross_infill_density_image"); std::ifstream cross_fs(cross_subdivision_spec_image_file.c_str()); if (! cross_subdivision_spec_image_file.empty() && cross_fs.good()) { - mesh.cross_fill_provider = new SierpinskiFillProvider(mesh.bounding_box, mesh.settings.get("infill_line_distance"), mesh.settings.get("infill_line_width"), cross_subdivision_spec_image_file); + mesh.cross_fill_provider = new SierpinskiFillProvider( + mesh.bounding_box, + mesh.settings.get("infill_line_distance"), + mesh.settings.get("infill_line_width"), + cross_subdivision_spec_image_file); } else { @@ -681,7 +696,8 @@ void FffPolygonGenerator::processDerivedWallsSkinInfill(SliceMeshStorage& mesh) { spdlog::error("Cannot find density image: {}.", cross_subdivision_spec_image_file); } - mesh.cross_fill_provider = new SierpinskiFillProvider(mesh.bounding_box, mesh.settings.get("infill_line_distance"), mesh.settings.get("infill_line_width")); + mesh.cross_fill_provider + = new SierpinskiFillProvider(mesh.bounding_box, mesh.settings.get("infill_line_distance"), mesh.settings.get("infill_line_width")); } } @@ -696,7 +712,7 @@ void FffPolygonGenerator::processDerivedWallsSkinInfill(SliceMeshStorage& mesh) SkinInfillAreaComputation::combineInfillLayers(mesh); // Fuzzy skin. Disabled when using interlocking structures, the internal interlocking walls become fuzzy. - if (mesh.settings.get("magic_fuzzy_skin_enabled") && !mesh.settings.get("interlocking_enable")) + if (mesh.settings.get("magic_fuzzy_skin_enabled") && ! mesh.settings.get("interlocking_enable")) { processFuzzyWalls(mesh); } @@ -808,7 +824,8 @@ void FffPolygonGenerator::processSkinsAndInfill(SliceMeshStorage& mesh, const La SkinInfillAreaComputation skin_infill_area_computation(layer_nr, mesh, process_infill); skin_infill_area_computation.generateSkinsAndInfill(); - if (mesh.settings.get("ironing_enabled") && (! mesh.settings.get("ironing_only_highest_layer") || mesh.layer_nr_max_filled_layer == layer_nr) || ! mesh.settings.get("small_skin_on_surface")) + if (mesh.settings.get("ironing_enabled") && (! mesh.settings.get("ironing_only_highest_layer") || mesh.layer_nr_max_filled_layer == layer_nr) + || ! mesh.settings.get("small_skin_on_surface")) { // Generate the top surface to iron over. mesh.layers[layer_nr].top_surface.setAreasFromMeshAndLayerNumber(mesh, layer_nr); @@ -847,11 +864,14 @@ void FffPolygonGenerator::computePrintHeightStatistics(SliceDataStorage& storage // Height of where the support reaches. Scene& scene = Application::getInstance().current_slice->scene; const Settings& mesh_group_settings = scene.current_mesh_group->settings; - const size_t support_infill_extruder_nr = mesh_group_settings.get("support_infill_extruder_nr").extruder_nr; // TODO: Support extruder should be configurable per object. + const size_t support_infill_extruder_nr + = mesh_group_settings.get("support_infill_extruder_nr").extruder_nr; // TODO: Support extruder should be configurable per object. max_print_height_per_extruder[support_infill_extruder_nr] = std::max(max_print_height_per_extruder[support_infill_extruder_nr], storage.support.layer_nr_max_filled_layer); - const size_t support_roof_extruder_nr = mesh_group_settings.get("support_roof_extruder_nr").extruder_nr; // TODO: Support roof extruder should be configurable per object. + const size_t support_roof_extruder_nr + = mesh_group_settings.get("support_roof_extruder_nr").extruder_nr; // TODO: Support roof extruder should be configurable per object. max_print_height_per_extruder[support_roof_extruder_nr] = std::max(max_print_height_per_extruder[support_roof_extruder_nr], storage.support.layer_nr_max_filled_layer); - const size_t support_bottom_extruder_nr = mesh_group_settings.get("support_bottom_extruder_nr").extruder_nr; // TODO: Support bottom extruder should be configurable per object. + const size_t support_bottom_extruder_nr + = mesh_group_settings.get("support_bottom_extruder_nr").extruder_nr; // TODO: Support bottom extruder should be configurable per object. max_print_height_per_extruder[support_bottom_extruder_nr] = std::max(max_print_height_per_extruder[support_bottom_extruder_nr], storage.support.layer_nr_max_filled_layer); // Height of where the platform adhesion reaches. @@ -861,12 +881,12 @@ void FffPolygonGenerator::computePrintHeightStatistics(SliceDataStorage& storage case EPlatformAdhesion::SKIRT: case EPlatformAdhesion::BRIM: { - const std::vector skirt_brim_extruder_trains = mesh_group_settings.get>("skirt_brim_extruder_nr"); - for (ExtruderTrain* train : skirt_brim_extruder_trains) - { - const size_t skirt_brim_extruder_nr = train->extruder_nr; - max_print_height_per_extruder[skirt_brim_extruder_nr] = std::max(0, max_print_height_per_extruder[skirt_brim_extruder_nr]); // Includes layer 0. - } + const std::vector skirt_brim_extruder_trains = mesh_group_settings.get>("skirt_brim_extruder_nr"); + for (ExtruderTrain* train : skirt_brim_extruder_trains) + { + const size_t skirt_brim_extruder_nr = train->extruder_nr; + max_print_height_per_extruder[skirt_brim_extruder_nr] = std::max(0, max_print_height_per_extruder[skirt_brim_extruder_nr]); // Includes layer 0. + } break; } case EPlatformAdhesion::RAFT: @@ -874,9 +894,11 @@ void FffPolygonGenerator::computePrintHeightStatistics(SliceDataStorage& storage const size_t base_extruder_nr = mesh_group_settings.get("raft_base_extruder_nr").extruder_nr; max_print_height_per_extruder[base_extruder_nr] = std::max(-raft_layers, max_print_height_per_extruder[base_extruder_nr]); // Includes the lowest raft layer. const size_t interface_extruder_nr = mesh_group_settings.get("raft_interface_extruder_nr").extruder_nr; - max_print_height_per_extruder[interface_extruder_nr] = std::max(-raft_layers + 1, max_print_height_per_extruder[interface_extruder_nr]); // Includes the second-lowest raft layer. + max_print_height_per_extruder[interface_extruder_nr] + = std::max(-raft_layers + 1, max_print_height_per_extruder[interface_extruder_nr]); // Includes the second-lowest raft layer. const size_t surface_extruder_nr = mesh_group_settings.get("raft_surface_extruder_nr").extruder_nr; - max_print_height_per_extruder[surface_extruder_nr] = std::max(-1, max_print_height_per_extruder[surface_extruder_nr]); // Includes up to the first layer below the model (so -1). + max_print_height_per_extruder[surface_extruder_nr] + = std::max(-1, max_print_height_per_extruder[surface_extruder_nr]); // Includes up to the first layer below the model (so -1). break; } default: @@ -917,7 +939,8 @@ void FffPolygonGenerator::processOozeShield(SliceDataStorage& storage) const AngleDegrees angle = mesh_group_settings.get("ooze_shield_angle"); if (angle <= 89) { - const coord_t allowed_angle_offset = tan(mesh_group_settings.get("ooze_shield_angle")) * mesh_group_settings.get("layer_height"); // Allow for a 60deg angle in the oozeShield. + const coord_t allowed_angle_offset + = tan(mesh_group_settings.get("ooze_shield_angle")) * mesh_group_settings.get("layer_height"); // Allow for a 60deg angle in the oozeShield. for (LayerIndex layer_nr = 1; layer_nr <= storage.max_print_height_second_to_last_extruder; layer_nr++) { storage.oozeShield[layer_nr] = storage.oozeShield[layer_nr].unionPolygons(storage.oozeShield[layer_nr - 1].offset(-allowed_angle_offset)); @@ -941,7 +964,8 @@ void FffPolygonGenerator::processOozeShield(SliceDataStorage& storage) const auto& extruders = Application::getInstance().current_slice->scene.extruders; for (int extruder_nr = 0; extruder_nr < int(extruders.size()); extruder_nr++) { - if ( ! extruder_is_used[extruder_nr]) continue; + if (! extruder_is_used[extruder_nr]) + continue; max_line_width = std::max(max_line_width, extruders[extruder_nr].settings.get("skirt_brim_line_width")); } } @@ -992,7 +1016,8 @@ void FffPolygonGenerator::processDraftShield(SliceDataStorage& storage) const auto& extruders = Application::getInstance().current_slice->scene.extruders; for (int extruder_nr = 0; extruder_nr < int(extruders.size()); extruder_nr++) { - if ( ! extruder_is_used[extruder_nr]) continue; + if (! extruder_is_used[extruder_nr]) + continue; max_line_width = std::max(max_line_width, extruders[extruder_nr].settings.get("skirt_brim_line_width")); } } @@ -1047,10 +1072,14 @@ void FffPolygonGenerator::processFuzzyWalls(SliceMeshStorage& mesh) const coord_t avg_dist_between_points = mesh.settings.get("magic_fuzzy_skin_point_dist"); const coord_t min_dist_between_points = avg_dist_between_points * 3 / 4; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value const coord_t range_random_point_dist = avg_dist_between_points / 2; - unsigned int start_layer_nr = (mesh.settings.get("adhesion_type") == EPlatformAdhesion::BRIM) ? 1 : 0; // don't make fuzzy skin on first layer if there's a brim + unsigned int start_layer_nr + = (mesh.settings.get("adhesion_type") == EPlatformAdhesion::BRIM) ? 1 : 0; // don't make fuzzy skin on first layer if there's a brim auto hole_area = Polygons(); - std::function accumulate_is_in_hole = [](const bool& prev_result, const ExtrusionJunction& junction) { return false; }; + std::function accumulate_is_in_hole = [](const bool& prev_result, const ExtrusionJunction& junction) + { + return false; + }; for (unsigned int layer_nr = start_layer_nr; layer_nr < mesh.layers.size(); layer_nr++) { @@ -1071,7 +1100,10 @@ void FffPolygonGenerator::processFuzzyWalls(SliceMeshStorage& mesh) if (apply_outside_only) { hole_area = part.print_outline.getOutsidePolygons().offset(-line_width); - accumulate_is_in_hole = [&hole_area](const bool& prev_result, const ExtrusionJunction& junction) { return prev_result || hole_area.inside(junction.p); }; + accumulate_is_in_hole = [&hole_area](const bool& prev_result, const ExtrusionJunction& junction) + { + return prev_result || hole_area.inside(junction.p); + }; } for (auto& line : toolpath) { @@ -1087,7 +1119,8 @@ void FffPolygonGenerator::processFuzzyWalls(SliceMeshStorage& mesh) result.is_closed = line.is_closed; // generate points in between p0 and p1 - int64_t dist_left_over = (min_dist_between_points / 4) + rand() % (min_dist_between_points / 4); // the distance to be traversed on the line before making the first new point + int64_t dist_left_over + = (min_dist_between_points / 4) + rand() % (min_dist_between_points / 4); // the distance to be traversed on the line before making the first new point auto* p0 = &line.front(); for (auto& p1 : line) { diff --git a/src/TopSurface.cpp b/src/TopSurface.cpp index 35709cfc79..9ed9cc7ede 100644 --- a/src/TopSurface.cpp +++ b/src/TopSurface.cpp @@ -1,28 +1,29 @@ // Copyright (c) 2023 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher -#include "infill.h" -#include "LayerPlan.h" -#include "sliceDataStorage.h" #include "TopSurface.h" + #include "ExtruderTrain.h" +#include "LayerPlan.h" +#include "infill.h" +#include "sliceDataStorage.h" namespace cura { TopSurface::TopSurface() { - //Do nothing. Areas stays empty. + // Do nothing. Areas stays empty. } void TopSurface::setAreasFromMeshAndLayerNumber(SliceMeshStorage& mesh, size_t layer_number) { - //The top surface is all parts of the mesh where there's no mesh above it, so find the layer above it first. + // The top surface is all parts of the mesh where there's no mesh above it, so find the layer above it first. Polygons mesh_above; if (layer_number < mesh.layers.size() - 1) { mesh_above = mesh.layers[layer_number + 1].getOutlines(); - } //If this is the top-most layer, mesh_above stays empty. + } // If this is the top-most layer, mesh_above stays empty. if (mesh.settings.get("magic_spiralize")) { @@ -39,13 +40,14 @@ void TopSurface::setAreasFromMeshAndLayerNumber(SliceMeshStorage& mesh, size_t l } } -bool TopSurface::ironing(const SliceDataStorage& storage, const SliceMeshStorage& mesh, const GCodePathConfig& line_config, LayerPlan& layer, const FffGcodeWriter& gcode_writer) const +bool TopSurface::ironing(const SliceDataStorage& storage, const SliceMeshStorage& mesh, const GCodePathConfig& line_config, LayerPlan& layer, const FffGcodeWriter& gcode_writer) + const { if (areas.empty()) { - return false; //Nothing to do. + return false; // Nothing to do. } - //Generate the lines to cover the surface. + // Generate the lines to cover the surface. const int extruder_nr = mesh.settings.get("top_bottom_extruder_nr").extruder_nr; const EFillMethod pattern = mesh.settings.get("ironing_pattern"); const bool zig_zaggify_infill = pattern == EFillMethod::ZIG_ZAG; @@ -55,7 +57,7 @@ bool TopSurface::ironing(const SliceDataStorage& storage, const SliceMeshStorage const size_t roofing_layer_count = std::min(mesh.settings.get("roofing_layer_count"), mesh.settings.get("top_layers")); const std::vector& top_most_skin_angles = (roofing_layer_count > 0) ? mesh.roofing_angles : mesh.skin_angles; assert(top_most_skin_angles.size() > 0); - const AngleDegrees direction = top_most_skin_angles[layer.getLayerNr() % top_most_skin_angles.size()] + AngleDegrees(90.0); //Always perpendicular to the skin lines. + const AngleDegrees direction = top_most_skin_angles[layer.getLayerNr() % top_most_skin_angles.size()] + AngleDegrees(90.0); // Always perpendicular to the skin lines. constexpr coord_t infill_overlap = 0; constexpr int infill_multiplier = 1; constexpr coord_t shift = 0; @@ -71,52 +73,70 @@ bool TopSurface::ironing(const SliceDataStorage& storage, const SliceMeshStorage coord_t ironing_inset = -mesh.settings.get("ironing_inset"); if (pattern == EFillMethod::ZIG_ZAG) { - //Compensate for the outline_offset decrease that takes place when using the infill generator to generate ironing with the zigzag pattern + // Compensate for the outline_offset decrease that takes place when using the infill generator to generate ironing with the zigzag pattern const Ratio width_scale = (float)mesh.settings.get("layer_height") / mesh.settings.get("infill_sparse_thickness"); ironing_inset += width_scale * line_width / 2; - //Align the edge of the ironing line with the edge of the outer wall + // Align the edge of the ironing line with the edge of the outer wall ironing_inset -= ironing_flow * line_width / 2; } else if (pattern == EFillMethod::CONCENTRIC) { - //Counteract the outline_offset increase that takes place when using the infill generator to generate ironing with the concentric pattern + // Counteract the outline_offset increase that takes place when using the infill generator to generate ironing with the concentric pattern ironing_inset += line_spacing - line_width / 2; - //Align the edge of the ironing line with the edge of the outer wall + // Align the edge of the ironing line with the edge of the outer wall ironing_inset -= ironing_flow * line_width / 2; } Polygons ironed_areas = areas.offset(ironing_inset); - Infill infill_generator(pattern, zig_zaggify_infill, connect_polygons, ironed_areas, line_width, line_spacing, infill_overlap, infill_multiplier, direction, layer.z - 10, shift, max_resolution, max_deviation, wall_line_count, small_area_width, infill_origin, skip_line_stitching); + Infill infill_generator( + pattern, + zig_zaggify_infill, + connect_polygons, + ironed_areas, + line_width, + line_spacing, + infill_overlap, + infill_multiplier, + direction, + layer.z - 10, + shift, + max_resolution, + max_deviation, + wall_line_count, + small_area_width, + infill_origin, + skip_line_stitching); std::vector ironing_paths; Polygons ironing_polygons; Polygons ironing_lines; infill_generator.generate(ironing_paths, ironing_polygons, ironing_lines, mesh.settings, layer.getLayerNr(), SectionType::IRONING); - if(ironing_polygons.empty() && ironing_lines.empty() && ironing_paths.empty()) + if (ironing_polygons.empty() && ironing_lines.empty() && ironing_paths.empty()) { - return false; //Nothing to do. + return false; // Nothing to do. } layer.mode_skip_agressive_merge = true; bool added = false; - if(!ironing_polygons.empty()) + if (! ironing_polygons.empty()) { constexpr bool force_comb_retract = false; layer.addTravel(ironing_polygons[0][0], force_comb_retract); layer.addPolygonsByOptimizer(ironing_polygons, line_config, ZSeamConfig()); added = true; } - if(!ironing_lines.empty()) + if (! ironing_lines.empty()) { if (pattern == EFillMethod::LINES || pattern == EFillMethod::ZIG_ZAG) { - //Move to a corner of the area that is perpendicular to the ironing lines, to reduce the number of seams. + // Move to a corner of the area that is perpendicular to the ironing lines, to reduce the number of seams. const AABB bounding_box(ironed_areas); PointMatrix rotate(-direction + 90); const Point center = bounding_box.getMiddle(); - const Point far_away = rotate.apply(Point(0, vSize(bounding_box.max - center) * 100)); //Some direction very far away in the direction perpendicular to the ironing lines, relative to the centre. - //Two options to start, both perpendicular to the ironing lines. Which is closer? + const Point far_away = rotate.apply( + Point(0, vSize(bounding_box.max - center) * 100)); // Some direction very far away in the direction perpendicular to the ironing lines, relative to the centre. + // Two options to start, both perpendicular to the ironing lines. Which is closer? const Point front_side = PolygonUtils::findNearestVert(center + far_away, ironed_areas).p(); const Point back_side = PolygonUtils::findNearestVert(center - far_away, ironed_areas).p(); if (vSize2(layer.getLastPlannedPositionOrStartingPosition() - front_side) < vSize2(layer.getLastPlannedPositionOrStartingPosition() - back_side)) @@ -129,25 +149,40 @@ bool TopSurface::ironing(const SliceDataStorage& storage, const SliceMeshStorage } } - if( ! enforce_monotonic_order) + if (! enforce_monotonic_order) { layer.addLinesByOptimizer(ironing_lines, line_config, SpaceFillType::PolyLines); } else { - const coord_t max_adjacent_distance = line_spacing * 1.1; //Lines are considered adjacent - meaning they need to be printed in monotonic order - if spaced 1 line apart, with 10% extra play. + const coord_t max_adjacent_distance + = line_spacing * 1.1; // Lines are considered adjacent - meaning they need to be printed in monotonic order - if spaced 1 line apart, with 10% extra play. layer.addLinesMonotonic(Polygons(), ironing_lines, line_config, SpaceFillType::PolyLines, AngleRadians(direction), max_adjacent_distance); } added = true; } - if(!ironing_paths.empty()) + if (! ironing_paths.empty()) { constexpr bool retract_before_outer_wall = false; constexpr coord_t wipe_dist = 0u; const ZSeamConfig z_seam_config(EZSeamType::SHORTEST, layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); - InsetOrderOptimizer wall_orderer(gcode_writer, storage, layer, mesh.settings, extruder_nr, - line_config, line_config, line_config, line_config, - retract_before_outer_wall, wipe_dist, wipe_dist, extruder_nr, extruder_nr, z_seam_config, ironing_paths); + InsetOrderOptimizer wall_orderer( + gcode_writer, + storage, + layer, + mesh.settings, + extruder_nr, + line_config, + line_config, + line_config, + line_config, + retract_before_outer_wall, + wipe_dist, + wipe_dist, + extruder_nr, + extruder_nr, + z_seam_config, + ironing_paths); wall_orderer.addToLayer(); added = true; } @@ -156,4 +191,4 @@ bool TopSurface::ironing(const SliceDataStorage& storage, const SliceMeshStorage return added; } -} +} // namespace cura From 8677b106c5daff638bfdfb6c01290ef00f4b39ca Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 8 Aug 2023 19:48:55 +0200 Subject: [PATCH 03/10] Fix include-issue exposed by auto-formatter. done as part of CURA-10829 --- include/TopSurface.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/TopSurface.h b/include/TopSurface.h index dcc5e5b9c2..62fd7539bb 100644 --- a/include/TopSurface.h +++ b/include/TopSurface.h @@ -12,6 +12,7 @@ namespace cura class GCodePathConfig; class FffGcodeWriter; class LayerPlan; +class SliceDataStorage; class SliceMeshStorage; class TopSurface From 6c375d0ab3dd8e19f9fea2608d06e6b7d468b3d2 Mon Sep 17 00:00:00 2001 From: rburema Date: Tue, 8 Aug 2023 17:49:39 +0000 Subject: [PATCH 04/10] Applied clang-format. --- include/TopSurface.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/TopSurface.h b/include/TopSurface.h index 62fd7539bb..49dba4e203 100644 --- a/include/TopSurface.h +++ b/include/TopSurface.h @@ -1,5 +1,5 @@ -//Copyright (c) 2018 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2018 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef TOPSURFACE_H #define TOPSURFACE_H @@ -60,6 +60,6 @@ class TopSurface Polygons areas; }; -} +} // namespace cura #endif /* TOPSURFACE_H */ From ac86c0338fc5620467d75095f64abd66110d9a8f Mon Sep 17 00:00:00 2001 From: rburema Date: Sat, 12 Aug 2023 08:57:29 +0000 Subject: [PATCH 05/10] Applied clang-format. --- src/FffGcodeWriter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 705053e0a9..12d66b9c58 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -2975,7 +2975,8 @@ bool FffGcodeWriter::addSupportToGCode(const SliceDataStorage& storage, LayerPla bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, LayerPlan& gcode_layer) const { bool added_something = false; - const SupportLayer& support_layer = storage.support.supportLayers[std::max(LayerIndex{ 0 }, gcode_layer.getLayerNr())]; // account for negative layer numbers for raft filler layers + const SupportLayer& support_layer + = storage.support.supportLayers[std::max(LayerIndex{ 0 }, gcode_layer.getLayerNr())]; // account for negative layer numbers for raft filler layers if (gcode_layer.getLayerNr() > storage.support.layer_nr_max_filled_layer || support_layer.support_infill_parts.empty()) { From f8818e13776a4a2368280a00a7f61cf5e66c3575 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 15 Aug 2023 16:32:36 +0200 Subject: [PATCH 06/10] Also possible to exclude bottom from small skin behaviour. Small skin areas replace the normal fill pattern and use walls. Previously in this branch, the possibility was added to not do that to areas exposed to air. It turns out this means in general, not just on the buildplate (also, bottoms can happen away from the buildplate as well of course). As such, take skin bottoms into account of when to exclude areas for consideration when 'Small Top/Bottom On Surface' is off. part of CURA-10829 --- include/sliceDataStorage.h | 7 +++++++ src/FffGcodeWriter.cpp | 3 ++- src/FffPolygonGenerator.cpp | 10 ++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index b34c722fbf..626334b10c 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -174,6 +174,13 @@ class SliceLayer */ TopSurface top_surface; + /*! + * \brief The parts of the model that are exposed at the bottom(s) of the model. + * + * Note: Filled only when needed. + */ + Polygons bottom_surface; + /*! * Get the all outlines of all layer parts in this layer. * diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 12d66b9c58..b165e4e931 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -2764,7 +2764,8 @@ void FffGcodeWriter::processSkinPrintFeature( constexpr int zag_skip_count = 0; constexpr coord_t pocket_size = 0; const bool small_areas_on_surface = mesh.settings.get("small_skin_on_surface"); - const auto& exposed_to_air = mesh.layers[gcode_layer.getLayerNr()].top_surface.areas; + const auto& current_layer = mesh.layers[gcode_layer.getLayerNr()]; + const auto& exposed_to_air = current_layer.top_surface.areas.unionPolygons(current_layer.bottom_surface); Infill infill_comp( pattern, diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index 75996887a5..055e81803e 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -830,6 +830,16 @@ void FffPolygonGenerator::processSkinsAndInfill(SliceMeshStorage& mesh, const La // Generate the top surface to iron over. mesh.layers[layer_nr].top_surface.setAreasFromMeshAndLayerNumber(mesh, layer_nr); } + + if (layer_nr >= 0 && ! mesh.settings.get("small_skin_on_surface")) + { + // Generate the bottom surface. + mesh.layers[layer_nr].bottom_surface = mesh.layers[layer_nr].getOutlines(); + if (layer_nr > 0) + { + mesh.layers[layer_nr].bottom_surface = mesh.layers[layer_nr].bottom_surface.difference(mesh.layers[layer_nr - 1].getOutlines()); + } + } } void FffPolygonGenerator::computePrintHeightStatistics(SliceDataStorage& storage) From 3e8d340f87c9970b6ab1714f0984a8e3ae92af93 Mon Sep 17 00:00:00 2001 From: rburema Date: Tue, 15 Aug 2023 14:33:13 +0000 Subject: [PATCH 07/10] Applied clang-format. --- include/sliceDataStorage.h | 66 ++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 626334b10c..0d20a90f14 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -1,16 +1,14 @@ -//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 SLICE_DATA_STORAGE_H #define SLICE_DATA_STORAGE_H -#include -#include - #include "PrimeTower.h" #include "RetractionConfig.h" #include "SupportInfillPart.h" #include "TopSurface.h" +#include "WipeScriptConfig.h" #include "settings/Settings.h" //For MAX_EXTRUDERS. #include "settings/types/Angle.h" //Infill angles. #include "settings/types/LayerIndex.h" @@ -19,7 +17,9 @@ #include "utils/IntPoint.h" #include "utils/NoCopy.h" #include "utils/polygon.h" -#include "WipeScriptConfig.h" + +#include +#include // libArachne #include "utils/ExtrusionLine.h" @@ -32,14 +32,15 @@ class SierpinskiFillProvider; class LightningGenerator; /*! - * A SkinPart is a connected area designated as top and/or bottom skin. + * A SkinPart is a connected area designated as top and/or bottom skin. * Surrounding each non-bridged skin area with an outline may result in better top skins. * It's filled during FffProcessor.processSliceData(.) and used in FffProcessor.writeGCode(.) to generate the final gcode. */ class SkinPart { public: - PolygonsPart outline; //!< The skinOutline is the area which needs to be 100% filled to generate a proper top&bottom filling. It's filled by the "skin" module. Includes both roofing and non-roofing. + PolygonsPart outline; //!< The skinOutline is the area which needs to be 100% filled to generate a proper top&bottom filling. It's filled by the "skin" module. Includes both + //!< roofing and non-roofing. Polygons skin_fill; //!< The part of the skin which is not roofing. Polygons roofing_fill; //!< The inner infill which has air directly above Polygons top_most_surface_fill; //!< The inner infill of the uppermost top layer which has air directly above. @@ -64,7 +65,7 @@ class SliceLayerPart //!< Too small parts will be omitted compared to the outline. Polygons spiral_wall; //!< The centerline of the wall used by spiralize mode. Only computed if spiralize mode is enabled. Polygons inner_area; //!< The area of the outline, minus the walls. This will be filled with either skin or infill. - std::vector skin_parts; //!< The skin parts which are filled for 100% with lines and/or insets. + std::vector skin_parts; //!< The skin parts which are filled for 100% with lines and/or insets. std::vector wall_toolpaths; //!< toolpaths for walls, will replace(?) the insets. Binned by inset_idx. std::vector infill_wall_toolpaths; //!< toolpaths for the walls of the infill areas. Binned by inset_idx. @@ -125,7 +126,7 @@ class SliceLayerPart * This maximum number of layers we can combine is a user setting. This number, say "n", means the maximum number of layers we can combine into one. * On the combined layers, the extrusion amount will be higher than the normal extrusion amount because it needs to extrude for multiple layers instead of one. * - * infill_area[x][n] is infill_area of (n+1) layers thick. + * infill_area[x][n] is infill_area of (n+1) layers thick. * * infill_area[0] corresponds to the most dense infill area. * infill_area[x] will lie fully inside infill_area[x+1]. @@ -161,9 +162,9 @@ class SliceLayerPart class SliceLayer { public: - coord_t printZ; //!< The height at which this layer needs to be printed. Can differ from sliceZ due to the raft. - coord_t thickness; //!< The thickness of this layer. Can be different when using variable layer heights. - std::vector parts; //!< An array of LayerParts which contain the actual data. The parts are printed one at a time to minimize travel outside of the 3D model. + coord_t printZ; //!< The height at which this layer needs to be printed. Can differ from sliceZ due to the raft. + coord_t thickness; //!< The thickness of this layer. Can be different when using variable layer heights. + std::vector parts; //!< An array of LayerParts which contain the actual data. The parts are printed one at a time to minimize travel outside of the 3D model. Polygons openPolyLines; //!< A list of lines which were never hooked up into a 2D polygon. (Currently unused in normal operation) /*! @@ -183,7 +184,7 @@ class SliceLayer /*! * Get the all outlines of all layer parts in this layer. - * + * * \param external_polys_only Whether to only include the outermost outline of each layer part * \return A collection of all the outline polygons */ @@ -192,7 +193,7 @@ class SliceLayer /*! * Get the all outlines of all layer parts in this layer. * Add those polygons to @p result. - * + * * \param external_polys_only Whether to only include the outermost outline of each layer part * \param result The result: a collection of all the outline polygons */ @@ -204,12 +205,10 @@ class SliceLayer /******************/ - - class SupportLayer { public: - std::vector support_infill_parts; //!< a list of support infill parts + 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_mesh_drop_down; //!< Areas from support meshes which should be supported by more support @@ -260,8 +259,10 @@ class SliceMeshStorage std::vector roofing_angles; //!< a list of angle values which is cycled through to determine the roofing angle of each layer std::vector skin_angles; //!< a list of angle values which is cycled through to determine the skin angle of each layer std::vector overhang_areas; //!< For each layer the areas that are classified as overhang on this mesh. - std::vector full_overhang_areas; //!< For each layer the full overhang without the tangent of the overhang angle removed, such that the overhang area adjoins the areas of the next layers. - std::vector> overhang_points; //!< For each layer a list of points where point-overhang is detected. This is overhang that hasn't got any surface area, such as a corner pointing downwards. + std::vector full_overhang_areas; //!< For each layer the full overhang without the tangent of the overhang angle removed, such that the overhang area adjoins the + //!< areas of the next layers. + std::vector> overhang_points; //!< For each layer a list of points where point-overhang is detected. This is overhang that hasn't got any surface area, + //!< such as a corner pointing downwards. AABB3D bounding_box; //!< the mesh's bounding box SubDivCube* base_subdiv_cube; @@ -329,22 +330,23 @@ class SliceDataStorage : public NoCopy std::vector retraction_wipe_config_per_extruder; //!< Config for retractions, extruder switch retractions, and wipes, per extruder. SupportStorage support; - + 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.) + 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. std::vector max_print_height_order; //!< Ordered indices into max_print_height_per_extruder: back() will return the extruder number with the highest print height. std::vector spiralize_seam_vertex_indices; //!< the index of the seam vertex for each layer - std::vector spiralize_wall_outlines; //!< the wall outline polygons for each layer + std::vector spiralize_wall_outlines; //!< the wall outline polygons for each layer PrimeTower primeTower; - std::vector oozeShield; //oozeShield per layer + std::vector oozeShield; // oozeShield per layer Polygons draft_protection_shield; //!< The polygons for a heightened skirt which protects from warping by gusts of wind and acts as a heated chamber. /*! @@ -359,7 +361,7 @@ class SliceDataStorage : public NoCopy /*! * Get all outlines within a given layer. - * + * * \param layer_nr The index of the layer for which to get the outlines * (negative layer numbers indicate the raft). * \param include_support Whether to include support in the outline. @@ -368,11 +370,13 @@ class SliceDataStorage : public NoCopy * \param external_polys_only Whether to disregard all hole polygons. * \param extruder_nr (optional) only give back outlines for this extruder (where the walls are printed with this extruder) */ - Polygons getLayerOutlines(const LayerIndex layer_nr, const bool include_support, const bool include_prime_tower, const bool external_polys_only = false, const int extruder_nr = -1) const; + Polygons + getLayerOutlines(const LayerIndex layer_nr, const bool include_support, const bool include_prime_tower, const bool external_polys_only = false, const int extruder_nr = -1) + const; /*! * Get the extruders used. - * + * * \return A vector of booleans indicating whether the extruder with the * corresponding index is used in the mesh group. */ @@ -380,7 +384,7 @@ class SliceDataStorage : public NoCopy /*! * Get the extruders used on a particular layer. - * + * * \param layer_nr the layer for which to check * \return a vector of bools indicating whether the extruder with corresponding index is used in this layer. */ @@ -409,6 +413,6 @@ class SliceDataStorage : public NoCopy std::vector initializeRetractionAndWipeConfigs(); }; -}//namespace cura +} // namespace cura -#endif//SLICE_DATA_STORAGE_H +#endif // SLICE_DATA_STORAGE_H From b85dd9f20b63da829a5c8915b53f728189b7099d Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 15 Aug 2023 16:56:14 +0200 Subject: [PATCH 08/10] Correct typo: to -> too. Was still left over from the code review for CURA-10670, committed as part of CURA-10829. --- src/infill.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/infill.cpp b/src/infill.cpp index f5c7e6cc26..279e1ceff3 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -104,12 +104,12 @@ void Infill::generate( // infill pattern is concentric or if the small_area_width is zero. if (pattern != EFillMethod::CONCENTRIC && small_area_width > 0) { - const auto to_small_length = INT2MM(static_cast(infill_line_width) / 2.0); + const auto too_small_length = INT2MM(static_cast(infill_line_width) / 2.0); // Split the infill region in a narrow region and the normal region. Polygons small_infill = inner_contour; inner_contour = inner_contour.offset(-small_area_width / 2); - inner_contour.removeSmallAreas(to_small_length * to_small_length, true); + inner_contour.removeSmallAreas(too_small_length * too_small_length, true); inner_contour = inner_contour.offset(small_area_width / 2); if (prevent_small_exposed_to_air.area() > 0) { From 5a0ae57d33d21c275a59f4ce706e288048a6779b Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 16 Aug 2023 18:04:26 +0200 Subject: [PATCH 09/10] Inner countour needs to be unioned and re-intersected anyway to fix spill. And the union _with_ prevent_small_exposed_to_air doesn't hurt if the area us 0 anyway. Done as part of CURA-10829, but fixes a bug found when QA'ing CURA-10670, which was split off and numbered CURA-10945. --- src/infill.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/infill.cpp b/src/infill.cpp index 279e1ceff3..4f4fd757e4 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -111,10 +111,7 @@ void Infill::generate( inner_contour = inner_contour.offset(-small_area_width / 2); inner_contour.removeSmallAreas(too_small_length * too_small_length, true); inner_contour = inner_contour.offset(small_area_width / 2); - if (prevent_small_exposed_to_air.area() > 0) - { - inner_contour = inner_contour.unionPolygons(prevent_small_exposed_to_air).intersection(small_infill); - } + inner_contour = inner_contour.unionPolygons(prevent_small_exposed_to_air).intersection(small_infill); inner_contour = Simplify(max_resolution, max_deviation, 0).polygon(inner_contour); small_infill = small_infill.difference(inner_contour); From ef687fe2064d4a7f2ad7874ccf92542367a42a9a Mon Sep 17 00:00:00 2001 From: Casper Lamboo Date: Sun, 20 Aug 2023 23:40:13 +0200 Subject: [PATCH 10/10] Update header --- include/sliceDataStorage.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 0d20a90f14..cad566d070 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Ultimaker B.V. +// Copyright (c) 2023 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef SLICE_DATA_STORAGE_H