diff --git a/include/settings/types/Angle.h b/include/settings/types/Angle.h index f2814ee3c8..7aeda52bf4 100644 --- a/include/settings/types/Angle.h +++ b/include/settings/types/Angle.h @@ -171,6 +171,19 @@ inline AngleRadians::AngleRadians(const AngleDegrees& value) { } +/*! + * \brief Safe call to "std::tan" which limits the higher angle value to something slightly less that π/2 so that when + * the given angle is higher that this value, the returned value is not a huge number + * \param angle The input angle, which should be [0, π/2] + * \return The tangent value of the angle, limited + * \note This method exists as a convenience because this is a common case in the engine, as we have many settings that + * are angles setup on [0, π/2] and which translate to a distance + */ +inline double boundedTan(const AngleRadians& angle) +{ + return std::tan(std::min(static_cast(angle), std::numbers::pi / 2.0 - 0.001)); +} + } // namespace cura #endif // ANGLE_H diff --git a/src/support.cpp b/src/support.cpp index ea7f4164ef..17a55d855a 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -471,11 +471,11 @@ Shape AreaSupport::join(const SliceDataStorage& storage, const Shape& supportLay coord_t conical_support_offset; if (conical_support_angle > 0) { // outward ==> wider base than overhang - conical_support_offset = -(tan(conical_support_angle) - 0.01) * layer_thickness; + conical_support_offset = -boundedTan(conical_support_angle) * layer_thickness; } else { // inward ==> smaller base than overhang - conical_support_offset = (tan(-conical_support_angle) - 0.01) * layer_thickness; + conical_support_offset = boundedTan(-conical_support_angle) * layer_thickness; } const bool conical_support = infill_settings.get("support_conical_enabled") && conical_support_angle != 0; if (conical_support) @@ -888,7 +888,7 @@ Shape AreaSupport::generateVaryingXYDisallowedArea(const SliceMeshStorage& stora const auto support_distance = z_delta_poly.support_distance; const auto delta_z = z_delta_poly.delta_z; const auto layer_delta = z_delta_poly.layer_delta; - const auto xy_distance_natural = support_distance * std::tan(overhang_angle); + const auto xy_distance_natural = support_distance * boundedTan(overhang_angle); for (auto [current_poly_idx, current_poly] : layer_current | ranges::views::enumerate) { @@ -1244,11 +1244,11 @@ void AreaSupport::generateSupportAreasForMesh( coord_t conical_support_offset; if (conical_support_angle > 0) { // outward ==> wider base than overhang - conical_support_offset = -(tan(conical_support_angle) - 0.01) * layer_thickness; + conical_support_offset = -boundedTan(conical_support_angle) * layer_thickness; } else { // inward ==> smaller base than overhang - conical_support_offset = (tan(-conical_support_angle) - 0.01) * layer_thickness; + conical_support_offset = boundedTan(-conical_support_angle) * layer_thickness; } const bool conical_support = infill_settings.get("support_conical_enabled") && conical_support_angle != 0; for (LayerIndex layer_idx = 1; layer_idx < storage.support.supportLayers.size(); layer_idx++) @@ -1447,7 +1447,7 @@ std::pair AreaSupport::computeBasicAndFullOverhang(const SliceData const coord_t layer_height = mesh.settings.get("layer_height"); const AngleRadians support_angle = mesh.settings.get("support_angle"); - const double tan_angle = tan(support_angle) - 0.01; // The X/Y component of the support angle. 0.01 to make 90 degrees work too. + const double tan_angle = boundedTan(support_angle); // The X/Y component of the support angle // overhang areas protruding less then `max_dist_from_lower_layer` don't need support const coord_t max_dist_from_lower_layer = tan_angle * layer_height; // Maximum horizontal distance that can be bridged. @@ -1576,7 +1576,7 @@ void AreaSupport::handleTowers( } else { - const double tan_tower_roof_angle = tan(tower_roof_angle); + const double tan_tower_roof_angle = boundedTan(tower_roof_angle); tower_roof_expansion_distance = layer_thickness / tan_tower_roof_angle; }