From 6e33f3f5dd11dee5250188b6acc540442fb1295c Mon Sep 17 00:00:00 2001 From: Hanif Koh Date: Fri, 11 Sep 2026 15:58:45 +0800 Subject: [PATCH] Share and Clamp the Build Plate Tilt Shift in Support Generators The three support generators each computed lh * tan(tilt), which overflows coord_t at 90 degrees and flips sign beyond it (belt sync can write up to 180). One helper now returns the tilt slope with the tilt capped at 89 degrees. --- src/libslic3r/Support/SupportCommon.cpp | 6 ++++++ src/libslic3r/Support/SupportCommon.hpp | 4 ++++ src/libslic3r/Support/SupportMaterial.cpp | 10 +++------- src/libslic3r/Support/TreeSupport.cpp | 10 +++------- src/libslic3r/Support/TreeSupport3D.cpp | 12 ++++-------- 5 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/libslic3r/Support/SupportCommon.cpp b/src/libslic3r/Support/SupportCommon.cpp index 27ac9b24d1..0c3d570b1d 100644 --- a/src/libslic3r/Support/SupportCommon.cpp +++ b/src/libslic3r/Support/SupportCommon.cpp @@ -2069,4 +2069,10 @@ sub clip_with_shape { } */ +Vec2d build_plate_tilt_slope(const PrintConfig &print_config) +{ + auto slope = [](double tilt_deg) { return std::tan(Geometry::deg2rad(std::clamp(tilt_deg, -89., 89.))); }; + return { slope(print_config.build_plate_tilt_y.value), slope(print_config.build_plate_tilt_x.value) }; +} + } // namespace Slic3r diff --git a/src/libslic3r/Support/SupportCommon.hpp b/src/libslic3r/Support/SupportCommon.hpp index f15c7d417a..4374986a3e 100644 --- a/src/libslic3r/Support/SupportCommon.hpp +++ b/src/libslic3r/Support/SupportCommon.hpp @@ -150,6 +150,10 @@ Polygons belt_floor_surface_polygon( const SlicingParameters &slicing_params, const PrintConfig &print_config, const PrintObject &object, coordf_t print_z); +// Build plate tilt: XY drift of gravity per unit of layer height, zero on a level plate. +// The tilt is capped below 90 degrees to keep the drift finite. +Vec2d build_plate_tilt_slope(const PrintConfig &print_config); + } // namespace Slic3r #endif /* slic3r_SupportCommon_hpp_ */ diff --git a/src/libslic3r/Support/SupportMaterial.cpp b/src/libslic3r/Support/SupportMaterial.cpp index c8ac217af2..5d886bcdf0 100644 --- a/src/libslic3r/Support/SupportMaterial.cpp +++ b/src/libslic3r/Support/SupportMaterial.cpp @@ -1438,9 +1438,8 @@ static inline ExPolygons detect_overhangs( const bool bridge_no_support = object_config.bridge_no_support.value; const coordf_t xy_expansion = scale_(object_config.support_expansion.value); // Build plate tilt: compute per-layer XY shift for tilted gravity direction - const double tilt_x_rad = Geometry::deg2rad(print_config.build_plate_tilt_x.value); - const double tilt_y_rad = Geometry::deg2rad(print_config.build_plate_tilt_y.value); - const bool has_tilt = std::abs(tilt_x_rad) > EPSILON || std::abs(tilt_y_rad) > EPSILON; + const Vec2d tilt_slope = build_plate_tilt_slope(print_config); + const bool has_tilt = tilt_slope.cwiseAbs().maxCoeff() > EPSILON; float lower_layer_offset = 0; if (layer_id == 0) @@ -1480,10 +1479,7 @@ static inline ExPolygons detect_overhangs( Polygons tilted_lower; if (has_tilt) { tilted_lower = lower_layer_polygons; - const double lh = lower_layer.height; - Point tilt_shift(coord_t(scale_(lh * tan(tilt_y_rad))), - coord_t(scale_(lh * tan(tilt_x_rad)))); - translate(tilted_lower, tilt_shift); + translate(tilted_lower, Point::new_scale(tilt_slope * lower_layer.height)); effective_lower = &tilted_lower; } diff --git a/src/libslic3r/Support/TreeSupport.cpp b/src/libslic3r/Support/TreeSupport.cpp index 84ae229130..a86aea3536 100644 --- a/src/libslic3r/Support/TreeSupport.cpp +++ b/src/libslic3r/Support/TreeSupport.cpp @@ -709,9 +709,8 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/) const double threshold_rad = Geometry::deg2rad(thresh_angle); // Build plate tilt: compute per-layer XY shift for tilted gravity direction const PrintConfig& print_cfg = m_object->print()->config(); - const double tilt_x_rad = Geometry::deg2rad(print_cfg.build_plate_tilt_x.value); - const double tilt_y_rad = Geometry::deg2rad(print_cfg.build_plate_tilt_y.value); - const bool has_tilt = std::abs(tilt_x_rad) > EPSILON || std::abs(tilt_y_rad) > EPSILON; + const Vec2d tilt_slope = build_plate_tilt_slope(print_cfg); + const bool has_tilt = tilt_slope.cwiseAbs().maxCoeff() > EPSILON; // FIXME this is a fudge constant! double support_tree_tip_diameter = 0.8; auto enforcer_overhang_offset = scaled(support_tree_tip_diameter); @@ -858,10 +857,7 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/) ExPolygons shifted_lower; if (has_tilt) { shifted_lower = lower_polys; // copy - const double lh = lower_layer->height; - Point tilt_shift(coord_t(scale_(lh * tan(tilt_y_rad))), - coord_t(scale_(lh * tan(tilt_x_rad)))); - translate(shifted_lower, tilt_shift); + translate(shifted_lower, Point::new_scale(tilt_slope * lower_layer->height)); } const ExPolygons &effective_lower = has_tilt ? shifted_lower : lower_polys; diff --git a/src/libslic3r/Support/TreeSupport3D.cpp b/src/libslic3r/Support/TreeSupport3D.cpp index e02f474420..b5c35bfd6b 100644 --- a/src/libslic3r/Support/TreeSupport3D.cpp +++ b/src/libslic3r/Support/TreeSupport3D.cpp @@ -211,9 +211,8 @@ static std::vector>> group_me // +1 makes the threshold inclusive double tan_threshold = support_threshold_auto ? 0. : tan(M_PI * double(support_threshold + 1) / 180.); // Build plate tilt: compute per-layer XY shift for tilted gravity direction - const double tilt_x_rad = Geometry::deg2rad(print_config.build_plate_tilt_x.value); - const double tilt_y_rad = Geometry::deg2rad(print_config.build_plate_tilt_y.value); - const bool has_tilt = std::abs(tilt_x_rad) > EPSILON || std::abs(tilt_y_rad) > EPSILON; + const Vec2d tilt_slope = build_plate_tilt_slope(print_config); + const bool has_tilt = tilt_slope.cwiseAbs().maxCoeff() > EPSILON; //FIXME this is a fudge constant! auto enforcer_overhang_offset = scaled(config.tree_support_tip_diameter.value); const coordf_t radius_sample_resolution = g_config_tree_support_collision_resolution; @@ -235,7 +234,7 @@ static std::vector>> group_me size_t num_overhang_layers = support_auto ? num_object_layers : std::min(num_object_layers, std::max(size_t(support_enforce_layers), enforcers_layers.size())); tbb::parallel_for(tbb::blocked_range(1, num_overhang_layers), [&print_object, &config, &print_config, &enforcers_layers, &blockers_layers, - support_auto, support_enforce_layers, support_threshold_auto, tan_threshold, enforcer_overhang_offset, num_raft_layers, radius_sample_resolution, has_tilt, tilt_x_rad, tilt_y_rad, &throw_on_cancel, &out] + support_auto, support_enforce_layers, support_threshold_auto, tan_threshold, enforcer_overhang_offset, num_raft_layers, radius_sample_resolution, has_tilt, tilt_slope, &throw_on_cancel, &out] (const tbb::blocked_range &range) { for (LayerIndex layer_id = range.begin(); layer_id < range.end(); ++ layer_id) { const Layer ¤t_layer = *print_object.get_layer(layer_id); @@ -263,10 +262,7 @@ static std::vector>> group_me Polygons lower_layer_offseted; if (has_tilt) { Polygons lower_src = to_polygons(lower_layer.lslices_extrudable); - const double lh = lower_layer.height; - Point tilt_shift(coord_t(scale_(lh * tan(tilt_y_rad))), - coord_t(scale_(lh * tan(tilt_x_rad)))); - translate(lower_src, tilt_shift); + translate(lower_src, Point::new_scale(tilt_slope * lower_layer.height)); lower_layer_offseted = offset(lower_src, lower_layer_offset); } else { lower_layer_offseted = offset(lower_layer.lslices_extrudable, lower_layer_offset);