diff --git a/include/FffGcodeWriter.h b/include/FffGcodeWriter.h index 96f504c1e3..7e5908e136 100644 --- a/include/FffGcodeWriter.h +++ b/include/FffGcodeWriter.h @@ -4,6 +4,9 @@ #ifndef GCODE_WRITER_H #define GCODE_WRITER_H +#include +#include + #include "FanSpeedLayerTime.h" #include "LayerPlanBuffer.h" #include "gcodeExport.h" @@ -12,9 +15,6 @@ #include "utils/ExtrusionLine.h" //Processing variable-width paths. #include "utils/NoCopy.h" -#include -#include - namespace cura { @@ -634,10 +634,12 @@ class FffGcodeWriter : public NoCopy * layer. * * \param[in] storage Where the slice data is stored. + * \param[in] support_roof_outlines which polygons to generate roofs for -- originally split-up because of fractional (layer-height) layers + * \param[in] current_roof_config config to be used -- most importantly, support has slightly different configs for fractional (layer-height) layers * \param gcodeLayer The initial planning of the g-code of the layer. * \return Whether any support skin was added to the layer plan. */ - bool addSupportRoofsToGCode(const SliceDataStorage& storage, LayerPlan& gcodeLayer) const; + bool addSupportRoofsToGCode(const SliceDataStorage& storage, const Polygons& support_roof_outlines, const GCodePathConfig& current_roof_config, LayerPlan& gcode_layer) const; /*! * Add the support bottoms to the layer plan \p gcodeLayer of the current diff --git a/include/GCodePathConfig.h b/include/GCodePathConfig.h index 1ee2003195..4531b650aa 100644 --- a/include/GCodePathConfig.h +++ b/include/GCodePathConfig.h @@ -18,6 +18,7 @@ namespace cura */ struct GCodePathConfig { + coord_t z_offset{}; //> infill_area_per_combine_per_density; //!< a list of separated sub-areas which requires different infill densities and combined thicknesses - // for infill_areas[x][n], x means the density level and n means the thickness + PolygonsPart outline; //!< The outline of the support infill area + AABB outline_boundary_box; //!< The boundary box for the infill area + coord_t support_line_width; //!< The support line width + int inset_count_to_generate; //!< The number of insets need to be generated from the outline. This is not the actual insets that will be generated. + std::vector> infill_area_per_combine_per_density; //!< a list of separated sub-areas which requires different infill densities and combined thicknesses + // for infill_areas[x][n], x means the density level and n means the thickness std::vector wall_toolpaths; //!< Any walls go here, not in the areas, where they could be combined vertically (don't combine walls). Binned by inset_idx. coord_t custom_line_distance; + bool use_fractional_config; //!< Request to use the configuration used to fill a partial layer height here, instead of the normal full layer height configuration. - SupportInfillPart(const PolygonsPart& outline, coord_t support_line_width, int inset_count_to_generate = 0, coord_t custom_line_distance = 0 ); + SupportInfillPart(const PolygonsPart& outline, coord_t support_line_width, bool use_fractional_config, int inset_count_to_generate = 0, coord_t custom_line_distance = 0); const Polygons& getInfillArea() const; }; diff --git a/include/pathPlanning/GCodePath.h b/include/pathPlanning/GCodePath.h index 7bbd56c709..da4efd30aa 100644 --- a/include/pathPlanning/GCodePath.h +++ b/include/pathPlanning/GCodePath.h @@ -4,6 +4,9 @@ #ifndef PATH_PLANNING_G_CODE_PATH_H #define PATH_PLANNING_G_CODE_PATH_H +#include +#include + #include "GCodePathConfig.h" #include "SpaceFillType.h" #include "TimeMaterialEstimates.h" @@ -11,9 +14,6 @@ #include "sliceDataStorage.h" #include "utils/IntPoint.h" -#include -#include - namespace cura { @@ -29,6 +29,7 @@ namespace cura */ struct GCodePath { + coord_t z_offset{}; // mesh; //!< Which mesh this path belongs to, if any. If it's not part of any mesh, the mesh should be nullptr; SpaceFillType space_fill_type{}; //!< The type of space filling of which this path is a part diff --git a/include/settings/PathConfigStorage.h b/include/settings/PathConfigStorage.h index e7bd54773a..feafea23bf 100644 --- a/include/settings/PathConfigStorage.h +++ b/include/settings/PathConfigStorage.h @@ -4,14 +4,14 @@ #ifndef SETTINGS_PATH_CONFIGS_H #define SETTINGS_PATH_CONFIGS_H +#include + #include "GCodePathConfig.h" #include "pathPlanning/SpeedDerivatives.h" #include "settings/MeshPathConfigs.h" #include "settings/types/LayerIndex.h" #include "utils/Coord_t.h" -#include - namespace cura { @@ -48,7 +48,9 @@ class PathConfigStorage std::vector prime_tower_config_per_extruder; //!< Configuration for the prime tower per extruder. std::vector support_infill_config; //!< The config used to print the normal support, rather than the support interface + std::vector support_fractional_infill_config; //!< The config used to print the normal support on fractional layer-height parts. GCodePathConfig support_roof_config; //!< The config used to print the dense roofs of support. + GCodePathConfig support_fractional_roof_config; //!< The config used to print the dense roofs of support on fractional layer-height parts. GCodePathConfig support_bottom_config; //!< The config to use to print the dense bottoms of support std::vector mesh_configs; //!< For each meash the config for all its feature types diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 6a362522ef..6db1cd605a 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -212,6 +212,9 @@ class SupportLayer std::vector support_infill_parts; //!< a list of support infill parts Polygons support_bottom; //!< Piece of support below the support and above the model. This must not overlap with any of the support_infill_parts or support_roof. Polygons support_roof; //!< Piece of support above the support and below the model. This must not overlap with any of the support_infill_parts or support_bottom. + // NOTE: This is _all_ of the support_roof, and as such, overlaps with support_fractional_roof! + Polygons support_fractional_roof; //!< If the support distance is not exactly a multiple of the layer height, + // the first part of support just underneath the model needs to be printed at a fracional layer height. Polygons support_mesh_drop_down; //!< Areas from support meshes which should be supported by more support Polygons support_mesh; //!< Areas from support meshes which should NOT be supported by more support Polygons anti_overhang; //!< Areas where no overhang should be detected. @@ -223,6 +226,24 @@ class SupportLayer * \param exclude_polygons_boundary_box The boundary box for the polygons to exclude */ void excludeAreasFromSupportInfillAreas(const Polygons& exclude_polygons, const AABB& exclude_polygons_boundary_box); + + /* Fill up the infill parts for the support with the given support polygons. The support polygons will be split into parts. This also takes into account fractional-height + * support layers. + * + * \param layer_nr Current layer index. + * \param support_fill_per_layer All of the (infill) support (since the layer above might be needed). + * \param support_line_width Line width of the support extrusions. + * \param wall_line_count Wall-line count around the fill. + * \param grow_layer_above (optional, default to 0) In cases where support shrinks per layer up, an appropriate offset may be nescesary. + * \param unionAll (optional, default to false) Wether to 'union all' for the split into parts bit. + */ + void fillInfillParts( + const LayerIndex layer_nr, + const std::vector& support_fill_per_layer, + const coord_t support_line_width, + const coord_t wall_line_count, + const coord_t grow_layer_above = 0, + const bool unionAll = false); }; class SupportStorage diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index d35b38d169..4605960d39 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -2288,7 +2289,7 @@ bool FffGcodeWriter::processInsets( if (mesh_group_settings.get("support_enable")) { const coord_t z_distance_top = mesh.settings.get("support_top_distance"); - const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height) + 1; + const size_t z_distance_top_layers = (z_distance_top / layer_height) + 1; const int support_layer_nr = gcode_layer.getLayerNr() - z_distance_top_layers; if (support_layer_nr > 0) @@ -2692,7 +2693,7 @@ void FffGcodeWriter::processTopBottom( { const coord_t layer_height = mesh_config.inset0_config.getLayerThickness(); const coord_t z_distance_top = mesh.settings.get("support_top_distance"); - const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height) + 1; + const size_t z_distance_top_layers = (z_distance_top / layer_height) + 1; support_layer_nr = layer_nr - z_distance_top_layers; } @@ -3056,13 +3057,21 @@ bool FffGcodeWriter::addSupportToGCode(const SliceDataStorage& storage, LayerPla return support_added; } + if (extruder_nr == support_roof_extruder_nr) + { + support_added |= addSupportRoofsToGCode(storage, support_layer.support_fractional_roof, gcode_layer.configs_storage.support_fractional_roof_config, gcode_layer); + } if (extruder_nr == support_infill_extruder_nr) { support_added |= processSupportInfill(storage, gcode_layer); } if (extruder_nr == support_roof_extruder_nr) { - support_added |= addSupportRoofsToGCode(storage, gcode_layer); + support_added |= addSupportRoofsToGCode( + storage, + support_layer.support_roof.difference(support_layer.support_fractional_roof), + gcode_layer.configs_storage.support_roof_config, + gcode_layer); } if (extruder_nr == support_bottom_extruder_nr) { @@ -3138,11 +3147,13 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer const auto zag_skip_count = infill_extruder.settings.get("support_zag_skip_count"); // create a list of outlines and use PathOrderOptimizer to optimize the travel move + PathOrderOptimizer island_order_optimizer_initial(gcode_layer.getLastPlannedPositionOrStartingPosition()); PathOrderOptimizer island_order_optimizer(gcode_layer.getLastPlannedPositionOrStartingPosition()); for (const SupportInfillPart& part : support_layer.support_infill_parts) { - island_order_optimizer.addPolygon(&part); + (part.use_fractional_config ? island_order_optimizer_initial : island_order_optimizer).addPolygon(&part); } + island_order_optimizer_initial.optimize(); island_order_optimizer.optimize(); const auto support_connect_zigzags = infill_extruder.settings.get("support_connect_zigzags"); @@ -3155,9 +3166,10 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer bool need_travel_to_end_of_last_spiral = true; // Print the thicker infill lines first. (double or more layer thickness, infill combined with previous layers) - for (const PathOrdering& path : island_order_optimizer.paths) + for (const PathOrdering& path : ranges::views::concat(island_order_optimizer_initial.paths, island_order_optimizer.paths)) { const SupportInfillPart& part = *path.vertices; + const auto& configs = part.use_fractional_config ? gcode_layer.configs_storage.support_fractional_infill_config : gcode_layer.configs_storage.support_infill_config; // always process the wall overlap if walls are generated const int current_support_infill_overlap = (part.inset_count_to_generate > 0) ? default_support_infill_overlap : 0; @@ -3167,7 +3179,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer if (! wall_toolpaths.empty()) { - const GCodePathConfig& config = gcode_layer.configs_storage.support_infill_config[0]; + const GCodePathConfig& config = configs[0]; constexpr bool retract_before_outer_wall = false; constexpr coord_t wipe_dist = 0; const ZSeamConfig z_seam_config(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); @@ -3221,7 +3233,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer { support_line_distance_here /= 2; } - const Polygons& area = part.infill_area_per_combine_per_density[density_idx][combine_idx]; + const Polygons& area = Simplify(infill_extruder.settings).polygon(part.infill_area_per_combine_per_density[density_idx][combine_idx]); constexpr size_t wall_count = 0; // Walls are generated somewhere else, so their layers aren't vertically combined. const coord_t small_area_width = 0; @@ -3237,7 +3249,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer current_support_infill_overlap - (density_idx == max_density_idx ? 0 : wall_line_count * support_line_width), infill_multiplier, support_infill_angle, - gcode_layer.z, + gcode_layer.z + configs[combine_idx].z_offset, support_shift, max_resolution, max_deviation, @@ -3301,7 +3313,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer gcode_layer.addPolygonsByOptimizer( support_polygons, - gcode_layer.configs_storage.support_infill_config[combine_idx], + configs[combine_idx], z_seam_config, wall_0_wipe_dist, spiralize, @@ -3322,7 +3334,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer gcode_layer.addLinesByOptimizer( support_lines, - gcode_layer.configs_storage.support_infill_config[combine_idx], + configs[combine_idx], (support_pattern == EFillMethod::ZIG_ZAG) ? SpaceFillType::PolyLines : SpaceFillType::Lines, enable_travel_optimization, wipe_dist, @@ -3338,7 +3350,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer // If not, the pattern may still generate gap filling (if it's connected infill or zigzag). We still want to print those. if (wall_line_count == 0 || ! wall_toolpaths_here.empty()) { - const GCodePathConfig& config = gcode_layer.configs_storage.support_infill_config[0]; + const GCodePathConfig& config = configs[0]; constexpr bool retract_before_outer_wall = false; constexpr coord_t wipe_dist = 0; constexpr coord_t simplify_curvature = 0; @@ -3373,7 +3385,11 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer } -bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, LayerPlan& gcode_layer) const +bool FffGcodeWriter::addSupportRoofsToGCode( + const SliceDataStorage& storage, + const Polygons& support_roof_outlines, + const GCodePathConfig& current_roof_config, + LayerPlan& gcode_layer) const { const SupportLayer& support_layer = storage.support.supportLayers[std::max(LayerIndex{ 0 }, gcode_layer.getLayerNr())]; @@ -3419,7 +3435,7 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay support_roof_line_distance *= roof_extruder.settings.get("initial_layer_line_width_factor"); } - Polygons infill_outline = support_layer.support_roof; + Polygons infill_outline = support_roof_outlines; Polygons wall; // make sure there is a wall if this is on the first layer if (gcode_layer.getLayerNr() == 0) @@ -3427,18 +3443,19 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay wall = support_layer.support_roof.offset(-support_roof_line_width / 2); infill_outline = wall.offset(-support_roof_line_width / 2); } + infill_outline = Simplify(roof_extruder.settings).polygon(infill_outline); Infill roof_computation( pattern, zig_zaggify_infill, connect_polygons, infill_outline, - gcode_layer.configs_storage.support_roof_config.getLineWidth(), + current_roof_config.getLineWidth(), support_roof_line_distance, support_roof_overlap, infill_multiplier, fill_angle, - gcode_layer.z, + gcode_layer.z + current_roof_config.z_offset, extra_infill_shift, max_resolution, max_deviation, @@ -3463,17 +3480,17 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay gcode_layer.setIsInside(false); // going to print stuff outside print object, i.e. support if (gcode_layer.getLayerNr() == 0) { - gcode_layer.addPolygonsByOptimizer(wall, gcode_layer.configs_storage.support_roof_config); + gcode_layer.addPolygonsByOptimizer(wall, current_roof_config); } if (! roof_polygons.empty()) { constexpr bool force_comb_retract = false; gcode_layer.addTravel(roof_polygons[0][0], force_comb_retract); - gcode_layer.addPolygonsByOptimizer(roof_polygons, gcode_layer.configs_storage.support_roof_config); + gcode_layer.addPolygonsByOptimizer(roof_polygons, current_roof_config); } if (! roof_paths.empty()) { - const GCodePathConfig& config = gcode_layer.configs_storage.support_roof_config; + const GCodePathConfig& config = current_roof_config; constexpr bool retract_before_outer_wall = false; constexpr coord_t wipe_dist = 0; const ZSeamConfig z_seam_config(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); @@ -3497,10 +3514,7 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay roof_paths); wall_orderer.addToLayer(); } - gcode_layer.addLinesByOptimizer( - roof_lines, - gcode_layer.configs_storage.support_roof_config, - (pattern == EFillMethod::ZIG_ZAG) ? SpaceFillType::PolyLines : SpaceFillType::Lines); + gcode_layer.addLinesByOptimizer(roof_lines, current_roof_config, (pattern == EFillMethod::ZIG_ZAG) ? SpaceFillType::PolyLines : SpaceFillType::Lines); return true; } diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 4a283c147e..52305a9521 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -3,6 +3,15 @@ #include "LayerPlan.h" +#include +#include +#include +#include + +#include +#include +#include + #include "Application.h" //To communicate layer view data. #include "ExtruderTrain.h" #include "PathOrderMonotonic.h" //Monotonic ordering of skin lines. @@ -20,15 +29,6 @@ #include "utils/polygonUtils.h" #include "utils/section_type.h" -#include -#include -#include - -#include -#include -#include -#include - namespace cura { @@ -38,19 +38,22 @@ constexpr int MINIMUM_SQUARED_LINE_LENGTH = MINIMUM_LINE_LENGTH * MINIMUM_LINE_L GCodePath* LayerPlan::getLatestPathWithConfig( const GCodePathConfig& config, - SpaceFillType space_fill_type, + const SpaceFillType space_fill_type, + const coord_t z_offset, const Ratio flow, const Ratio width_factor, - bool spiralize, + const bool spiralize, const Ratio speed_factor) { std::vector& paths = extruder_plans.back().paths; if (paths.size() > 0 && paths.back().config == config && ! paths.back().done && paths.back().flow == flow && paths.back().width_factor == width_factor - && paths.back().speed_factor == speed_factor && paths.back().mesh == current_mesh) // spiralize can only change when a travel path is in between + && paths.back().speed_factor == speed_factor && paths.back().z_offset == z_offset + && paths.back().mesh == current_mesh) // spiralize can only change when a travel path is in between { return &paths.back(); } - paths.emplace_back(GCodePath{ .config = config, + paths.emplace_back(GCodePath{ .z_offset = z_offset, + .config = config, .mesh = current_mesh, .space_fill_type = space_fill_type, .flow = flow, @@ -326,14 +329,14 @@ std::optional> LayerPlan::getFirstTravelDestinationState( return ret; } -GCodePath& LayerPlan::addTravel(const Point p, const bool force_retract) +GCodePath& LayerPlan::addTravel(const Point& p, const bool force_retract, const coord_t z_offset) { const GCodePathConfig& travel_config = configs_storage.travel_config_per_extruder[getExtruder()]; const RetractionConfig& retraction_config = current_mesh ? current_mesh->retraction_wipe_config.retraction_config : storage.retraction_wipe_config_per_extruder[getExtruder()].retraction_config; - GCodePath* path = getLatestPathWithConfig(travel_config, SpaceFillType::None); + GCodePath* path = getLatestPathWithConfig(travel_config, SpaceFillType::None, z_offset); bool combed = false; @@ -478,7 +481,7 @@ GCodePath& LayerPlan::addTravel(const Point p, const bool force_retract) return ret; } -GCodePath& LayerPlan::addTravel_simple(Point p, GCodePath* path) +GCodePath& LayerPlan::addTravel_simple(const Point& p, GCodePath* path) { bool is_first_travel_of_layer = ! static_cast(last_planned_position); if (is_first_travel_of_layer) @@ -506,16 +509,16 @@ void LayerPlan::planPrime(const float& prime_blob_wipe_length) } void LayerPlan::addExtrusionMove( - Point p, + const Point p, const GCodePathConfig& config, - SpaceFillType space_fill_type, + const SpaceFillType space_fill_type, const Ratio& flow, const Ratio width_factor, - bool spiralize, - Ratio speed_factor, - double fan_speed) + const bool spiralize, + const Ratio speed_factor, + const double fan_speed) { - GCodePath* path = getLatestPathWithConfig(config, space_fill_type, flow, width_factor, spiralize, speed_factor); + GCodePath* path = getLatestPathWithConfig(config, space_fill_type, config.z_offset, flow, width_factor, spiralize, speed_factor); path->points.push_back(p); path->setFanSpeed(fan_speed); if (! static_cast(first_extrusion_acc_jerk)) @@ -537,7 +540,7 @@ void LayerPlan::addPolygon( { constexpr Ratio width_ratio = 1.0_r; // Not printed with variable line width. Point p0 = polygon[start_idx]; - addTravel(p0, always_retract); + addTravel(p0, always_retract, config.z_offset); const int direction = backwards ? -1 : 1; for (size_t point_idx = 1; point_idx < polygon.size(); point_idx++) { @@ -1250,7 +1253,7 @@ void LayerPlan::addLinesInGivenOrder( } else { - addTravel(start); + addTravel(start, false, config.z_offset); } Point p0 = start; @@ -1947,7 +1950,12 @@ void LayerPlan::writeGCode(GCodeExport& gcode) gcode.writeRetraction(retraction_config->retraction_config); } - if (! path.retract && path.config.isTravelPath() && path.points.size() == 1 && path.points[0] == gcode.getPositionXY() && z == gcode.getPositionZ()) + if (z > 0) + { + gcode.setZ(z + path.z_offset); + } + + if (! path.retract && path.config.isTravelPath() && path.points.size() == 1 && path.points[0] == gcode.getPositionXY() && (z + path.z_offset) == gcode.getPositionZ()) { // ignore travel moves to the current location to avoid needless change of acceleration/jerk continue; @@ -2071,7 +2079,7 @@ void LayerPlan::writeGCode(GCodeExport& gcode) // Prevent the final travel(s) from resetting to the 'previous' layer height. gcode.setZ(final_travel_z); } - for (unsigned int point_idx = 0; point_idx < path.points.size() - 1; point_idx++) + for (size_t point_idx = 0; point_idx + 1 < path.points.size(); point_idx++) { gcode.writeTravel(path.points[point_idx], speed); } diff --git a/src/SupportInfillPart.cpp b/src/SupportInfillPart.cpp index 76344af468..ae0b8cf7c1 100644 --- a/src/SupportInfillPart.cpp +++ b/src/SupportInfillPart.cpp @@ -2,17 +2,19 @@ // CuraEngine is released under the terms of the AGPLv3 or higher. #include "SupportInfillPart.h" + #include "support.h" using namespace cura; -SupportInfillPart::SupportInfillPart(const PolygonsPart& outline, coord_t support_line_width, int inset_count_to_generate, coord_t custom_line_distance) -: outline(outline) -, outline_boundary_box(outline) -, support_line_width(support_line_width) -, inset_count_to_generate(inset_count_to_generate) -, custom_line_distance(custom_line_distance) +SupportInfillPart::SupportInfillPart(const PolygonsPart& outline, coord_t support_line_width, bool use_fractional_config, int inset_count_to_generate, coord_t custom_line_distance) + : outline(outline) + , outline_boundary_box(outline) + , support_line_width(support_line_width) + , inset_count_to_generate(inset_count_to_generate) + , custom_line_distance(custom_line_distance) + , use_fractional_config(use_fractional_config) { infill_area_per_combine_per_density.clear(); } diff --git a/src/TreeSupport.cpp b/src/TreeSupport.cpp index c226588ebe..bf876ec582 100644 --- a/src/TreeSupport.cpp +++ b/src/TreeSupport.cpp @@ -3,6 +3,20 @@ #include "TreeSupport.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + #include "Application.h" //To get settings. #include "TreeSupportTipGenerator.h" #include "TreeSupportUtils.h" @@ -18,20 +32,6 @@ #include "utils/polygonUtils.h" //For moveInside. #include "utils/section_type.h" -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - namespace cura { @@ -2226,10 +2226,9 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor support_layer_storage[layer_idx] = support_layer_storage[layer_idx].difference(floor_layer.offset(10)); // Subtract the support floor from the normal support. } - for (PolygonsPart part : support_layer_storage[layer_idx].splitIntoParts(true)) // Convert every part into a PolygonsPart for the support. - { - storage.support.supportLayers[layer_idx].support_infill_parts.emplace_back(part, config.support_line_width, config.support_wall_count); - } + constexpr bool convert_every_part = true; // Convert every part into a PolygonsPart for the support. + storage.support.supportLayers[layer_idx] + .fillInfillParts(layer_idx, support_layer_storage, config.support_line_width, config.support_wall_count, config.maximum_move_distance, convert_every_part); { std::lock_guard critical_section_progress(critical_sections); diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index 99677f9c09..094a819544 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -3,6 +3,17 @@ #include "TreeSupportTipGenerator.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include + #include "Application.h" //To get settings. #include "TreeSupportUtils.h" #include "infill/SierpinskiFillProvider.h" @@ -13,17 +24,6 @@ #include "utils/math.h" //For round_up_divide and PI. #include "utils/polygonUtils.h" //For moveInside. -#include -#include -#include -#include -#include - -#include -#include -#include -#include - namespace cura { @@ -1164,10 +1164,8 @@ void TreeSupportTipGenerator::generateTips( { if (use_fake_roof) { - for (auto part : support_roof_drawn[layer_idx].splitIntoParts()) - { - storage.support.supportLayers[layer_idx].support_infill_parts.emplace_back(part, config.support_line_width, 0, support_roof_line_distance); - } + storage.support.supportLayers[layer_idx] + .fillInfillParts(layer_idx, support_roof_drawn, config.support_line_width, support_roof_line_distance, config.maximum_move_distance); placed_support_lines_support_areas[layer_idx].add(TreeSupportUtils::generateSupportInfillLines( support_roof_drawn[layer_idx], config, @@ -1186,6 +1184,18 @@ void TreeSupportTipGenerator::generateTips( } }); + cura::parallel_for( + 1, + mesh.overhang_areas.size() - z_distance_delta, + [&](const LayerIndex layer_idx) + { + if (layer_idx > 0) + { + storage.support.supportLayers[layer_idx].support_fractional_roof.add( + storage.support.supportLayers[layer_idx].support_roof.difference(storage.support.supportLayers[layer_idx + 1].support_roof)); + } + }); + removeUselessAddedPoints(new_tips, storage, additional_support_areas); for (auto [layer_idx, tips_on_layer] : new_tips | ranges::views::enumerate) diff --git a/src/settings/PathConfigStorage.cpp b/src/settings/PathConfigStorage.cpp index f6e6d1b703..2ecf94eb70 100644 --- a/src/settings/PathConfigStorage.cpp +++ b/src/settings/PathConfigStorage.cpp @@ -150,6 +150,21 @@ PathConfigStorage::PathConfigStorage(const SliceDataStorage& storage, const Laye { handleInitialLayerSpeedup(storage, layer_nr, initial_speedup_layer_count); } + + const auto layer_height = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("layer_height"); + const auto support_top_distance = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("support_top_distance"); + const coord_t leftover_support_distance = support_top_distance % layer_height; + + support_fractional_infill_config = support_infill_config; // copy + for (auto& config : support_fractional_infill_config) + { + config.z_offset = -leftover_support_distance; + config.flow *= Ratio(layer_height - leftover_support_distance, layer_height); + } + + support_fractional_roof_config = support_roof_config; // copy + support_fractional_roof_config.z_offset = -leftover_support_distance; + support_fractional_roof_config.flow *= Ratio(layer_height - leftover_support_distance, layer_height); } void MeshPathConfigs::smoothAllSpeeds(const SpeedDerivatives& first_layer_config, const LayerIndex layer_nr, const LayerIndex max_speed_layer) diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index b9b978d557..fbd4a5d1a9 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -705,4 +705,27 @@ void SupportLayer::excludeAreasFromSupportInfillAreas(const Polygons& exclude_po } } +void SupportLayer::fillInfillParts( + const LayerIndex layer_nr, + const std::vector& support_fill_per_layer, + const coord_t support_line_width, + const coord_t wall_line_count, + const coord_t grow_layer_above /*has default 0*/, + const bool unionAll /*has default false*/) +{ + const Polygons& support_this_layer = support_fill_per_layer[layer_nr]; + const Polygons& support_layer_above + = (layer_nr + 1) >= support_fill_per_layer.size() || layer_nr <= 0 ? Polygons() : support_fill_per_layer[layer_nr + 1].offset(grow_layer_above); + const auto all_support_areas_in_layer = { support_this_layer.difference(support_layer_above), support_this_layer.intersection(support_layer_above) }; + bool use_fractional_config = true; + for (auto& support_areas : all_support_areas_in_layer) + { + for (const PolygonsPart& island_outline : support_areas.splitIntoParts(unionAll)) + { + support_infill_parts.emplace_back(island_outline, support_line_width, use_fractional_config, wall_line_count); + } + use_fractional_config = false; + } +} + } // namespace cura diff --git a/src/support.cpp b/src/support.cpp index 188f2b486d..6bae947fa2 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -3,6 +3,21 @@ #include "support.h" +#include // sqrt, round +#include +#include // ifstream.good() +#include // pair + +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "Application.h" //To get settings. #include "BoostInterface.hpp" #include "ExtruderTrain.h" @@ -24,21 +39,6 @@ #include "utils/math.h" #include "utils/views/get.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include // sqrt, round -#include -#include // ifstream.good() -#include // pair - namespace cura { @@ -106,7 +106,6 @@ void AreaSupport::splitGlobalSupportAreasIntoSupportInfillParts( { // The first layer will be printed with a grid pattern wall_line_count_this_layer++; } - assert(storage.support.supportLayers[layer_nr].support_infill_parts.empty() && "support infill part list is supposed to be uninitialized"); const Polygons& global_support_areas = global_support_areas_per_layer[layer_nr]; if (global_support_areas.size() == 0 || layer_nr < min_layer || layer_nr > max_layer) @@ -116,20 +115,14 @@ void AreaSupport::splitGlobalSupportAreasIntoSupportInfillParts( continue; } - std::vector support_islands = global_support_areas.splitIntoParts(); - for (const PolygonsPart& island_outline : support_islands) + coord_t support_line_width_here = support_line_width; + if (layer_nr == 0 && mesh_group_settings.get("adhesion_type") != EPlatformAdhesion::RAFT) { - coord_t support_line_width_here = support_line_width; - if (layer_nr == 0 && mesh_group_settings.get("adhesion_type") != EPlatformAdhesion::RAFT) - { - support_line_width_here *= infill_extruder.settings.get("initial_layer_line_width_factor"); - } - // We don't generate insets and infill area for the parts yet because later the skirt/brim and prime - // tower will remove themselves from the support, so the outlines of the parts can be changed. - SupportInfillPart support_infill_part(island_outline, support_line_width_here, wall_line_count_this_layer); - - storage.support.supportLayers[layer_nr].support_infill_parts.push_back(support_infill_part); + support_line_width_here *= infill_extruder.settings.get("initial_layer_line_width_factor"); } + // We don't generate insets and infill area for the parts yet because later the skirt/brim and prime + // tower will remove themselves from the support, so the outlines of the parts can be changed. + storage.support.supportLayers[layer_nr].fillInfillParts(layer_nr, global_support_areas_per_layer, support_line_width_here, wall_line_count_this_layer); } } @@ -686,28 +679,26 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage) } } - for (LayerIndex layer_idx = 0; layer_idx < storage.print_layer_count; layer_idx++) + for (Polygons& support_areas : global_support_areas_per_layer) { - Polygons& support_areas = global_support_areas_per_layer[layer_idx]; support_areas = support_areas.unionPolygons(); } // handle support interface - for (unsigned int mesh_idx = 0; mesh_idx < storage.meshes.size(); mesh_idx++) + for (auto& mesh : storage.meshes) { - SliceMeshStorage& mesh = *storage.meshes[mesh_idx]; - if (mesh.settings.get("infill_mesh") || mesh.settings.get("anti_overhang_mesh")) + if (mesh->settings.get("infill_mesh") || mesh->settings.get("anti_overhang_mesh")) { continue; } - if (mesh.settings.get("support_roof_enable")) + if (mesh->settings.get("support_roof_enable")) { - generateSupportRoof(storage, mesh, global_support_areas_per_layer); + generateSupportRoof(storage, *mesh, global_support_areas_per_layer); } - if (mesh.settings.get("support_bottom_enable")) + if (mesh->settings.get("support_bottom_enable")) { - generateSupportBottom(storage, mesh, global_support_areas_per_layer); + generateSupportBottom(storage, *mesh, global_support_areas_per_layer); } } @@ -794,7 +785,7 @@ void AreaSupport::generateOverhangAreasForMesh(SliceDataStorage& storage, SliceM // Don't generate overhang areas if the Z distance is higher than the objects we're generating support for. const coord_t layer_height = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("layer_height"); const coord_t z_distance_top = mesh.settings.get("support_top_distance"); - const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height) + 1; // Support must always be 1 layer below overhang. + const size_t z_distance_top_layers = (z_distance_top / layer_height) + 1; if (z_distance_top_layers + 1 > storage.print_layer_count) { return; @@ -1059,7 +1050,7 @@ void AreaSupport::generateSupportAreasForMesh( // early out const coord_t layer_thickness = mesh_group_settings.get("layer_height"); const coord_t z_distance_top = ((mesh.settings.get("support_roof_enable")) ? roof_settings : infill_settings).get("support_top_distance"); - const size_t layer_z_distance_top = round_up_divide(z_distance_top, layer_thickness) + 1; // support must always be 1 layer below overhang + const size_t layer_z_distance_top = (z_distance_top / layer_thickness) + 1; if (layer_z_distance_top + 1 > layer_count) { return; @@ -1805,7 +1796,7 @@ void AreaSupport::generateSupportRoof(SliceDataStorage& storage, const SliceMesh const double minimum_roof_area = mesh.settings.get("minimum_roof_area"); std::vector& support_layers = storage.support.supportLayers; - for (LayerIndex layer_idx = 0; layer_idx < static_cast(support_layers.size() - z_distance_top); layer_idx++) + for (LayerIndex layer_idx = static_cast(support_layers.size() - z_distance_top) - 1; layer_idx >= 0; --layer_idx) { const LayerIndex top_layer_idx_above{ std::min(LayerIndex{ support_layers.size() - 1 }, LayerIndex{ layer_idx + roof_layer_count + z_distance_top }) @@ -1818,15 +1809,17 @@ void AreaSupport::generateSupportRoof(SliceDataStorage& storage, const SliceMesh Polygons roofs; generateSupportInterfaceLayer(global_support_areas_per_layer[layer_idx], mesh_outlines, roof_line_width, roof_outline_offset, minimum_roof_area, roofs); support_layers[layer_idx].support_roof.add(roofs); + if (layer_idx > 0 && layer_idx < support_layers.size() - 1) + { + support_layers[layer_idx].support_fractional_roof.add(roofs.difference(support_layers[layer_idx + 1].support_roof)); + } scripta::log("support_interface_roofs", roofs, SectionType::SUPPORT, layer_idx); } // Remove support in between the support roof and the model. Subtracts the roof polygons from the support polygons on the layers above it. for (auto [layer_idx, support_layer] : support_layers | ranges::views::enumerate | ranges::views::drop(1) | ranges::views::drop_last(z_distance_top)) { - Polygons roof = support_layer.support_roof; - - if (roof.empty()) + if (support_layer.support_roof.empty()) { continue; } @@ -1835,7 +1828,7 @@ void AreaSupport::generateSupportRoof(SliceDataStorage& storage, const SliceMesh int upper = std::min(static_cast(layer_idx + roof_layer_count + z_distance_top + 5), static_cast(global_support_areas_per_layer.size()) - 1); for (Polygons& global_support : global_support_areas_per_layer | ranges::views::slice(lower, upper)) { - global_support = global_support.difference(roof); + global_support = global_support.difference(support_layer.support_roof); } } } diff --git a/tests/LayerPlanTest.cpp b/tests/LayerPlanTest.cpp index b583005053..e7428f421c 100644 --- a/tests/LayerPlanTest.cpp +++ b/tests/LayerPlanTest.cpp @@ -169,6 +169,7 @@ class LayerPlanTest : public testing::Test settings->add("support_roof_extruder_nr", "0"); settings->add("support_roof_line_width", "0.404"); settings->add("support_roof_material_flow", "104"); + settings->add("support_top_distance", "200"); settings->add("wall_line_count", "3"); settings->add("wall_line_width_x", "0.3"); settings->add("wall_line_width_0", "0.301");