Feature: Fuzzy Skin Extrusion Mode (#9878)

* Feature: Fuzzy Skin Extrusion Mode

This extension allows you to add new features to the fuzzy skin generator.

* Add auto switch to Arachne mode

* Move dialog to `update_print_fff_config` and update how `is_msg_dlg_already_exist` is used

---------

Co-authored-by: Noisyfox <timemanager.rick@gmail.com>
This commit is contained in:
π²
2025-07-25 10:36:18 +03:00
committed by GitHub
parent 43a84842e8
commit 3d16c7f4c8
8 changed files with 81 additions and 7 deletions

View File

@@ -116,6 +116,7 @@ void fuzzy_extrusion_line(Arachne::ExtrusionJunctions& ext_lines, coordf_t slice
const double min_dist_between_points = cfg.point_distance * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value
const double range_random_point_dist = cfg.point_distance / 2.;
const double min_extrusion_width = 0.01; // workaround for many print options. Need overwrite formula with the layer height parameter. The width must more than >>> layer_height * (1 - 0.25 * PI) * 1.05 <<< (last num is the coeff of overlay error case)
double dist_left_over = random_value() * (min_dist_between_points / 2.); // the distance to be traversed on the line before making the first new point
auto* p0 = &ext_lines.front();
@@ -134,7 +135,18 @@ void fuzzy_extrusion_line(Arachne::ExtrusionJunctions& ext_lines, coordf_t slice
for (; p0pa_dist < p0p1_size; p0pa_dist += min_dist_between_points + random_value() * range_random_point_dist) {
Point pa = p0->p + (p0p1 * (p0pa_dist / p0p1_size)).cast<coord_t>();
double r = noise->GetValue(unscale_(pa.x()), unscale_(pa.y()), slice_z) * cfg.thickness;
out.emplace_back(pa + (perp(p0p1).cast<double>().normalized() * r).cast<coord_t>(), p1.w, p1.perimeter_index);
switch (cfg.mode) { //the curly code for testing
case FuzzySkinMode::Displacement :
out.emplace_back(pa + (perp(p0p1).cast<double>().normalized() * r).cast<coord_t>(), p1.w, p1.perimeter_index);
break;
case FuzzySkinMode::Extrusion :
out.emplace_back(pa, std::max(p1.w + r + min_extrusion_width, min_extrusion_width), p1.perimeter_index);
break;
case FuzzySkinMode::Combined :
double rad = std::max(p1.w + r + min_extrusion_width, min_extrusion_width);
out.emplace_back(pa + (perp(p0p1).cast<double>().normalized() * ((rad - p1.w) / 2)).cast<coord_t>(), rad, p1.perimeter_index); //0.05 - minimum width of extruded line
break;
}
}
dist_left_over = p0pa_dist - p0p1_size;
p0 = &p1;
@@ -148,8 +160,10 @@ void fuzzy_extrusion_line(Arachne::ExtrusionJunctions& ext_lines, coordf_t slice
--point_idx;
}
if (ext_lines.back().p == ext_lines.front().p) // Connect endpoints.
if (ext_lines.back().p == ext_lines.front().p) { // Connect endpoints.
out.front().p = out.back().p;
out.front().w = out.back().w;
}
if (out.size() >= 3)
ext_lines = std::move(out);
@@ -171,7 +185,8 @@ void group_region_by_fuzzify(PerimeterGenerator& g)
region_config.fuzzy_skin_noise_type,
region_config.fuzzy_skin_scale,
region_config.fuzzy_skin_octaves,
region_config.fuzzy_skin_persistence};
region_config.fuzzy_skin_persistence,
region_config.fuzzy_skin_mode};
auto& surfaces = regions[cfg];
for (const auto& surface : region->slices.surfaces) {
surfaces.push_back(&surface);

View File

@@ -20,6 +20,7 @@ struct FuzzySkinConfig
double noise_scale;
int noise_octaves;
double noise_persistence;
FuzzySkinMode mode;
bool operator==(const FuzzySkinConfig& r) const
{
@@ -30,7 +31,8 @@ struct FuzzySkinConfig
&& noise_type == r.noise_type
&& noise_scale == r.noise_scale
&& noise_octaves == r.noise_octaves
&& noise_persistence == r.noise_persistence;
&& noise_persistence == r.noise_persistence
&& mode == r.mode;
}
bool operator!=(const FuzzySkinConfig& r) const { return !(*this == r); }

View File

@@ -791,7 +791,7 @@ static std::vector<std::string> s_Preset_print_options {
"ironing_type", "ironing_pattern", "ironing_flow", "ironing_speed", "ironing_spacing", "ironing_angle", "ironing_inset",
"support_ironing", "support_ironing_pattern", "support_ironing_flow", "support_ironing_spacing",
"max_travel_detour_distance",
"fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", "fuzzy_skin_noise_type", "fuzzy_skin_scale", "fuzzy_skin_octaves", "fuzzy_skin_persistence",
"fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", "fuzzy_skin_noise_type", "fuzzy_skin_mode", "fuzzy_skin_scale", "fuzzy_skin_octaves", "fuzzy_skin_persistence",
"max_volumetric_extrusion_rate_slope", "max_volumetric_extrusion_rate_slope_segment_length","extrusion_rate_smoothing_external_perimeter_only",
"inner_wall_speed", "outer_wall_speed", "sparse_infill_speed", "internal_solid_infill_speed",
"top_surface_speed", "support_speed", "support_object_xy_distance", "support_object_first_layer_gap", "support_interface_speed",

View File

@@ -118,7 +118,6 @@ static t_config_enum_values s_keys_map_GCodeFlavor {
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(GCodeFlavor)
static t_config_enum_values s_keys_map_FuzzySkinType {
{ "none", int(FuzzySkinType::None) },
{ "external", int(FuzzySkinType::External) },
@@ -136,6 +135,13 @@ static t_config_enum_values s_keys_map_NoiseType {
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(NoiseType)
static t_config_enum_values s_keys_map_FuzzySkinMode {
{ "displacement", int(FuzzySkinMode::Displacement) },
{ "extrusion", int(FuzzySkinMode::Extrusion) },
{ "combined", int(FuzzySkinMode::Combined)}
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(FuzzySkinMode)
static t_config_enum_values s_keys_map_InfillPattern {
{ "monotonic", ipMonotonic },
{ "monotonicline", ipMonotonicLine },
@@ -2826,6 +2832,29 @@ void PrintConfigDef::init_fff_params()
def->mode = comSimple;
def->set_default_value(new ConfigOptionBool(0));
def = this->add("fuzzy_skin_mode", coEnum);
def->label = L("Fuzzy skin generator mode");
def->category = L("Others");
def->tooltip = L("Fuzzy skin generation mode. Works only with Arachne!\n"
"Displacement: Сlassic mode when the pattern is formed by shifting the nozzle sideways from the original path.\n"
"Extrusion: The mode when the pattern formed by the amount of extruded plastic. "
"This is the fast and straight algorithm without unnecessary nozzle shake that gives a smooth pattern. "
"But it is more useful for forming loose walls in the entire they array.\n"
"Combined: Joint mode [Displacement] + [Extrusion]. The appearance of the walls is similar to [Displacement] Mode, but it leaves no pores between the perimeters.\n\n"
"Attention! The [Extrusion] and [Combined] modes works only the fuzzy_skin_thickness parameter not more than the thickness of printed loop."
"At the same time, the width of the extrusion for a particular layer should also not be below a certain level. "
"It is usually equal 15-25%% of a layer height. Therefore, the maximum fuzzy skin thickness with a perimeter width of 0.4 mm and a layer height of 0.2 mm will be 0.4-(0.2*0.25)=±0.35mm! "
"If you enter a higher parameter than this, the error Flow::spacing() will displayed, and the model will not be sliced. You can choose this number until this error is repeated." );
def->enum_keys_map = &ConfigOptionEnum<FuzzySkinMode>::get_enum_values();
def->enum_values.push_back("displacement");
def->enum_values.push_back("extrusion");
def->enum_values.push_back("combined");
def->enum_labels.push_back(L("Displacement"));
def->enum_labels.push_back(L("Extrusion"));
def->enum_labels.push_back(L("Combined"));
def->mode = comSimple;
def->set_default_value(new ConfigOptionEnum<FuzzySkinMode>(FuzzySkinMode::Displacement));
def = this->add("fuzzy_skin_noise_type", coEnum);
def->label = L("Fuzzy skin noise type");
def->category = L("Others");

View File

@@ -34,6 +34,7 @@ enum GCodeFlavor : unsigned char {
gcfSmoothie, gcfNoExtrusion
};
enum class FuzzySkinType {
None,
External,
@@ -41,6 +42,12 @@ enum class FuzzySkinType {
AllWalls,
};
enum class FuzzySkinMode {
Displacement,
Extrusion,
Combined,
};
enum class NoiseType {
Classic,
Perlin,
@@ -440,6 +447,7 @@ static std::string get_bed_temp_1st_layer_key(const BedType type)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PrinterTechnology)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(GCodeFlavor)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(FuzzySkinType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(FuzzySkinMode)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(NoiseType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(InfillPattern)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(IroningType)
@@ -980,6 +988,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, fuzzy_skin_point_distance))
((ConfigOptionBool, fuzzy_skin_first_layer))
((ConfigOptionEnum<NoiseType>, fuzzy_skin_noise_type))
((ConfigOptionEnum<FuzzySkinMode>, fuzzy_skin_mode))
((ConfigOptionFloat, fuzzy_skin_scale))
((ConfigOptionInt, fuzzy_skin_octaves))
((ConfigOptionFloat, fuzzy_skin_persistence))

View File

@@ -1133,6 +1133,7 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "fuzzy_skin_thickness"
|| opt_key == "fuzzy_skin_point_distance"
|| opt_key == "fuzzy_skin_first_layer"
|| opt_key == "fuzzy_skin_mode"
|| opt_key == "fuzzy_skin_noise_type"
|| opt_key == "fuzzy_skin_scale"
|| opt_key == "fuzzy_skin_octaves"

View File

@@ -486,7 +486,24 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
apply(config, &new_conf);
is_msg_dlg_already_exist = false;
}
bool have_arachne = config->opt_enum<PerimeterGeneratorType>("wall_generator") == PerimeterGeneratorType::Arachne;
if (config->opt_enum<FuzzySkinMode>("fuzzy_skin_mode") != FuzzySkinMode::Displacement && !have_arachne) {
wxString msg_text = _(L("Both [Extrusion] and [Combined] modes of Fuzzy Skin require the Arachne Wall Generator to be enabled."));
msg_text += "\n\n" + _(L("Change these settings automatically?\n"
"Yes - Enable Arachne Wall Generator\n"
"No - Disable Arachne Wall Generator and set [Displacement] mode of the Fuzzy Skin"));
MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxYES | wxNO);
DynamicPrintConfig new_conf = *config;
is_msg_dlg_already_exist = true;
auto answer = dialog.ShowModal();
if (answer == wxID_YES)
new_conf.set_key_value("wall_generator", new ConfigOptionEnum<PerimeterGeneratorType>(PerimeterGeneratorType::Arachne));
else
new_conf.set_key_value("fuzzy_skin_mode", new ConfigOptionEnum<FuzzySkinMode>(FuzzySkinMode::Displacement));
apply(config, &new_conf);
is_msg_dlg_already_exist = false;
}
}
void ConfigManipulation::apply_null_fff_config(DynamicPrintConfig *config, std::vector<std::string> const &keys, std::map<ObjectBase *, ModelConfig *> const &configs)

View File

@@ -2454,6 +2454,7 @@ optgroup->append_single_option_line("skirt_loops", "others_settings_skirt#loops"
optgroup = page->new_optgroup(L("Fuzzy Skin"), L"fuzzy_skin");
optgroup->append_single_option_line("fuzzy_skin", "others_settings_special_mode#fuzzy-skin");
optgroup->append_single_option_line("fuzzy_skin_mode");
optgroup->append_single_option_line("fuzzy_skin_noise_type", "others_settings_special_mode#fuzzy-skin-mode");
optgroup->append_single_option_line("fuzzy_skin_point_distance", "others_settings_special_mode#point-distance");
optgroup->append_single_option_line("fuzzy_skin_thickness", "others_settings_special_mode#skin-thickness");