diff --git a/src/libslic3r/ElephantFootCompensation.cpp b/src/libslic3r/ElephantFootCompensation.cpp index 2694b5e8a..130f1b58f 100644 --- a/src/libslic3r/ElephantFootCompensation.cpp +++ b/src/libslic3r/ElephantFootCompensation.cpp @@ -524,11 +524,10 @@ static inline void smooth_compensation_banded(const Points &contour, float band, } } -ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, const Flow &external_perimeter_flow, const double compensation) +ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, double min_contour_width, const double compensation) { - // The contour shall be wide enough to apply the external perimeter plus compensation on both sides. - double min_contour_width = double(external_perimeter_flow.scaled_width() + external_perimeter_flow.scaled_spacing()); double scaled_compensation = scale_(compensation); + min_contour_width = scale_(min_contour_width); double min_contour_width_compensated = min_contour_width + 2. * scaled_compensation; // Make the search radius a bit larger for the averaging in contour_distance over a fan of rays to work. double search_radius = min_contour_width_compensated + min_contour_width * 0.5; @@ -593,10 +592,21 @@ ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, const Flow & assert(out_vec.size() == 1); } } + + // FIXME: orientations are messed up (Tamas) + out.contour.make_counter_clockwise(); + for (auto &h : out.holes) h.make_clockwise(); return out; } +ExPolygon elephant_foot_compensation(const ExPolygon &input, const Flow &external_perimeter_flow, const double compensation) +{ + // The contour shall be wide enough to apply the external perimeter plus compensation on both sides. + double min_contour_width = double(external_perimeter_flow.width + external_perimeter_flow.spacing()); + return elephant_foot_compensation(input, min_contour_width, compensation); +} + ExPolygons elephant_foot_compensation(const ExPolygons &input, const Flow &external_perimeter_flow, const double compensation) { ExPolygons out; @@ -606,4 +616,13 @@ ExPolygons elephant_foot_compensation(const ExPolygons &input, const Flow &exter return out; } +ExPolygons elephant_foot_compensation(const ExPolygons &input, double min_contour_width, const double compensation) +{ + ExPolygons out; + out.reserve(input.size()); + for (const ExPolygon &expoly : input) + out.emplace_back(elephant_foot_compensation(expoly, min_contour_width, compensation)); + return out; +} + } // namespace Slic3r diff --git a/src/libslic3r/ElephantFootCompensation.hpp b/src/libslic3r/ElephantFootCompensation.hpp index 0119df1af..beb17d10b 100644 --- a/src/libslic3r/ElephantFootCompensation.hpp +++ b/src/libslic3r/ElephantFootCompensation.hpp @@ -8,6 +8,8 @@ namespace Slic3r { class Flow; +ExPolygon elephant_foot_compensation(const ExPolygon &input, double min_countour_width, const double compensation); +ExPolygons elephant_foot_compensation(const ExPolygons &input, double min_countour_width, const double compensation); ExPolygon elephant_foot_compensation(const ExPolygon &input, const Flow &external_perimeter_flow, const double compensation); ExPolygons elephant_foot_compensation(const ExPolygons &input, const Flow &external_perimeter_flow, const double compensation); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index f1daebf54..40ea1772e 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -113,6 +113,16 @@ void PrintConfigDef::init_common_params() "If left blank, the default OS CA certificate repository is used."); def->mode = comAdvanced; def->set_default_value(new ConfigOptionString("")); + + def = this->add("elefant_foot_compensation", coFloat); + def->label = L("Elephant foot compensation"); + def->category = L("Advanced"); + def->tooltip = L("The first layer will be shrunk in the XY plane by the configured value " + "to compensate for the 1st layer squish aka an Elephant Foot effect."); + def->sidetext = L("mm"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(0.2)); } void PrintConfigDef::init_fff_params() @@ -371,16 +381,6 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->set_default_value(new ConfigOptionFloat(6)); - def = this->add("elefant_foot_compensation", coFloat); - def->label = L("Elephant foot compensation"); - def->category = L("Advanced"); - def->tooltip = L("The first layer will be shrunk in the XY plane by the configured value " - "to compensate for the 1st layer squish aka an Elephant Foot effect."); - def->sidetext = L("mm"); - def->min = 0; - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(0)); - def = this->add("end_gcode", coString); def->label = L("End G-code"); def->tooltip = L("This end procedure is inserted at the end of the output file. " @@ -2442,6 +2442,15 @@ void PrintConfigDef::init_sla_params() "to the sign of the correction."); def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0.0)); + + def = this->add("elefant_foot_min_width", coFloat); + def->label = L("Elefant foot minimum width"); + def->category = L("Advanced"); + def->tooltip = L("Minimum with of features to maintain when doing EFC"); + def->sidetext = L("mm"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(0.2)); def = this->add("gamma_correction", coFloat); def->label = L("Printer gamma correction"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index c854feafc..8c6710dad 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1175,6 +1175,8 @@ public: ConfigOptionBool display_mirror_y; ConfigOptionFloats relative_correction; ConfigOptionFloat absolute_correction; + ConfigOptionFloat elefant_foot_compensation; + ConfigOptionFloat elefant_foot_min_width; ConfigOptionFloat gamma_correction; ConfigOptionFloat fast_tilt_time; ConfigOptionFloat slow_tilt_time; @@ -1198,6 +1200,8 @@ protected: OPT_PTR(display_orientation); OPT_PTR(relative_correction); OPT_PTR(absolute_correction); + OPT_PTR(elefant_foot_compensation); + OPT_PTR(elefant_foot_min_width); OPT_PTR(gamma_correction); OPT_PTR(fast_tilt_time); OPT_PTR(slow_tilt_time); diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 06c4f687b..cca0abd5c 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -785,6 +785,8 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector &SLAPrintObject::get_support_slices() const const ExPolygons &SliceRecord::get_slice(SliceOrigin o) const { - size_t idx = o == soModel ? m_model_slices_idx : - m_support_slices_idx; + size_t idx = o == soModel ? m_model_slices_idx : m_support_slices_idx; if(m_po == nullptr) return EMPTY_SLICE; diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index c9f5198db..70f773f6b 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -152,6 +152,10 @@ public: } const ExPolygons& get_slice(SliceOrigin o) const; + size_t get_slice_idx(SliceOrigin o) const + { + return o == soModel ? m_model_slices_idx : m_support_slices_idx; + } }; private: diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp index c8550e2fe..01220a633 100644 --- a/src/libslic3r/SLAPrintSteps.cpp +++ b/src/libslic3r/SLAPrintSteps.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include // For geometry algorithms with native Clipper types (no copies and conversions) @@ -78,6 +80,40 @@ SLAPrint::Steps::Steps(SLAPrint *print) , objectstep_scale{(max_objstatus - min_objstatus) / (objcount * 100.0)} {} +void SLAPrint::Steps::apply_printer_corrections(SLAPrintObject &po, SliceOrigin o) +{ + if (o == soSupport && !po.m_supportdata) return; + + auto faded_lyrs = size_t(po.m_config.faded_layers.getInt()); + double min_w = m_print->m_printer_config.elefant_foot_min_width.getFloat() / 2.; + double start_efc = m_print->m_printer_config.elefant_foot_compensation.getFloat(); + + double doffs = m_print->m_printer_config.absolute_correction.getFloat(); + coord_t clpr_offs = scaled(doffs); + + faded_lyrs = std::min(po.m_slice_index.size(), faded_lyrs); + + auto efc = [start_efc, faded_lyrs](size_t pos) { + return (faded_lyrs - 1 - pos) * start_efc / (faded_lyrs - 1); + }; + + std::vector &slices = o == soModel ? + po.m_model_slices : + po.m_supportdata->support_slices; + + if (clpr_offs != 0) for (size_t i = 0; i < po.m_slice_index.size(); ++i) { + size_t idx = po.m_slice_index[i].get_slice_idx(o); + if (idx < slices.size()) + slices[idx] = offset_ex(slices[idx], float(clpr_offs)); + } + + if (start_efc > 0.) for (size_t i = 0; i < faded_lyrs; ++i) { + size_t idx = po.m_slice_index[i].get_slice_idx(o); + if (idx < slices.size()) + slices[idx] = elephant_foot_compensation(slices[idx], min_w, efc(i)); + } +} + void SLAPrint::Steps::hollow_model(SLAPrintObject &po) { po.m_hollowing_data.reset(); @@ -236,20 +272,15 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po) } auto mit = slindex_it; - double doffs = m_print->m_printer_config.absolute_correction.getFloat(); - coord_t clpr_offs = scaled(doffs); - for(size_t id = 0; + for (size_t id = 0; id < po.m_model_slices.size() && mit != po.m_slice_index.end(); - id++) - { - // We apply the printer correction offset here. - if(clpr_offs != 0) - po.m_model_slices[id] = - offset_ex(po.m_model_slices[id], float(clpr_offs)); - + id++) { mit->set_model_slice_idx(po, id); ++mit; } + // We apply the printer correction offset here. + apply_printer_corrections(po, soModel); + if(po.m_config.supports_enable.getBool() || po.m_config.pad_enable.getBool()) { po.m_supportdata.reset(new SLAPrintObject::SupportData(mesh)); @@ -446,21 +477,15 @@ void SLAPrint::Steps::slice_supports(SLAPrintObject &po) { auto heights = reserve_vector(po.m_slice_index.size()); for(auto& rec : po.m_slice_index) heights.emplace_back(rec.slice_level()); - + sd->support_slices = sd->support_tree_ptr->slice( - heights, float(po.config().slice_closing_radius.value)); + heights, float(po.config().slice_closing_radius.value)); } - double doffs = m_print->m_printer_config.absolute_correction.getFloat(); - coord_t clpr_offs = scaled(doffs); - - for (size_t i = 0; i < sd->support_slices.size() && i < po.m_slice_index.size(); ++i) { - // We apply the printer correction offset here. - if (clpr_offs != 0) - sd->support_slices[i] = offset_ex(sd->support_slices[i], float(clpr_offs)); - + for (size_t i = 0; i < sd->support_slices.size() && i < po.m_slice_index.size(); ++i) po.m_slice_index[i].set_support_slice_idx(po, i); - } + + apply_printer_corrections(po, soSupport); // Using RELOAD_SLA_PREVIEW to tell the Plater to pass the update // status to the 3D preview to load the SLA slices. diff --git a/src/libslic3r/SLAPrintSteps.hpp b/src/libslic3r/SLAPrintSteps.hpp index 0418072cf..d3341bc14 100644 --- a/src/libslic3r/SLAPrintSteps.hpp +++ b/src/libslic3r/SLAPrintSteps.hpp @@ -43,6 +43,8 @@ private: bool canceled() const { return m_print->canceled(); } void initialize_printer_input(); + void apply_printer_corrections(SLAPrintObject &po, SliceOrigin o); + public: Steps(SLAPrint *print); diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index b48d74aa1..f83afba9d 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -557,6 +557,8 @@ const std::vector& Preset::sla_printer_options() "fast_tilt_time", "slow_tilt_time", "area_fill", "relative_correction", "absolute_correction", + "elefant_foot_compensation", + "elefant_foot_min_width", "gamma_correction", "min_exposure_time", "max_exposure_time", "min_initial_exposure_time", "max_initial_exposure_time", diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 836402a94..e0cfe5be6 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2112,8 +2112,10 @@ void TabPrinter::build_sla() } optgroup->append_line(line); optgroup->append_single_option_line("absolute_correction"); + optgroup->append_single_option_line("elefant_foot_compensation"); + optgroup->append_single_option_line("elefant_foot_min_width"); optgroup->append_single_option_line("gamma_correction"); - + optgroup = page->new_optgroup(_(L("Exposure"))); optgroup->append_single_option_line("min_exposure_time"); optgroup->append_single_option_line("max_exposure_time"); diff --git a/tests/libslic3r/test_elephant_foot_compensation.cpp b/tests/libslic3r/test_elephant_foot_compensation.cpp index 98ec5df52..616c0c6ad 100644 --- a/tests/libslic3r/test_elephant_foot_compensation.cpp +++ b/tests/libslic3r/test_elephant_foot_compensation.cpp @@ -413,6 +413,19 @@ static ExPolygon contour_with_hole() return out; } +static bool is_valid_orientation(const ExPolygon &p) +{ + bool ret = p.contour.is_counter_clockwise(); + for (auto &h : p.holes) ret = ret && h.is_clockwise(); + return ret; +} + +static bool is_efc_result_smaller(const ExPolygon &efc, const ExPolygon &orig) +{ + double efc_area = efc.area(); + return efc_area > 0. && efc_area < orig.area() && is_valid_orientation(efc); +} + SCENARIO("Elephant foot compensation", "[ElephantFoot]") { GIVEN("Contour with hole") { @@ -426,7 +439,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") { { { expoly_compensated }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } } }); #endif /* TESTS_EXPORT_SVGS */ THEN("area of the compensated polygon is smaller") { - REQUIRE(expoly_compensated.area() < expoly.area()); + REQUIRE(is_efc_result_smaller(expoly_compensated, expoly)); } } } @@ -456,7 +469,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") { { { expoly_compensated }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } } }); #endif /* TESTS_EXPORT_SVGS */ THEN("area of the compensated polygon is smaller") { - REQUIRE(expoly_compensated.area() < expoly.area()); + REQUIRE(is_efc_result_smaller(expoly_compensated, expoly)); } } } @@ -471,7 +484,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") { { { expoly_compensated }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } } }); #endif /* TESTS_EXPORT_SVGS */ THEN("area of the compensated polygon is smaller") { - REQUIRE(expoly_compensated.area() < expoly.area()); + REQUIRE(is_efc_result_smaller(expoly_compensated, expoly)); } } } @@ -523,7 +536,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") { { { expoly_compensated }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } } }); #endif /* TESTS_EXPORT_SVGS */ THEN("area of the compensated polygon is smaller") { - REQUIRE(expoly_compensated.area() < expoly.area()); + REQUIRE(is_efc_result_smaller(expoly_compensated, expoly)); } } WHEN("Fully compensated") { @@ -534,7 +547,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") { { { expoly_compensated }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } } }); #endif /* TESTS_EXPORT_SVGS */ THEN("area of the compensated polygon is smaller") { - REQUIRE(expoly_compensated.area() < expoly.area()); + REQUIRE(is_efc_result_smaller(expoly_compensated, expoly)); } } } @@ -549,7 +562,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") { { { expoly_compensated }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } } }); #endif /* TESTS_EXPORT_SVGS */ THEN("area of the compensated polygon is smaller") { - REQUIRE(expoly_compensated.area() < expoly.area()); + REQUIRE(is_efc_result_smaller(expoly_compensated, expoly)); } } } @@ -566,7 +579,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") { { { expoly_compensated }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } } }); #endif /* TESTS_EXPORT_SVGS */ THEN("area of the compensated polygon is smaller") { - REQUIRE(expoly_compensated.area() < expoly.area()); + REQUIRE(is_efc_result_smaller(expoly_compensated, expoly)); } } WHEN("Fully compensated") { @@ -577,7 +590,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") { { { expoly_compensated }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } } }); #endif /* TESTS_EXPORT_SVGS */ THEN("area of the compensated polygon is smaller") { - REQUIRE(expoly_compensated.area() < expoly.area()); + REQUIRE(is_efc_result_smaller(expoly_compensated, expoly)); } } WHEN("Brutally compensated") { @@ -588,7 +601,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") { { { expoly_compensated }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } } }); #endif /* TESTS_EXPORT_SVGS */ THEN("area of the compensated polygon is smaller") { - REQUIRE(expoly_compensated.area() < expoly.area()); + REQUIRE(is_efc_result_smaller(expoly_compensated, expoly)); } } } @@ -603,7 +616,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") { { { expoly_compensated }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } } }); #endif /* TESTS_EXPORT_SVGS */ THEN("area of the compensated polygon is smaller") { - REQUIRE(expoly_compensated.area() < expoly.area()); + REQUIRE(is_efc_result_smaller(expoly_compensated, expoly)); } } }