Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CURA-12352 different minimum layer time for layers that contain overhangs #2187

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
13 changes: 9 additions & 4 deletions include/FanSpeedLayerTime.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//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
Expand All @@ -8,7 +8,7 @@
#include "settings/types/LayerIndex.h"
#include "settings/types/Velocity.h"

namespace cura
namespace cura
{

/*!
Expand All @@ -19,7 +19,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 +28,11 @@ 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;

/*!
* "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
34 changes: 23 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 @@ -115,8 +121,10 @@ 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 contains_overhang_{ false }; //!< Indicates whether this plan contains any overhanging extrusion
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 @@ -295,11 +303,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 @@ -393,6 +401,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 @@ -1000,13 +1019,6 @@ class LayerPlan : public NoCopy
* \return The distance from the start of the current wall line to the first bridge segment
*/
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;
};

} // namespace cura
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
52 changes: 42 additions & 10 deletions src/FffGcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ 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_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 @@ -3080,21 +3081,52 @@ 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);
const coord_t overhang_width = layer_height * std::tan(AngleRadians(overhang_angle));
return fully_supported_region.offset(overhang_width + 10);
};
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)
{
const AngleDegrees overhang_step = (90.0 - wall_overhang_angle) / static_cast<double>(overhang_angles_count);
for (size_t angle_index = 0; 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 = angle_index == 0 ? 1.0_r : overhang_speed_factors[angle_index - 1];

overhang_masks.push_back(LayerPlan::OverhangMask{ get_supported_region(actual_wall_overhang_angle), speed_factor });
}

// Add an empty region, which actually means everything and should be ignored anyway
overhang_masks.push_back(LayerPlan::OverhangMask{ Shape(), overhang_speed_factors.back() });
}
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 @@ -3125,7 +3157,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
Loading