Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into CURA-11978_retract-an…
Browse files Browse the repository at this point in the history
…d-unretract-in-a-travel
  • Loading branch information
wawanbreton committed Feb 5, 2025
2 parents 270b1b5 + 2dec76d commit 84be5f5
Show file tree
Hide file tree
Showing 69 changed files with 1,321 additions and 121 deletions.
857 changes: 857 additions & 0 deletions doc/gradual_overhang_speed.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 16 additions & 4 deletions include/FanSpeedLayerTime.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
//Copyright (c) 2020 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.
// Copyright (c) 2020 Ultimaker B.V.
// CuraEngine is released under the terms of the AGPLv3 or higher.

#ifndef FAN_SPEED_LAYER_TIME_H
#define FAN_SPEED_LAYER_TIME_H

#include <utils/Coord_t.h>

#include "settings/types/Duration.h"
#include "settings/types/LayerIndex.h"
#include "settings/types/Velocity.h"

namespace cura
namespace cura
{

/*!
Expand All @@ -19,7 +21,7 @@ namespace cura
* store these settings over and over again for each part, even though the
* settings may be different for each part on a layer.
*/
struct FanSpeedLayerTimeSettings
struct FanSpeedLayerTimeSettings
{
public:
/*!
Expand All @@ -28,6 +30,16 @@ struct FanSpeedLayerTimeSettings
*/
Duration cool_min_layer_time;

/*!
* Similar to Minimum layer time, but to be applied for layers that contain overhanging extrusion.
*/
Duration cool_min_layer_time_overhang;

/*!
* The specific minimum layer time for overhanging will be applied only if there is at least one overhanging segment longer that this threshold
*/
coord_t cool_min_layer_time_overhang_min_segment_length;

/*!
* "Regular/Maximum Fan Speed Threshold". If the layers take longer to print
* than this, they'll use the regular fan speed. If they take shorter, we'll
Expand Down
37 changes: 26 additions & 11 deletions include/LayerPlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ class LayerPlan : public NoCopy
#endif

public:
struct OverhangMask
{
Shape supported_region;
Ratio speed_ratio;
};

const PathConfigStorage configs_storage_; //!< The line configs for this layer for each feature type
const coord_t z_;
coord_t final_travel_z_;
Expand Down Expand Up @@ -129,8 +135,13 @@ class LayerPlan : public NoCopy
Comb* comb_;
coord_t comb_move_inside_distance_; //!< Whenever using the minimum boundary for combing it tries to move the coordinates inside by this distance after calculating the combing.
Shape bridge_wall_mask_; //!< The regions of a layer part that are not supported, used for bridging
Shape overhang_mask_; //!< The regions of a layer part where the walls overhang
std::vector<OverhangMask> overhang_masks_; //!< The regions of a layer part where the walls overhang, calculated for multiple overhang angles. The latter is the most
//!< overhanging. For a visual explanation of the result, see doc/gradual_overhang_speed.svg
Shape seam_overhang_mask_; //!< The regions of a layer part where the walls overhang, specifically as defined for the seam
bool currently_overhanging_{ false }; //!< Indicates whether the last extrusion move was overhanging
coord_t current_overhang_length_{ 0 }; //!< When doing consecutive overhanging moves, this is the current accumulated overhanging length
coord_t max_overhang_length_{ 0 }; //!< From all consecutive overhanging moves in the layer, this is the longest one

Shape roofing_mask_; //!< The regions of a layer part where the walls are exposed to the air

bool min_layer_time_used = false; //!< Wether or not the minimum layer time (cool_min_layer_time) was actually used in this layerplan.
Expand Down Expand Up @@ -309,11 +320,11 @@ class LayerPlan : public NoCopy
void setBridgeWallMask(const Shape& polys);

/*!
* Set overhang_mask.
* Set overhang_masks.
*
* \param polys The overhung areas of the part currently being processed that will require modified print settings
* \param masks The overhung areas of the part currently being processed that will require modified print settings
*/
void setOverhangMask(const Shape& polys);
void setOverhangMasks(const std::vector<OverhangMask>& masks);

/*!
* Set seam_overhang_mask.
Expand Down Expand Up @@ -407,6 +418,17 @@ class LayerPlan : public NoCopy
const double fan_speed = GCodePathConfig::FAN_SPEED_DEFAULT,
const bool travel_to_z = true);

void addExtrusionMoveWithGradualOverhang(
const Point3LL& p,
const GCodePathConfig& config,
const SpaceFillType space_fill_type,
const Ratio& flow = 1.0_r,
const Ratio width_factor = 1.0_r,
const bool spiralize = false,
const Ratio speed_factor = 1.0_r,
const double fan_speed = GCodePathConfig::FAN_SPEED_DEFAULT,
const bool travel_to_z = true);

/*!
* Add polygon to the gcode starting at vertex \p startIdx
* \param polygon The polygon
Expand Down Expand Up @@ -1021,13 +1043,6 @@ class LayerPlan : public NoCopy
*/
coord_t computeDistanceToBridgeStart(const ExtrusionLine& wall, const size_t current_index, const coord_t min_bridge_line_len) const;

/*!
* \brief Calculates whether the given segment is to be treated as overhanging
* \param p0 The start point of the segment
* \param p1 The end point of the segment
*/
bool segmentIsOnOverhang(const Point3LL& p0, const Point3LL& p1) const;

/*!
* Compute the Z-hop and travel duration for the given travel path
* @param gcode The gcode exporter, which we need to get the current nozzle position
Expand Down
8 changes: 8 additions & 0 deletions include/geometry/Shape.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,14 @@ class Shape : public LinesSet<Polygon>
*/
void simplify(ClipperLib::PolyFillType fill_type = ClipperLib::pftEvenOdd);

/*!
* Calculates the intersections between the given segment and all the segments of the shape
* @param start The start position of the segment
* @param end The end position of the segment
* @return The parameters of the intersections on the segment (intersection = start + t * (end - start)), unsorted
*/
std::vector<float> intersectionsWithSegment(const Point2LL& start, const Point2LL& end) const;

#ifdef BUILD_TESTS
/*!
* @brief Import the polygon from a WKT string
Expand Down
90 changes: 80 additions & 10 deletions src/FffGcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <optional>
#include <unordered_set>

#include <range/v3/view/chunk_by.hpp>
#include <range/v3/view/concat.hpp>
#include <spdlog/spdlog.h>

Expand Down Expand Up @@ -318,6 +319,8 @@ void FffGcodeWriter::setConfigFanSpeedLayerTime()
fan_speed_layer_time_settings_per_extruder.emplace_back();
FanSpeedLayerTimeSettings& fan_speed_layer_time_settings = fan_speed_layer_time_settings_per_extruder.back();
fan_speed_layer_time_settings.cool_min_layer_time = train.settings_.get<Duration>("cool_min_layer_time");
fan_speed_layer_time_settings.cool_min_layer_time_overhang = train.settings_.get<Duration>("cool_min_layer_time_overhang");
fan_speed_layer_time_settings.cool_min_layer_time_overhang_min_segment_length = train.settings_.get<coord_t>("cool_min_layer_time_overhang_min_segment_length");
fan_speed_layer_time_settings.cool_min_layer_time_fan_speed_max = train.settings_.get<Duration>("cool_min_layer_time_fan_speed_max");
fan_speed_layer_time_settings.cool_fan_speed_0 = train.settings_.get<Ratio>("cool_fan_speed_0") * 100.0;
fan_speed_layer_time_settings.cool_fan_speed_min = train.settings_.get<Ratio>("cool_fan_speed_min") * 100.0;
Expand Down Expand Up @@ -3084,21 +3087,88 @@ bool FffGcodeWriter::processInsets(
gcode_layer.setBridgeWallMask(Shape());
}

const auto get_overhang_region = [&](const AngleDegrees overhang_angle) -> Shape
const Shape fully_supported_region = outlines_below.offset(-half_outer_wall_width);
const Shape part_print_region = part.outline.offset(-half_outer_wall_width);

const auto get_supported_region = [&fully_supported_region, &layer_height](const AngleDegrees& overhang_angle) -> Shape
{
if (overhang_angle >= 90)
{
return Shape(); // keep empty to disable overhang detection
}
// the overhang mask is set to the area of the current part's outline minus the region that is considered to be supported
// the supported region is made up of those areas that really are supported by either model or support on the layer below
// expanded to take into account the overhang angle, the greater the overhang angle, the larger the supported area is
// considered to be
const coord_t overhang_width = layer_height * std::tan(overhang_angle / (180 / std::numbers::pi));
return part.outline.offset(-half_outer_wall_width).difference(outlines_below.offset(10 + overhang_width - half_outer_wall_width)).offset(10);
if (overhang_angle < 90.0)
{
const coord_t overhang_width = layer_height * std::tan(AngleRadians(overhang_angle));
return fully_supported_region.offset(overhang_width + 10);
}

return Shape();
};
gcode_layer.setOverhangMask(get_overhang_region(mesh.settings.get<AngleDegrees>("wall_overhang_angle")));
gcode_layer.setSeamOverhangMask(get_overhang_region(mesh.settings.get<AngleDegrees>("seam_overhang_angle")));

// Build supported regions for all the overhang speeds. For a visual explanation of the result, see doc/gradual_overhang_speed.svg
std::vector<LayerPlan::OverhangMask> overhang_masks;
const auto overhang_speed_factors = mesh.settings.get<std::vector<Ratio>>("wall_overhang_speed_factors");
const size_t overhang_angles_count = overhang_speed_factors.size();
const auto wall_overhang_angle = mesh.settings.get<AngleDegrees>("wall_overhang_angle");
if (overhang_angles_count > 0 && wall_overhang_angle < 90.0)
{
struct SpeedRegion
{
AngleDegrees overhang_angle;
Ratio speed_factor;
bool chunk = true;
};

// Create raw speed regions
const AngleDegrees overhang_step = (90.0 - wall_overhang_angle) / static_cast<double>(overhang_angles_count);
std::vector<SpeedRegion> speed_regions;
speed_regions.reserve(overhang_angles_count + 2);

constexpr bool dont_chunk_first = false; // Never merge internal region in order to detect actual overhanging
speed_regions.push_back(SpeedRegion{ wall_overhang_angle, 1.0_r, dont_chunk_first }); // Initial internal region, always 100% speed factor

for (size_t angle_index = 1; angle_index <= overhang_angles_count; ++angle_index)
{
const AngleDegrees actual_wall_overhang_angle = wall_overhang_angle + static_cast<double>(angle_index) * overhang_step;
const Ratio speed_factor = overhang_speed_factors[angle_index - 1];

speed_regions.push_back(SpeedRegion{ actual_wall_overhang_angle, speed_factor });
}

speed_regions.push_back(SpeedRegion{ 90.0, overhang_speed_factors.back() }); // Final "everything else" speed region

// Now merge regions that have similar speed factors (saves calculations and avoid generating micro-segments)
auto merged_regions = speed_regions
| ranges::views::chunk_by(
[](const auto& region_a, const auto& region_b)
{
return region_a.chunk && region_b.chunk && region_a.speed_factor == region_b.speed_factor;
});

// If finally necessary, add actual calculated speed regions
if (ranges::distance(merged_regions) > 1)
{
for (const auto& regions : merged_regions)
{
const SpeedRegion& last_region = *ranges::prev(regions.end());
overhang_masks.push_back(LayerPlan::OverhangMask{ get_supported_region(last_region.overhang_angle), last_region.speed_factor });
}
}
}
gcode_layer.setOverhangMasks(overhang_masks);

// the seam overhang mask is set to the area of the current part's outline minus the region that is considered to be supported,
// which will then be empty if everything is considered supported i.r.t. the angle
const AngleDegrees seam_overhang_angle = mesh.settings.get<AngleDegrees>("seam_overhang_angle");
if (seam_overhang_angle < 90.0)
{
const Shape supported_region_seam = get_supported_region(seam_overhang_angle);
gcode_layer.setSeamOverhangMask(part_print_region.difference(supported_region_seam).offset(10));
}
else
{
gcode_layer.setSeamOverhangMask(Shape());
}

const auto roofing_mask_fn = [&]() -> Shape
{
Expand Down Expand Up @@ -3129,7 +3199,7 @@ bool FffGcodeWriter::processInsets(
// clear to disable use of bridging settings
gcode_layer.setBridgeWallMask(Shape());
// clear to disable overhang detection
gcode_layer.setOverhangMask(Shape());
gcode_layer.setOverhangMasks({});
// clear to disable overhang detection
gcode_layer.setSeamOverhangMask(Shape());
// clear to disable use of roofing settings
Expand Down
Loading

0 comments on commit 84be5f5

Please sign in to comment.