diff --git a/resources/data/sla_support.svg b/resources/data/sla_support.svg
index d2f4e02c38..7fef16f080 100644
--- a/resources/data/sla_support.svg
+++ b/resources/data/sla_support.svg
@@ -26,13 +26,13 @@
showgrid="false"
showborder="true"
borderlayer="true"
- inkscape:zoom="3.3638608"
- inkscape:cx="92.601929"
- inkscape:cy="110.88449"
- inkscape:window-width="1920"
- inkscape:window-height="1129"
- inkscape:window-x="1912"
- inkscape:window-y="-8"
+ inkscape:zoom="19.02887"
+ inkscape:cx="14.845863"
+ inkscape:cy="132.29897"
+ inkscape:window-width="2400"
+ inkscape:window-height="1261"
+ inkscape:window-x="-9"
+ inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
+ id="tspan9676">Last virtual point of curve is [last.x, ∞]
+ style="stroke-width:2.5" />
diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt
index a19cc5d058..b0021a0012 100644
--- a/src/libslic3r/CMakeLists.txt
+++ b/src/libslic3r/CMakeLists.txt
@@ -473,6 +473,7 @@ set(SLIC3R_SOURCES
SLA/SupportIslands/PostProcessNeighbors.cpp
SLA/SupportIslands/PostProcessNeighbors.hpp
SLA/SupportIslands/SampleConfig.hpp
+ SLA/SupportIslands/SampleConfigFactory.cpp
SLA/SupportIslands/SampleConfigFactory.hpp
SLA/SupportIslands/SampleIslandUtils.cpp
SLA/SupportIslands/SampleIslandUtils.hpp
diff --git a/src/libslic3r/SLA/SupportIslands/SampleConfig.hpp b/src/libslic3r/SLA/SupportIslands/SampleConfig.hpp
index eb40320bad..c82ce54d29 100644
--- a/src/libslic3r/SLA/SupportIslands/SampleConfig.hpp
+++ b/src/libslic3r/SLA/SupportIslands/SampleConfig.hpp
@@ -13,12 +13,12 @@ struct SampleConfig
{
// Every point on island has at least one support point in maximum distance
// MUST be bigger than zero
- coord_t max_distance = 2;
- coord_t half_distance = 1; // has to be half od max_distance
+ coord_t max_distance = static_cast(scale_(5.));
+ coord_t half_distance = static_cast(scale_(2.5)); // has to be half od max_distance
// Support point head radius
// MUST be bigger than zero
- coord_t head_radius = 1; // [nano meter]
+ coord_t head_radius = static_cast(scale_(.4)); // [nano meter]
// When it is possible, there will be this minimal distance from outline.
// zero when head should be on outline
@@ -27,7 +27,7 @@ struct SampleConfig
// Measured as sum of VD edge length from outline
// Used only when there is no space for outline offset on first/last point
// Must be bigger than minimal_distance_from_outline
- coord_t maximal_distance_from_outline = 1.;// [nano meter]
+ coord_t maximal_distance_from_outline = static_cast(scale_(1.));// [nano meter]
// When angle on outline is smaller than max_interesting_angle
// than create unmovable support point.
@@ -44,23 +44,23 @@ struct SampleConfig
// Maximal length of longest path in voronoi diagram to be island
// supported only by one single support point this point will be in center of path.
- coord_t max_length_for_one_support_point = 1.;
+ coord_t max_length_for_one_support_point = static_cast(scale_(1.));
// Maximal length of island supported by 2 points
- coord_t max_length_for_two_support_points = 1.;
+ coord_t max_length_for_two_support_points = static_cast(scale_(1.));
// Maximal width of line island supported in the middle of line
// Must be greater or equal to min_width_for_outline_support
- coord_t max_width_for_center_support_line = 1.;
+ coord_t max_width_for_center_support_line = static_cast(scale_(1.));
// Minimal width to be supported by outline
// Must be smaller or equal to max_width_for_center_support_line
- coord_t min_width_for_outline_support = 1.;
+ coord_t min_width_for_outline_support = static_cast(scale_(1.));
// Term criteria for end of alignment
// Minimal change in manhatn move of support position before termination
- coord_t minimal_move = 1000; // in nanometers, devide from print resolution to quater pixel
+ coord_t minimal_move = static_cast(scale_(.01)); // devide from print resolution to quater pixel
// Maximal count of align iteration
size_t count_iteration = 100;
@@ -75,7 +75,7 @@ struct SampleConfig
// There is no need to calculate with precisse island
// NOTE: Slice of Cylinder bottom has tip of trinagles on contour
// (neighbor coordinate - create issue in voronoi)
- double simplification_tolerance = 1e4; // [nm]
+ double simplification_tolerance = scale_(0.05 /*mm*/);
};
} // namespace Slic3r::sla
#endif // slic3r_SLA_SuppotstIslands_SampleConfig_hpp_
diff --git a/src/libslic3r/SLA/SupportIslands/SampleConfigFactory.cpp b/src/libslic3r/SLA/SupportIslands/SampleConfigFactory.cpp
new file mode 100644
index 0000000000..0bbbdc9abb
--- /dev/null
+++ b/src/libslic3r/SLA/SupportIslands/SampleConfigFactory.cpp
@@ -0,0 +1,104 @@
+#include "SampleConfigFactory.hpp"
+
+using namespace Slic3r::sla;
+
+bool SampleConfigFactory::verify(SampleConfig &cfg) {
+ auto verify_max = [](coord_t &c, coord_t max) {
+ assert(c <= max);
+ if (c > max) {
+ c = max;
+ return false;
+ }
+ return true;
+ };
+ auto verify_min = [](coord_t &c, coord_t min) {
+ assert(c >= min);
+ if (c < min) {
+ c = min;
+ return false;
+ }
+ return true;
+ };
+ auto verify_min_max = [](coord_t &min, coord_t &max) {
+ // min must be smaller than max
+ assert(min < max);
+ if (min > max) {
+ std::swap(min, max);
+ return false;
+ } else if (min == max) {
+ min /= 2; // cut in half
+ return false;
+ }
+ return true;
+ };
+ bool res = true;
+ res &= verify_min_max(cfg.max_length_for_one_support_point, cfg.max_length_for_two_support_points);
+ res &= verify_min_max(cfg.min_width_for_outline_support, cfg.max_width_for_center_support_line); // check histeresis
+ res &= verify_max(cfg.max_length_for_one_support_point,
+ 2 * cfg.max_distance +
+ 2 * cfg.head_radius +
+ 2 * cfg.minimal_distance_from_outline);
+ res &= verify_min(cfg.max_length_for_one_support_point,
+ 2 * cfg.head_radius + 2 * cfg.minimal_distance_from_outline);
+ res &= verify_max(cfg.max_length_for_two_support_points,
+ 2 * cfg.max_distance +
+ 2 * 2 * cfg.head_radius +
+ 2 * cfg.minimal_distance_from_outline);
+ res &= verify_min(cfg.max_width_for_center_support_line,
+ 2 * cfg.head_radius + 2 * cfg.minimal_distance_from_outline);
+ res &= verify_max(cfg.max_width_for_center_support_line,
+ 2 * cfg.max_distance + 2 * cfg.head_radius);
+ if (!res) while (!verify(cfg));
+ return res;
+}
+
+SampleConfig SampleConfigFactory::create(float support_head_diameter_in_mm)
+{
+ coord_t head_diameter = static_cast(scale_(support_head_diameter_in_mm));
+ coord_t minimal_distance = head_diameter * 7;
+ coord_t min_distance = head_diameter / 2 + minimal_distance;
+ coord_t max_distance = 3 * min_distance;
+
+ // TODO: find valid params !!!!
+ SampleConfig result;
+ result.max_distance = max_distance;
+ result.half_distance = result.max_distance / 2;
+ result.head_radius = head_diameter / 2;
+ result.minimal_distance_from_outline = result.head_radius;
+ result.maximal_distance_from_outline = result.max_distance/3;
+ assert(result.minimal_distance_from_outline < result.maximal_distance_from_outline);
+ result.minimal_support_distance = result.minimal_distance_from_outline +
+ result.half_distance;
+
+ result.min_side_branch_length = 2 * result.minimal_distance_from_outline + result.max_distance/4;
+ result.max_length_for_one_support_point =
+ max_distance / 3 +
+ 2 * result.minimal_distance_from_outline +
+ head_diameter;
+ result.max_length_for_two_support_points =
+ result.max_length_for_one_support_point + max_distance / 2;
+ result.max_width_for_center_support_line =
+ 2 * head_diameter + 2 * result.minimal_distance_from_outline +
+ max_distance / 2;
+ result.min_width_for_outline_support = result.max_width_for_center_support_line - 2 * head_diameter;
+ result.outline_sample_distance = 3*result.max_distance/4;
+
+ // Align support points
+ // TODO: propagate print resolution
+ result.minimal_move = scale_(0.1); // 0.1 mm is enough
+ // [in nanometers --> 0.01mm ], devide from print resolution to quater pixel is too strict
+ result.count_iteration = 30; // speed VS precission
+ result.max_align_distance = result.max_distance / 2;
+
+ verify(result);
+ return result;
+}
+
+std::optional SampleConfigFactory::gui_sample_config_opt;
+SampleConfig &SampleConfigFactory::get_sample_config() {
+ // init config
+ if (!gui_sample_config_opt.has_value())
+ // create default configuration
+ gui_sample_config_opt = sla::SampleConfigFactory::create(.4f);
+ return *gui_sample_config_opt;
+}
diff --git a/src/libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp b/src/libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp
index 1f046364c2..762798a0b6 100644
--- a/src/libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp
+++ b/src/libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp
@@ -1,8 +1,9 @@
#ifndef slic3r_SLA_SuppotstIslands_SampleConfigFactory_hpp_
#define slic3r_SLA_SuppotstIslands_SampleConfigFactory_hpp_
+#include
#include "SampleConfig.hpp"
-#include "../SupportPointGenerator.hpp"
+#include "libslic3r/PrintConfig.hpp"
namespace Slic3r::sla {
@@ -14,78 +15,15 @@ class SampleConfigFactory
public:
SampleConfigFactory() = delete;
- // factory method to iniciate config
- static SampleConfig create(const SupportPointGeneratorConfig &config)
- {
- coord_t head_diameter = scale_((double)config.head_diameter.min);
- coord_t minimal_distance = head_diameter * 7;
- coord_t min_distance = head_diameter / 2 + minimal_distance;
- coord_t max_distance = 3 * min_distance;
-
- // TODO: find valid params !!!!
- SampleConfig result;
- result.max_distance = max_distance;
- result.half_distance = result.max_distance / 2;
- result.head_radius = head_diameter / 2;
- result.minimal_distance_from_outline = result.head_radius;
- result.maximal_distance_from_outline = result.max_distance/3;
- assert(result.minimal_distance_from_outline < result.maximal_distance_from_outline);
- result.minimal_support_distance = result.minimal_distance_from_outline +
- result.half_distance;
+ static bool verify(SampleConfig &cfg);
+ static SampleConfig create(float support_head_diameter_in_mm);
- result.min_side_branch_length = 2 * result.minimal_distance_from_outline;
-
- result.max_length_for_one_support_point =
- 2 * result.minimal_distance_from_outline +
- head_diameter;
- coord_t max_length_for_one_support_point =
- 2 * max_distance +
- head_diameter +
- 2 * result.minimal_distance_from_outline;
- if (result.max_length_for_one_support_point > max_length_for_one_support_point)
- result.max_length_for_one_support_point = max_length_for_one_support_point;
- coord_t min_length_for_one_support_point =
- 2 * head_diameter +
- 2 * result.minimal_distance_from_outline;
- if (result.max_length_for_one_support_point < min_length_for_one_support_point)
- result.max_length_for_one_support_point = min_length_for_one_support_point;
-
- result.max_length_for_two_support_points =
- 2 * max_distance + 2 * head_diameter +
- 2 * result.minimal_distance_from_outline;
- coord_t max_length_for_two_support_points =
- 2 * max_distance +
- 2 * head_diameter +
- 2 * result.minimal_distance_from_outline;
- if (result.max_length_for_two_support_points > max_length_for_two_support_points)
- result.max_length_for_two_support_points = max_length_for_two_support_points;
- assert(result.max_length_for_two_support_points > result.max_length_for_one_support_point);
-
- result.max_width_for_center_support_line =
- 2 * head_diameter + 2 * result.minimal_distance_from_outline +
- max_distance / 2;
- coord_t min_width_for_center_support_line = head_diameter + 2 * result.minimal_distance_from_outline;
- if (result.max_width_for_center_support_line < min_width_for_center_support_line)
- result.max_width_for_center_support_line = min_width_for_center_support_line;
- coord_t max_width_for_center_support_line = 2 * max_distance + head_diameter;
- if (result.max_width_for_center_support_line > max_width_for_center_support_line)
- result.max_width_for_center_support_line = max_width_for_center_support_line;
-
- result.min_width_for_outline_support = result.max_width_for_center_support_line - 2 * head_diameter;
- assert(result.min_width_for_outline_support <= result.max_width_for_center_support_line);
-
- result.outline_sample_distance = 3*result.max_distance/4;
-
- // Align support points
- // TODO: propagate print resolution
- result.minimal_move = scale_(0.1); // 0.1 mm is enough
- // [in nanometers --> 0.01mm ], devide from print resolution to quater pixel is too strict
- result.count_iteration = 30; // speed VS precission
- result.max_align_distance = result.max_distance / 2;
-
- return result;
- }
+private:
+ // TODO: REMOVE IT. Do not use in production
+ // Global variable to temporary set configuration from GUI into SLA print steps
+ static std::optional gui_sample_config_opt;
+public:
+ static SampleConfig &get_sample_config();
};
-
} // namespace Slic3r::sla
#endif // slic3r_SLA_SuppotstIslands_SampleConfigFactory_hpp_
diff --git a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp
index 7346773871..670bc71080 100644
--- a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp
+++ b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp
@@ -57,26 +57,84 @@ const ExPolygon &get_expolygon_with_biggest_contour(const ExPolygons &expolygons
}
return *biggest;
}
+
+///
+/// When radius of all points is smaller than max radius set output center and return true
+///
+///
+///
+///
+/// True when Bounding box of points is smaller than max radius
+bool get_center(const Points &points, coord_t max_radius, Point& output_center){
+ if (points.size()<=2)
+ return false;
+ auto it = points.begin();
+ Point min = *it;
+ Point max = *it;
+ for (++it; it != points.end(); ++it) {
+ if (min.x() > it->x()) {
+ min.x() = it->x();
+ if (max.x() - min.x() > max_radius)
+ return false;
+ } else if(max.x() < it->x()) {
+ max.x() = it->x();
+ if (max.x() - min.x() > max_radius)
+ return false;
+ }
+ if (min.y() > it->y()) {
+ min.y() = it->y();
+ if (max.y() - min.y() > max_radius)
+ return false;
+ } else if (max.y() < it->y()) {
+ max.y() = it->y();
+ if (max.y() - min.y() > max_radius)
+ return false;
+ }
+ }
+
+ // prevent overflow of point range, no care about 1 size
+ output_center = min/2 + max/2;
+ return true;
+}
+
+///
+/// Decrease level of detail
+///
+/// Polygon to reduce count of points
+/// Define progressivness of reduction
+/// Simplified island
+ExPolygon get_simplified(const ExPolygon &island, const SampleConfig &config) {
+ //// closing similar to FDM arachne do before voronoi inspiration in make_expolygons inside TriangleMeshSlicer
+ //float closing_radius = scale_(0.0499f);
+ //float offset_out = closing_radius;
+ //float offset_in = -closing_radius;
+ //ExPolygons closed_expolygons = offset2_ex({island}, offset_out, offset_in); // mitter
+ //ExPolygon closed_expolygon = get_expolygon_with_biggest_contour(closed_expolygons);
+ //// "Close" operation still create neighbor pixel for sharp triangle tip - cause VD issues
+
+ ExPolygons simplified_expolygons = island.simplify(config.simplification_tolerance);
+ return simplified_expolygons.empty() ?
+ island : get_expolygon_with_biggest_contour(simplified_expolygons);
+}
+
} // namespace
SupportIslandPoints SampleIslandUtils::uniform_cover_island(
const ExPolygon &island, const SampleConfig &config
) {
- // closing similar to FDM arachne do before voronoi
- // inspired by make_expolygons inside TriangleMeshSlicer
- float closing_radius = scale_(0.0499f);
- float offset_out = closing_radius;
- float offset_in = -closing_radius;
- ExPolygons closed_expolygons = offset2_ex({island}, offset_out, offset_in); // mitter
- ExPolygon closed_expolygon = get_expolygon_with_biggest_contour(closed_expolygons);
+ ExPolygon simplified_island = get_simplified(island, config);
- // "Close" operation create neighbor pixel for sharp triangle tip
- double tolerance = scale_(0.05);
- ExPolygons simplified_expolygons = island.simplify(tolerance);
- ExPolygon simplified_expolygon = get_expolygon_with_biggest_contour(simplified_expolygons);
+ // When island is smaller than minimal-head diameter,
+ // it will be supported whole by support poin in center
+ if (Point center; get_center(simplified_island.contour.points, config.head_radius, center)) {
+ SupportIslandPoints result;
+ result.push_back(std::make_unique(
+ center, SupportIslandInnerPoint::Type::one_bb_center_point));
+ return result;
+ }
Slic3r::Geometry::VoronoiDiagram vd;
- Lines lines = to_lines(simplified_expolygon);
+ Lines lines = to_lines(simplified_island);
vd.construct_voronoi(lines.begin(), lines.end());
Slic3r::Voronoi::annotate_inside_outside(vd, lines);
VoronoiGraph skeleton = VoronoiGraphUtils::create_skeleton(vd, lines);
@@ -976,7 +1034,6 @@ SupportIslandPoints SampleIslandUtils::sample_voronoi_graph(
// every island has to have a point on contour
assert(start_node != nullptr);
longest_path = VoronoiGraphUtils::create_longest_path(start_node);
- // longest_path = create_longest_path_recursive(start_node);
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG_PATH
{
diff --git a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp
index bad9b628f3..2348b84b5f 100644
--- a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp
+++ b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp
@@ -34,6 +34,7 @@ public:
outline, // keep position align with island outline
inner, // point inside wide part, without restriction on move
+ one_bb_center_point, // for island smaller than head radius
undefined
};
diff --git a/src/libslic3r/SLA/SupportPointGenerator.cpp b/src/libslic3r/SLA/SupportPointGenerator.cpp
index 99c8506a12..66236df764 100644
--- a/src/libslic3r/SLA/SupportPointGenerator.cpp
+++ b/src/libslic3r/SLA/SupportPointGenerator.cpp
@@ -10,7 +10,6 @@
#include "libslic3r/KDTreeIndirect.hpp"
// SupportIslands
-#include "libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp"
#include "libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp"
using namespace Slic3r;
@@ -232,7 +231,6 @@ void support_part_overhangs(
(const LayerSupportPoint &support_point, const Point &p) -> bool {
// Debug visualization of all sampled outline
//return false;
-
coord_t r = support_point.current_radius;
Point dp = support_point.position_on_layer - p;
if (std::abs(dp.x()) > r) return false;
@@ -269,9 +267,8 @@ void support_part_overhangs(
/// z coordinate of part
///
void support_island(const LayerPart &part, NearPoints& near_points, float part_z,
- const SupportPointGeneratorConfig &cfg) {
- SampleConfig sample_cfg = SampleConfigFactory::create(cfg);
- SupportIslandPoints samples = SampleIslandUtils::uniform_cover_island(*part.shape, sample_cfg);
+ const SupportPointGeneratorConfig &cfg) {
+ SupportIslandPoints samples = SampleIslandUtils::uniform_cover_island(*part.shape, cfg.island_configuration);
//samples = {std::make_unique(island.contour.centroid())};
for (const SupportIslandPointPtr &sample : samples)
near_points.add(LayerSupportPoint{
@@ -443,6 +440,12 @@ Points sample_overhangs(const LayerPart& part, double dist2) {
void prepare_supports_for_layer(LayerSupportPoints &supports, float layer_z,
const SupportPointGeneratorConfig &config) {
+ auto set_radius = [&config](LayerSupportPoint &support, float radius) {
+ if (!is_approx(config.density_relative, 1.f, 1e-4f)) // exist relative density
+ radius /= config.density_relative;
+ support.current_radius = static_cast(scale_(radius));
+ };
+
const std::vector& curve = config.support_curve;
// calculate support area for each support point as radius
// IMPROVE: use some offsets of previous supported island
@@ -458,7 +461,7 @@ void prepare_supports_for_layer(LayerSupportPoints &supports, float layer_z,
if ((index+1) >= curve.size()) {
// set maximal radius
- support.current_radius = static_cast(scale_(curve.back().x()));
+ set_radius(support, curve.back().x());
continue;
}
// interpolate radius on input curve
@@ -467,7 +470,7 @@ void prepare_supports_for_layer(LayerSupportPoints &supports, float layer_z,
assert(a.y() <= diff_z && diff_z <= b.y());
float t = (diff_z - a.y()) / (b.y() - a.y());
assert(0 <= t && t <= 1);
- support.current_radius = static_cast(scale_(a.x() + t * (b.x() - a.x())));
+ set_radius(support, a.x() + t * (b.x() - a.x()));
}
}
diff --git a/src/libslic3r/SLA/SupportPointGenerator.hpp b/src/libslic3r/SLA/SupportPointGenerator.hpp
index ed310c7ca9..9abd0c9962 100644
--- a/src/libslic3r/SLA/SupportPointGenerator.hpp
+++ b/src/libslic3r/SLA/SupportPointGenerator.hpp
@@ -13,6 +13,7 @@
#include "libslic3r/Point.hpp"
#include "libslic3r/ExPolygon.hpp"
#include "libslic3r/SLA/SupportPoint.hpp"
+#include "libslic3r/SLA/SupportIslands/SampleConfig.hpp"
namespace Slic3r::sla {
@@ -31,7 +32,7 @@ struct SupportPointGeneratorConfig{
///
/// Size range for support point interface (head)
///
- MinMax head_diameter = {0.2f, 0.6f}; // [in mm]
+ float head_diameter = 0.4f; // [in mm]
// FIXME: calculate actual pixel area from printer config:
// const float pixel_area =
@@ -46,6 +47,9 @@ struct SupportPointGeneratorConfig{
// y axis .. mean difference of height(Z)
// Points of lines [in mm]
std::vector support_curve;
+
+ // Configuration for sampling island
+ SampleConfig island_configuration;
};
struct LayerPart; // forward decl.
diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp
index ec5d55719e..5cf8f98aaf 100644
--- a/src/libslic3r/SLAPrintSteps.cpp
+++ b/src/libslic3r/SLAPrintSteps.cpp
@@ -53,6 +53,7 @@
#include "libslic3r/SLA/RasterBase.hpp"
#include "libslic3r/SLA/SupportTree.hpp"
#include "libslic3r/SLA/SupportTreeStrategies.hpp"
+#include "libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp"
#include "libslic3r/SLAPrint.hpp"
#include "libslic3r/TriangleMesh.hpp"
@@ -627,99 +628,104 @@ void SLAPrint::Steps::support_points(SLAPrintObject &po)
BOOST_LOG_TRIVIAL(debug) << "Support point count "
<< mo.sla_support_points.size();
- // Unless the user modified the points or we already did the calculation,
- // we will do the autoplacement. Otherwise we will just blindly copy the
- // frontend data into the backend cache.
- if (mo.sla_points_status != sla::PointsStatus::UserModified) {
- throw_if_canceled();
- sla::SupportPointGeneratorConfig config;
- const SLAPrintObjectConfig& cfg = po.config();
-
- // the density config value is in percents:
- config.density_relative = float(cfg.support_points_density_relative / 100.f);
-
- switch (cfg.support_tree_type) {
- case sla::SupportTreeType::Default:
- case sla::SupportTreeType::Organic:
- config.head_diameter = {float(cfg.support_head_front_diameter), .0};
- break;
- case sla::SupportTreeType::Branching:
- config.head_diameter = {float(cfg.branchingsupport_head_front_diameter), .0};
- break;
- }
-
- // scaling for the sub operations
- double d = objectstep_scale * OBJ_STEP_LEVELS[slaposSupportPoints] / 100.0;
- double init = current_status();
-
- auto statuscb = [this, d, init](unsigned st)
- {
- double current = init + st * d;
- if(std::round(current_status()) < std::round(current))
- report_status(current, OBJ_STEP_LABELS(slaposSupportPoints));
- };
-
- // Construction of this object does the calculation.
- throw_if_canceled();
-
- // TODO: filter small unprintable islands in slices
- // (Island with area smaller than 1 pixel was skipped in support generator)
-
- std::vector slices = po.get_model_slices(); // copy
- const std::vector& heights = po.m_model_height_levels;
- sla::ThrowOnCancel cancel = [this]() { throw_if_canceled(); };
- sla::StatusFunction status = statuscb;
- sla::SupportPointGeneratorData data =
- sla::prepare_generator_data(std::move(slices), heights, cancel, status);
-
- sla::LayerSupportPoints layer_support_points =
- sla::generate_support_points(data, config, cancel, status);
-
- const AABBMesh& emesh = po.m_supportdata->input.emesh;
- // Maximal move of support point to mesh surface,
- // no more than height of layer
- assert(po.m_model_height_levels.size() > 1);
- double allowed_move = (po.m_model_height_levels[1] - po.m_model_height_levels[0]) +
- std::numeric_limits::epsilon();
- sla::SupportPoints support_points =
- sla::move_on_mesh_surface(layer_support_points, emesh, allowed_move, cancel);
-
- throw_if_canceled();
-
- MeshSlicingParamsEx params;
- params.closing_radius = float(po.config().slice_closing_radius.value);
- std::vector blockers =
- slice_volumes(po.model_object()->volumes,
- po.m_model_height_levels, po.trafo(), params,
- [](const ModelVolume *vol) {
- return vol->is_support_blocker();
- });
-
- std::vector enforcers =
- slice_volumes(po.model_object()->volumes,
- po.m_model_height_levels, po.trafo(), params,
- [](const ModelVolume *vol) {
- return vol->is_support_enforcer();
- });
-
- SuppPtMask mask{blockers, enforcers, po.config().support_enforcers_only.getBool()};
- filter_support_points_by_modifiers(support_points, mask, po.m_model_height_levels);
-
- po.m_supportdata->input.pts = support_points;
-
- BOOST_LOG_TRIVIAL(debug)
- << "Automatic support points: "
- << po.m_supportdata->input.pts.size();
-
- // Using RELOAD_SLA_SUPPORT_POINTS to tell the Plater to pass
- // the update status to GLGizmoSlaSupports
- report_status(-1, _u8L("Generating support points"),
- SlicingStatus::RELOAD_SLA_SUPPORT_POINTS);
- } else {
+ if (mo.sla_points_status == sla::PointsStatus::UserModified) {
// There are either some points on the front-end, or the user
// removed them on purpose. No calculation will be done.
po.m_supportdata->input.pts = po.transformed_support_points();
+ return;
}
+ // Unless the user modified the points or we already did the calculation,
+ // we will do the autoplacement. Otherwise we will just blindly copy the
+ // frontend data into the backend cache.
+ // if (mo.sla_points_status != sla::PointsStatus::UserModified)
+
+ throw_if_canceled();
+ const SLAPrintObjectConfig& cfg = po.config();
+
+ // the density config value is in percents:
+ sla::SupportPointGeneratorConfig config;
+ config.density_relative = float(cfg.support_points_density_relative / 100.f);
+
+ switch (cfg.support_tree_type) {
+ case sla::SupportTreeType::Default:
+ case sla::SupportTreeType::Organic:
+ config.head_diameter = float(cfg.support_head_front_diameter);
+ break;
+ case sla::SupportTreeType::Branching:
+ config.head_diameter = float(cfg.branchingsupport_head_front_diameter);
+ break;
+ }
+
+ // copy current configuration for sampling islands
+ config.island_configuration = sla::SampleConfigFactory::get_sample_config();
+
+ // scaling for the sub operations
+ double d = objectstep_scale * OBJ_STEP_LEVELS[slaposSupportPoints] / 100.0;
+ double init = current_status();
+
+ auto statuscb = [this, d, init](unsigned st)
+ {
+ double current = init + st * d;
+ if(std::round(current_status()) < std::round(current))
+ report_status(current, OBJ_STEP_LABELS(slaposSupportPoints));
+ };
+
+ // Construction of this object does the calculation.
+ throw_if_canceled();
+
+ // TODO: filter small unprintable islands in slices
+ // (Island with area smaller than 1 pixel was skipped in support generator)
+
+ std::vector slices = po.get_model_slices(); // copy
+ const std::vector& heights = po.m_model_height_levels;
+ sla::ThrowOnCancel cancel = [this]() { throw_if_canceled(); };
+ sla::StatusFunction status = statuscb;
+ sla::SupportPointGeneratorData data =
+ sla::prepare_generator_data(std::move(slices), heights, cancel, status);
+
+ sla::LayerSupportPoints layer_support_points =
+ sla::generate_support_points(data, config, cancel, status);
+
+ const AABBMesh& emesh = po.m_supportdata->input.emesh;
+ // Maximal move of support point to mesh surface,
+ // no more than height of layer
+ assert(po.m_model_height_levels.size() > 1);
+ double allowed_move = (po.m_model_height_levels[1] - po.m_model_height_levels[0]) +
+ std::numeric_limits::epsilon();
+ sla::SupportPoints support_points =
+ sla::move_on_mesh_surface(layer_support_points, emesh, allowed_move, cancel);
+
+ throw_if_canceled();
+
+ MeshSlicingParamsEx params;
+ params.closing_radius = float(po.config().slice_closing_radius.value);
+ std::vector blockers =
+ slice_volumes(po.model_object()->volumes,
+ po.m_model_height_levels, po.trafo(), params,
+ [](const ModelVolume *vol) {
+ return vol->is_support_blocker();
+ });
+
+ std::vector enforcers =
+ slice_volumes(po.model_object()->volumes,
+ po.m_model_height_levels, po.trafo(), params,
+ [](const ModelVolume *vol) {
+ return vol->is_support_enforcer();
+ });
+
+ SuppPtMask mask{blockers, enforcers, po.config().support_enforcers_only.getBool()};
+ filter_support_points_by_modifiers(support_points, mask, po.m_model_height_levels);
+
+ po.m_supportdata->input.pts = support_points;
+
+ BOOST_LOG_TRIVIAL(debug)
+ << "Automatic support points: "
+ << po.m_supportdata->input.pts.size();
+
+ // Using RELOAD_SLA_SUPPORT_POINTS to tell the Plater to pass
+ // the update status to GLGizmoSlaSupports
+ report_status(-1, _u8L("Generating support points"),
+ SlicingStatus::RELOAD_SLA_SUPPORT_POINTS);
}
void SLAPrint::Steps::support_tree(SLAPrintObject &po)
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index ebcbe1747c..3ec1b2679c 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -22,6 +22,8 @@
#include "libslic3r/PresetBundle.hpp"
#include "libslic3r/SLAPrint.hpp"
+#include "libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp"
+
static const double CONE_RADIUS = 0.25;
static const double CONE_HEIGHT = 0.75;
@@ -677,6 +679,92 @@ RENDER_AGAIN:
}
else { // not in editing mode:
m_imgui->disabled_begin(!is_input_enabled());
+ if (int density = static_cast(get_config_options({"support_points_density_relative"})[0])->value;
+ ImGui::SliderInt("points_density", &density, 0, 200, "%d \%")) {
+ mo->config.set("support_points_density_relative", density);
+ } else if (ImGui::IsItemHovered()) {
+ ImGui::SetTooltip("Divider for the supported radius\nSmaller mean less point(75% -> supported radius is enlaged to 133%, for 50% it is 200% of radius)\nLarger mean more points(125% -> supported radius is reduced to 80%, for value 150% it is 66% of radius, for 200% -> 50%)");
+ }
+
+ if (ImGui::TreeNode("Support islands:")) {
+ sla::SampleConfig &sample_config = sla::SampleConfigFactory::get_sample_config();
+ bool exist_change = false;
+ if (float simplification_tolerance = unscale(sample_config.simplification_tolerance); // [in mm]
+ ImGui::InputFloat("input simplify", &simplification_tolerance, .1f, 1.f, "%.2f mm")) {
+ sample_config.simplification_tolerance = scale_(simplification_tolerance);
+ exist_change = true;
+ } else if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("There is no need to calculate with precisse island\nNOTE: Slice of Cylinder bottom has tip of trinagles on contour\n(neighbor coordinate -> create issue in boost::voronoi)");
+ if (float max_distance = unscale(sample_config.max_distance); // [in mm]
+ ImGui::InputFloat("Max dist", &max_distance, .1f, 1.f, "%.2f mm")) {
+ sample_config.max_distance = scale_(max_distance);
+ sample_config.half_distance = sample_config.max_distance / 2;
+ exist_change = true;
+ } else if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("Every support point on island has at least one support point in maximum distance\nMUST be bigger than zero");
+ ImGui::SameLine(); ImGui::Text("half is %.2f", unscale(sample_config.half_distance));
+ if (float minimal_distance_from_outline = unscale(sample_config.minimal_distance_from_outline); // [in mm]
+ ImGui::InputFloat("from outline", &minimal_distance_from_outline, .1f, 1.f, "%.2f mm")) {
+ sample_config.minimal_distance_from_outline = scale_(minimal_distance_from_outline);
+ exist_change = true;
+ } else if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("When it is possible, there will be this minimal distance from outline.\nZERO when head center should be on outline\nSHOULD be positive number");
+ ImGui::SameLine();
+ if (float maximal_distance_from_outline = unscale(sample_config.maximal_distance_from_outline); // [in mm]
+ ImGui::InputFloat("max from outline", &maximal_distance_from_outline, .1f, 1.f, "%.2f mm")) {
+ sample_config.maximal_distance_from_outline = scale_(maximal_distance_from_outline);
+ exist_change = true;
+ } else if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("Measured as sum of VD edge length from outline\nUsed only when there is no space for outline offset on first/last point\nMust be bigger than minimal_distance_from_outline");
+ ImGui::Text("max_interesting_angle is %.0f", float(sample_config.max_interesting_angle*180/M_PI));
+ if (ImGui::IsItemHovered()) ImGui::SetTooltip(" When angle on outline is smaller than max_interesting_angle\nthan create unmovable support point.\nShould be in range from 90 to 180");
+ if (float minimal_support_distance = unscale(sample_config.minimal_support_distance); // [in mm]
+ ImGui::InputFloat("Thin dist", &minimal_support_distance, .1f, 1.f, "%.2f mm")) {
+ sample_config.minimal_support_distance = scale_(minimal_support_distance);
+ exist_change = true;
+ } else if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("Distinguish when to add support point on Voronoi Diagram\nMUST be bigger than minimal_distance_from_outline\nSmaller -> more supports AND Larger -> less amount");
+ if (float min_side_branch_length = unscale(sample_config.min_side_branch_length); // [in mm]
+ ImGui::InputFloat("min_side_branch_length", &min_side_branch_length, .1f, 1.f, "%.2f mm")) {
+ sample_config.min_side_branch_length = scale_(min_side_branch_length);
+ exist_change = true;
+ } else if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("minimal length of side branch to be sampled\nit is used for sampling in center only");
+ if (float max_for_one = unscale(sample_config.max_length_for_one_support_point); // [in mm]
+ ImGui::InputFloat("Max len for one", &max_for_one, .1f, 1.f, "%.2f mm")) {
+ sample_config.max_length_for_one_support_point = scale_(max_for_one);
+ exist_change = true;
+ } else if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("Maximal island length (longest voronoi path) for support by point in path center");
+ if (float max_for_two = unscale(sample_config.max_length_for_two_support_points); // [in mm]
+ ImGui::InputFloat("Max len for two", &max_for_two, .1f, 1.f, "%.2f mm")) {
+ sample_config.max_length_for_two_support_points = scale_(max_for_two);
+ exist_change = true;
+ } else if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("Maximal island length (longest voronoi path)\n for support by 2 points on path sides");
+ if (float max_width_for_center_support_line = unscale(sample_config.max_width_for_center_support_line); // [in mm]
+ ImGui::InputFloat("thin max width", &max_width_for_center_support_line, .1f, 1.f, "%.2f mm")) {
+ sample_config.max_width_for_center_support_line = scale_(max_width_for_center_support_line);
+ exist_change = true;
+ } else if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("Maximal width of line island supported in the middle of line\nMust be greater or equal to thick min width(to make hysteresis)");
+ if (float min_width_for_outline_support = unscale(sample_config.min_width_for_outline_support); // [in mm]
+ ImGui::InputFloat("thick min width", &min_width_for_outline_support, .1f, 1.f, "%.2f mm")) {
+ sample_config.min_width_for_outline_support = scale_(min_width_for_outline_support);
+ exist_change = true;
+ } else if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("Minimal width to be supported by outline\nMust be smaller or equal to thin max width(to make hysteresis)");
+
+ ImGui::Text("head radius is set to %.2f", unscale(sample_config.head_radius));
+ ImGui::Text("Alignment stop criteria: min_move(%.0f um), iter(%d x), max_VD_move(%.2f mm)", unscale(sample_config.minimal_move)*1000, sample_config.count_iteration,
+ unscale(sample_config.max_align_distance)
+ );
+
+ if (exist_change){
+ sla::SampleConfigFactory::verify(sample_config);
+ }
+ ImGui::TreePop();
+ }
ImGui::Text("Distribution depends on './resources/data/sla_support.svg'\ninstruction for edit are in file");
@@ -720,9 +808,7 @@ RENDER_AGAIN:
// wxGetApp().obj_list()->update_and_show_object_settings_item();
//}
- bool generate = ImGuiPureWrap::button(m_desc.at("auto_generate"));
-
- if (generate)
+ if (ImGuiPureWrap::button(m_desc.at("auto_generate")))
auto_generate();
ImGui::Separator();
diff --git a/tests/sla_print/sla_supptgen_tests.cpp b/tests/sla_print/sla_supptgen_tests.cpp
index bcc8e388df..470c1a6ce3 100644
--- a/tests/sla_print/sla_supptgen_tests.cpp
+++ b/tests/sla_print/sla_supptgen_tests.cpp
@@ -7,6 +7,7 @@
#include
#include
+#include
#include
#include
#include
@@ -17,7 +18,7 @@
using namespace Slic3r;
using namespace Slic3r::sla;
-#define STORE_SAMPLE_INTO_SVG_FILES
+//#define STORE_SAMPLE_INTO_SVG_FILES
TEST_CASE("Overhanging point should be supported", "[SupGen]") {
@@ -304,9 +305,23 @@ ExPolygon create_mountains(double size) {
{size / 7, size}});
}
+/// Neighbor points create trouble for voronoi - test of neccessary offseting(closing) of contour
+ExPolygon create_cylinder_bottom_slice() {
+ indexed_triangle_set its_cylinder = its_make_cylinder(6.6551999999999998, 11.800000000000001);
+ MeshSlicingParams param;
+ Polygons polygons = slice_mesh(its_cylinder, 0.0125000002, param);
+ return ExPolygon{polygons.front()};
+}
+
+ExPolygon load_frog(){
+ TriangleMesh mesh = load_model("frog_legs.obj");
+ std::vector slices = slice_mesh_ex(mesh.its, {0.1f});
+ return slices.front()[1];
+}
+
ExPolygons createTestIslands(double size)
{
- bool useFrogLeg = false;
+ bool useFrogLeg = false;
// need post reorganization of longest path
ExPolygons result = {
// one support point
@@ -338,6 +353,9 @@ ExPolygons createTestIslands(double size)
create_tiny_wide_test_2(3 * size, 2 / 3. * size),
create_tiny_between_holes(3 * size, 2 / 3. * size),
+ ExPolygon(PolygonUtils::create_equilateral_triangle(scale_(18.6))),
+ create_cylinder_bottom_slice(),
+
// still problem
// three support points
ExPolygon(PolygonUtils::create_equilateral_triangle(3 * size)),
@@ -347,14 +365,9 @@ ExPolygons createTestIslands(double size)
create_trinagle_with_hole(size),
create_square_with_hole(size, size / 2),
create_square_with_hole(size, size / 3)
- };
-
- if (useFrogLeg) {
- TriangleMesh mesh = load_model("frog_legs.obj");
- std::vector slices = slice_mesh_ex(mesh.its, {0.1f});
- ExPolygon frog_leg = slices.front()[1];
- result.push_back(frog_leg);
- }
+ };
+ if (useFrogLeg)
+ result.push_back(load_frog());
return result;
}
@@ -403,7 +416,7 @@ Points rasterize(const ExPolygon &island, double distance) {
SupportIslandPoints test_island_sampling(const ExPolygon & island,
const SampleConfig &config)
{
- auto points = SupportPointGenerator::uniform_cover_island(island, config);
+ auto points = SampleIslandUtils::uniform_cover_island(island, config);
Points chck_points = rasterize(island, config.head_radius); // TODO: Use resolution of printer
bool is_ok = true;
@@ -447,7 +460,7 @@ SupportIslandPoints test_island_sampling(const ExPolygon & island,
}
}
CHECK(!points.empty());
- //CHECK(is_ok);
+ CHECK(is_ok);
// all points must be inside of island
for (const auto &point : points) { CHECK(island.contains(point->point)); }
@@ -539,12 +552,6 @@ TEST_CASE("speed sampling", "[hide], [SupGen]") {
size_t count = 1;
- std::vector> result1;
- result1.reserve(islands.size()*count);
- for (size_t i = 0; i> result2;
result2.reserve(islands.size()*count);
for (size_t i = 0; i < count; ++i)
@@ -560,7 +567,7 @@ TEST_CASE("speed sampling", "[hide], [SupGen]") {
#ifdef STORE_SAMPLE_INTO_SVG_FILES
- for (size_t i = 0; i < result1.size(); ++i) {
+ for (size_t i = 0; i < result2.size(); ++i) {
size_t island_index = i % islands.size();
ExPolygon &island = islands[island_index];
@@ -568,9 +575,6 @@ TEST_CASE("speed sampling", "[hide], [SupGen]") {
std::string name = "sample_" + std::to_string(i) + ".svg";
SVG svg(name, LineUtils::create_bounding_box(lines));
svg.draw(island, "lightgray");
- svg.draw_text({0, 0}, ("random samples " + std::to_string(result1[i].size())).c_str(), "blue");
- for (Vec2f &p : result1[i])
- svg.draw((p * 1e6).cast(), "blue", 1e6);
svg.draw_text({0., 5e6}, ("uniform samples " + std::to_string(result2[i].size())).c_str(), "green");
for (Vec2f &p : result2[i])
svg.draw((p * 1e6).cast(), "green", 1e6);
@@ -580,16 +584,17 @@ TEST_CASE("speed sampling", "[hide], [SupGen]") {
///
/// Check for correct sampling of island
-///
///
TEST_CASE("Small islands should be supported in center", "[SupGen], [VoronoiSkeleton]")
{
- double size = 3e7;
- SampleConfig cfg = create_sample_config(size);
- ExPolygons islands = createTestIslands(size);
+ float head_diameter = .4f;
+ SampleConfig cfg = SampleConfigFactory::create(head_diameter);
+ ExPolygons islands = createTestIslands(21 * scale_(head_diameter));
for (ExPolygon &island : islands) {
// information for debug which island cause problem
[[maybe_unused]] size_t debug_index = &island - &islands.front();
+
+ // TODO: index 17 - create field again
auto points = test_island_sampling(island, cfg);
double angle = 3.14 / 3; // cca 60 degree
@@ -601,46 +606,31 @@ TEST_CASE("Small islands should be supported in center", "[SupGen], [VoronoiSkel
}
}
-std::vector sample_old(const ExPolygon &island)
-{
- // Create the support point generator
- static TriangleMesh mesh;
- static AABBMesh emesh(mesh);
- static sla::SupportPointGenerator::Config autogencfg;
- //autogencfg.minimal_distance = 8.f;
- static sla::SupportPointGenerator generator{emesh, autogencfg, [] {}, [](int) {}};
-
- // tear preasure
- float tp = autogencfg.tear_pressure();
- size_t layer_id = 13;
- coordf_t print_z = 11.f;
- SupportPointGenerator::MyLayer layer(layer_id, print_z);
- ExPolygon poly = island;
- BoundingBox bbox(island.contour.points);
- Vec2f centroid;
- float area = island.area();
- float h = 17.f;
- sla::SupportPointGenerator::Structure s(layer, poly, bbox, centroid,area,h);
- auto flag = sla::SupportPointGenerator::IslandCoverageFlags(
- sla::SupportPointGenerator::icfIsNew | sla::SupportPointGenerator::icfWithBoundary);
- SupportPointGenerator::PointGrid3D grid3d;
- generator.uniformly_cover({island}, s, s.area * tp, grid3d, flag);
-
- std::vector result;
- result.reserve(grid3d.grid.size());
- for (auto g : grid3d.grid) {
- const Vec3f &p = g.second.position;
- Vec2f p2f(p.x(), p.y());
- result.emplace_back(scale_(p2f));
- }
- return result;
-}
+//TEST_CASE("Cell polygon check", "") {
+// coord_t max_distance = 9;
+// Points points{Point{0,0}, Point{10,0}};
+// using VD = Slic3r::Geometry::VoronoiDiagram;
+// VD vd;
+// vd.construct_voronoi(points.begin(), points.end());
+// assert(points.size() == vd.cells().size());
+// Polygons cells(points.size());
+// for (const VD::cell_type &cell : vd.cells())
+// cells[cell.source_index()] = VoronoiGraphUtils::to_polygon(cell, points, max_distance);
+//
+// REQUIRE(cells[0].size() >= 3);
+// REQUIRE(cells[1].size() >= 3);
+// Polygons cell_overlaps = intersection(cells[0], cells[1]);
+// double area = 0;
+// for (const Polygon &cell_overlap : cell_overlaps)
+// area += cell_overlap.area();
+// CHECK(area < 1);
+//}
#include
std::vector sample_filip(const ExPolygon &island)
{
static SampleConfig cfg = create_sample_config(1e6);
- SupportIslandPoints points = SupportPointGenerator::uniform_cover_island(island, cfg);
+ SupportIslandPoints points = SampleIslandUtils::uniform_cover_island(island, cfg);
std::vector result;
result.reserve(points.size());
@@ -675,16 +665,8 @@ void store_sample(const std::vector &samples, const ExPolygon& island)
}
TEST_CASE("Compare sampling test", "[hide]")
-{
- enum class Sampling {
- old,
- filip
- } sample_type = Sampling::old;
-
- std::function(const ExPolygon &)> sample =
- (sample_type == Sampling::old) ? sample_old :
- (sample_type == Sampling::filip) ? sample_filip :
- nullptr;
+{
+ std::function(const ExPolygon &)> sample = sample_filip;
ExPolygons islands = createTestIslands(1e6);
ExPolygons islands_big = createTestIslands(3e6);
islands.insert(islands.end(), islands_big.begin(), islands_big.end());
diff --git a/tests/sla_print/sla_test_utils.cpp b/tests/sla_print/sla_test_utils.cpp
index 94d77e1dff..17331335da 100644
--- a/tests/sla_print/sla_test_utils.cpp
+++ b/tests/sla_print/sla_test_utils.cpp
@@ -129,8 +129,7 @@ void test_supports(const std::string &obj_filename,
// Create the support point generator
sla::SupportPointGeneratorConfig autogencfg;
- float head_diam = 2 * supportcfg.head_front_radius_mm;
- autogencfg.head_diameter = {head_diam, head_diam};
+ autogencfg.head_diameter = 2 * supportcfg.head_front_radius_mm;
sla::ThrowOnCancel cancel = []() {};
sla::StatusFunction status = [](int) {};
sla::SupportPointGeneratorData gen_data = sla::prepare_generator_data(std::move(out.model_slices), out.slicegrid, cancel, status);