From 6d1974a66262ecda7f265dc1d04aa69fde744afd Mon Sep 17 00:00:00 2001 From: Mqrius Date: Thu, 16 Jul 2026 14:10:15 +0200 Subject: [PATCH] Restore flow calibration special order, overridable via fill order (#14786) --- src/libslic3r/Fill/FillBase.cpp | 11 +++++++---- src/libslic3r/Fill/FillPlanePath.cpp | 29 +++++++++++++++++++++++++++- src/libslic3r/Preset.cpp | 1 + src/libslic3r/PrintConfig.cpp | 6 +++++- src/libslic3r/PrintConfig.hpp | 3 +++ src/slic3r/GUI/Plater.cpp | 9 +++++++-- 6 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 29eb6120ed..2606529099 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -162,11 +162,14 @@ void Fill::fill_surface_extrusion(const Surface* surface, const FillParams& para out.push_back(eec = new ExtrusionEntityCollection()); // Only concentric fills are not sorted. eec->no_sort = this->no_sort(); + // ORCA: special flag for flow rate calibration + auto is_flow_calib = params.extrusion_role == erTopSolidInfill && this->print_object_config->has("calib_flowrate_topinfill_special_order") && + this->print_object_config->option("calib_flowrate_topinfill_special_order")->getBool(); // Orca: a forced surface fill order must survive the G-code path planner, which would - // otherwise re-chain and possibly reverse the paths. This also covers the flow rate - // calibration, which forces an outward fill order on its top surfaces. + // otherwise re-chain and possibly reverse the paths. The same applies to the flow rate + // calibration's special toolpath order. const bool keep_fill_order = params.fill_order != SurfaceFillOrder::Default; - if (keep_fill_order) { + if (is_flow_calib || keep_fill_order) { eec->no_sort = true; } size_t idx = eec->entities.size(); @@ -181,7 +184,7 @@ void Fill::fill_surface_extrusion(const Surface* surface, const FillParams& para params.extrusion_role, flow_mm3_per_mm, float(flow_width), params.flow.height()); } - if (!params.can_reverse || keep_fill_order) { + if (!params.can_reverse || is_flow_calib || keep_fill_order) { for (size_t i = idx; i < eec->entities.size(); i++) eec->entities[i]->set_reverse(); } diff --git a/src/libslic3r/Fill/FillPlanePath.cpp b/src/libslic3r/Fill/FillPlanePath.cpp index edfbaef7d6..7ce8e4abb3 100644 --- a/src/libslic3r/Fill/FillPlanePath.cpp +++ b/src/libslic3r/Fill/FillPlanePath.cpp @@ -134,7 +134,34 @@ void FillPlanePath::_fill_surface_single( if (!polylines.empty()) { Polylines chained; if (params.dont_connect() || params.density > 0.5) { - if (params.fill_order != SurfaceFillOrder::Default) { + // ORCA: special flag for flow rate calibration. The chords chained ahead of the + // inside-out center spiral collide with it in opposing directions, raising a + // tactile lip that the calibration reads. Only applies while the fill order is + // Default, so it can be overridden from the calibration objects. + auto is_flow_calib = params.fill_order == SurfaceFillOrder::Default && + params.extrusion_role == erTopSolidInfill && + this->print_object_config->has("calib_flowrate_topinfill_special_order") && + this->print_object_config->option("calib_flowrate_topinfill_special_order")->getBool() && + dynamic_cast(this); + if (is_flow_calib) { + // We want the spiral part to be printed inside-out + // Find the center spiral line first, by looking for the longest one + auto it = std::max_element(polylines.begin(), polylines.end(), + [](const Polyline& a, const Polyline& b) { return a.length() < b.length(); }); + Polyline center_spiral = std::move(*it); + + // Ensure the spiral is printed from inside to out + if (center_spiral.first_point().squaredNorm() > center_spiral.last_point().squaredNorm()) { + center_spiral.reverse(); + } + + // Chain the other polylines + polylines.erase(it); + chained = chain_polylines(std::move(polylines), nullptr); + + // Then add the center spiral back + chained.push_back(std::move(center_spiral)); + } else if (params.fill_order != SurfaceFillOrder::Default) { // Orca: print the fragments in the order they appear along the generated // path, which runs from the center outwards. The Euclidean distance from // the center cannot be used for this: along the Octagram Spiral the radius diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index e3f8f53b31..16ae49bdc1 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1310,6 +1310,7 @@ static std::vector s_Preset_print_options{ "interlocking_depth", "interlocking_boundary_avoidance", "interlocking_beam_width", + "calib_flowrate_topinfill_special_order", // Z Anti-Aliasing (ZAA) "zaa_enabled", "zaa_minimize_perimeter_height", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index e92562e132..7a71c444f9 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -4647,6 +4647,11 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionInt(2)); + // ORCA: special flag for flow rate calibration + def = this->add("calib_flowrate_topinfill_special_order", coBool); + def->mode = comDevelop; + def->set_default_value(new ConfigOptionBool(false)); + def = this->add("ironing_type", coEnum); def->label = L("Ironing type"); def->category = L("Quality"); @@ -9016,7 +9021,6 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va "internal_bridge_support_thickness", "top_area_threshold", "reduce_wall_solid_infill","filament_load_time","filament_unload_time", "smooth_coefficient", "overhang_totally_speed", "silent_mode", "overhang_speed_classic", "filament_prime_volume", - "calib_flowrate_topinfill_special_order", "anisotropic_surfaces", // superseded by top_surface_fill_order / bottom_surface_fill_order }; diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index f9aab25f2f..7b611dec9f 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1221,6 +1221,9 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionInt, interlocking_beam_layer_count)) ((ConfigOptionInt, interlocking_depth)) ((ConfigOptionInt, interlocking_boundary_avoidance)) + + // Orca: internal use only + ((ConfigOptionBool, calib_flowrate_topinfill_special_order)) // ORCA: special flag for flow rate calibration ) // This object is mapped to Perl as Slic3r::Config::PrintRegion. diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index ffa4bbc5b3..0a1164c3a1 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -13929,8 +13929,13 @@ void adjust_settings_for_flowrate_calib(ModelObjectPtrs& objects, bool linear, i _obj->config.set_key_value("seam_slope_type", new ConfigOptionEnum(SeamScarfType::None)); _obj->config.set_key_value("gap_fill_target", new ConfigOptionEnum(GapFillTarget::gftNowhere)); print_config->set_key_value("max_volumetric_extrusion_rate_slope", new ConfigOptionFloat(0)); - // ORCA: print the top surface spiral from the center outwards, so the tiles are comparable. - _obj->config.set_key_value("top_surface_fill_order", new ConfigOptionEnum(SurfaceFillOrder::Outward)); + // ORCA: request the calibration's special toolpath order (chords first, center spiral + // last and inside-out) so opposing directions collide into the tactile lip the test + // reads. The special order only applies while the fill order is Default, so reset the + // profile's fill order on the calibration objects; changing the setting on the object + // afterwards deliberately overrides the special order. + _obj->config.set_key_value("calib_flowrate_topinfill_special_order", new ConfigOptionBool(true)); + _obj->config.set_key_value("top_surface_fill_order", new ConfigOptionEnum(SurfaceFillOrder::Default)); // extract flowrate from name, filename format: flowrate_xxx std::string obj_name = _obj->name;