WIP: Initial Fuzzy Skin implementaiton #2010
Based on pull request Experimental fuzzy skin mode #4611 by @etet100 and on CuraEngine implementation of perimeter fuzzyfication void FffPolygonGenerator::processFuzzyWalls(SliceMeshStorage& mesh)
This commit is contained in:
parent
d9448c9f2a
commit
4620402ab4
@ -5,6 +5,7 @@
|
||||
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -230,8 +231,128 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
|
||||
return out;
|
||||
}
|
||||
|
||||
enum class FuzzyShape {
|
||||
Triangle,
|
||||
Sawtooth,
|
||||
Random
|
||||
};
|
||||
|
||||
static void fuzzy_polygon(Polygon &poly, FuzzyShape shape, double fuzzy_skin_thickness, double fuzzy_skin_point_dist)
|
||||
{
|
||||
#if 0
|
||||
Point last = poly.points.at(poly.points.size() - 1);
|
||||
Point last_processed = last;
|
||||
|
||||
double max_length = scale_(2);
|
||||
double min_length = scale_(1);
|
||||
|
||||
if (poly.length() < scale_(5))
|
||||
return;
|
||||
|
||||
deepness *= 3;
|
||||
|
||||
bool triangle_or_sawtooth = shape == FuzzyShape::Sawtooth;
|
||||
double length_sum = 0;
|
||||
Points::iterator it = poly.points.begin();
|
||||
while (it != poly.points.end()) {
|
||||
Point &pt = *it;
|
||||
|
||||
Line line(last, pt);
|
||||
double length = line.length();
|
||||
|
||||
// split long line
|
||||
if (length > max_length) {
|
||||
auto parts = int(ceil(length / max_length));
|
||||
if (parts == 2) {
|
||||
Point point_to_insert(line.midpoint());
|
||||
it = poly.points.insert(it, point_to_insert);
|
||||
}
|
||||
else {
|
||||
Vector part_vector = line.vector() / parts;
|
||||
|
||||
Points points_to_insert;
|
||||
Point point_to_insert(last);
|
||||
while (--parts) {
|
||||
point_to_insert += part_vector;
|
||||
Point point_to_insert_2(point_to_insert);
|
||||
points_to_insert.push_back(point_to_insert_2);
|
||||
}
|
||||
|
||||
it = poly.points.insert(it, points_to_insert.begin(), points_to_insert.end());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
length_sum += length;
|
||||
|
||||
// join short lines
|
||||
if (length_sum < min_length) {
|
||||
last = pt;
|
||||
it = poly.points.erase(it);
|
||||
continue;
|
||||
}
|
||||
|
||||
line = Line(last_processed, pt);
|
||||
last = pt;
|
||||
last_processed = pt;
|
||||
|
||||
if (shape == FuzzyShape::Random) {
|
||||
triangle_or_sawtooth = !(rand() % 2);
|
||||
}
|
||||
|
||||
Point point_to_insert(triangle_or_sawtooth ? pt : line.midpoint());
|
||||
|
||||
int scale = (rand() % deepness) + 1;
|
||||
|
||||
Vec2d normal = line.normal().cast<double>();
|
||||
normal /= line.length() / scale_(1.) / ((double)scale / 20.);
|
||||
|
||||
it = poly.points.insert(it, point_to_insert + normal.cast<coord_t>()) + 2;
|
||||
|
||||
length_sum = 0;
|
||||
}
|
||||
|
||||
#else
|
||||
const double min_dist_between_points = fuzzy_skin_point_dist * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value
|
||||
const double range_random_point_dist = fuzzy_skin_point_dist / 2.;
|
||||
double dist_left_over = double(rand()) * (min_dist_between_points / 2) / double(RAND_MAX); // the distance to be traversed on the line before making the first new point
|
||||
Point* p0 = &poly.points.back();
|
||||
Points out;
|
||||
out.reserve(poly.points.size());
|
||||
for (Point &p1 : poly.points)
|
||||
{ // 'a' is the (next) new point between p0 and p1
|
||||
Vec2d p0p1 = (p1 - *p0).cast<double>();
|
||||
double p0p1_size = p0p1.norm();
|
||||
// so that p0p1_size - dist_last_point evaulates to dist_left_over - p0p1_size
|
||||
double dist_last_point = dist_left_over + p0p1_size * 2.;
|
||||
for (double p0pa_dist = dist_left_over; p0pa_dist < p0p1_size;
|
||||
p0pa_dist += min_dist_between_points + double(rand()) * range_random_point_dist / double(RAND_MAX))
|
||||
{
|
||||
double r = double(rand()) * (fuzzy_skin_thickness * 2.) / double(RAND_MAX) - fuzzy_skin_thickness;
|
||||
out.emplace_back(*p0 + (p0p1 * (p0pa_dist / p0p1_size) + perp(p0p1).cast<double>().normalized() * r).cast<coord_t>());
|
||||
dist_last_point = p0pa_dist;
|
||||
}
|
||||
dist_left_over = p0p1_size - dist_last_point;
|
||||
p0 = &p1;
|
||||
}
|
||||
while (out.size() < 3) {
|
||||
size_t point_idx = poly.size() - 2;
|
||||
out.emplace_back(poly[point_idx]);
|
||||
if (point_idx == 0)
|
||||
break;
|
||||
-- point_idx;
|
||||
}
|
||||
if (out.size() >= 3)
|
||||
poly.points = std::move(out);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PerimeterGenerator::process()
|
||||
{
|
||||
// nasty hack! initialize random generator
|
||||
auto time_us = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now()).time_since_epoch()).count();
|
||||
srand(this->layer_id * time_us);
|
||||
|
||||
// other perimeters
|
||||
m_mm3_per_mm = this->perimeter_flow.mm3_per_mm();
|
||||
coord_t perimeter_width = this->perimeter_flow.scaled_width();
|
||||
@ -272,6 +393,32 @@ void PerimeterGenerator::process()
|
||||
m_lower_slices_polygons = offset(*this->lower_slices, float(scale_(+nozzle_diameter/2)));
|
||||
}
|
||||
|
||||
// fuzzy skin configuration
|
||||
double fuzzy_skin_thickness;
|
||||
double fuzzy_skin_point_dist;
|
||||
FuzzyShape fuzzy_skin_shape;
|
||||
if (this->object_config->fuzzy_skin_perimeter_mode != FuzzySkinPerimeterMode::None) {
|
||||
switch (this->object_config->fuzzy_skin_shape) {
|
||||
case FuzzySkinShape::Triangle1:
|
||||
case FuzzySkinShape::Triangle2:
|
||||
case FuzzySkinShape::Triangle3:
|
||||
fuzzy_skin_shape = FuzzyShape::Triangle;
|
||||
break;
|
||||
case FuzzySkinShape::Sawtooth1:
|
||||
case FuzzySkinShape::Sawtooth2:
|
||||
case FuzzySkinShape::Sawtooth3:
|
||||
fuzzy_skin_shape = FuzzyShape::Sawtooth;
|
||||
break;
|
||||
case FuzzySkinShape::Random1:
|
||||
case FuzzySkinShape::Random2:
|
||||
case FuzzySkinShape::Random3:
|
||||
fuzzy_skin_shape = FuzzyShape::Random;
|
||||
break;
|
||||
}
|
||||
fuzzy_skin_thickness = scale_(this->object_config->fuzzy_skin_thickness);
|
||||
fuzzy_skin_point_dist = scale_(this->object_config->fuzzy_skin_point_dist);
|
||||
}
|
||||
|
||||
// we need to process each island separately because we might have different
|
||||
// extra perimeters for each one
|
||||
for (const Surface &surface : this->slices->surfaces) {
|
||||
@ -352,13 +499,35 @@ void PerimeterGenerator::process()
|
||||
// If i > loop_number, we were looking just for gaps.
|
||||
break;
|
||||
}
|
||||
for (const ExPolygon &expolygon : offsets) {
|
||||
for (ExPolygon &expolygon : offsets) {
|
||||
// Outer contour may overlap with an inner contour,
|
||||
// inner contour may overlap with another inner contour,
|
||||
// outer contour may overlap with itself.
|
||||
//FIXME evaluate the overlaps, annotate each point with an overlap depth,
|
||||
|
||||
bool skip_polygon = false;
|
||||
|
||||
if (this->object_config->fuzzy_skin_perimeter_mode != FuzzySkinPerimeterMode::None) {
|
||||
if (i == 0 && (this->object_config->fuzzy_skin_perimeter_mode != FuzzySkinPerimeterMode::ExternalSkipFirst || this->layer_id > 0)) {
|
||||
if (
|
||||
this->object_config->fuzzy_skin_perimeter_mode == FuzzySkinPerimeterMode::External ||
|
||||
this->object_config->fuzzy_skin_perimeter_mode == FuzzySkinPerimeterMode::ExternalSkipFirst
|
||||
) {
|
||||
ExPolygon expolygon_fuzzy(expolygon);
|
||||
fuzzy_polygon(expolygon_fuzzy.contour, fuzzy_skin_shape, fuzzy_skin_thickness, fuzzy_skin_point_dist);
|
||||
// compensate for the depth of intersection.
|
||||
contours[i].emplace_back(PerimeterGeneratorLoop(expolygon_fuzzy.contour, i, true));
|
||||
skip_polygon = true;
|
||||
} else
|
||||
fuzzy_polygon(expolygon.contour, fuzzy_skin_shape, fuzzy_skin_thickness, fuzzy_skin_point_dist);
|
||||
}
|
||||
}
|
||||
|
||||
if (!skip_polygon) {
|
||||
// compensate for the depth of intersection.
|
||||
contours[i].emplace_back(PerimeterGeneratorLoop(expolygon.contour, i, true));
|
||||
}
|
||||
|
||||
if (! expolygon.holes.empty()) {
|
||||
holes[i].reserve(holes[i].size() + expolygon.holes.size());
|
||||
for (const Polygon &hole : expolygon.holes)
|
||||
|
@ -411,6 +411,7 @@ const std::vector<std::string>& Preset::print_options()
|
||||
"solid_infill_below_area", "only_retract_when_crossing_perimeters", "infill_first",
|
||||
"ironing", "ironing_type", "ironing_flowrate", "ironing_speed", "ironing_spacing",
|
||||
"max_print_speed", "max_volumetric_speed", "avoid_crossing_perimeters_max_detour",
|
||||
"fuzzy_skin_perimeter_mode", "fuzzy_skin_shape", "fuzzy_skin_thickness", "fuzzy_skin_point_dist",
|
||||
#ifdef HAS_PRESSURE_EQUALIZER
|
||||
"max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative",
|
||||
#endif /* HAS_PRESSURE_EQUALIZER */
|
||||
|
@ -1007,6 +1007,68 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionInts { 0 });
|
||||
|
||||
def = this->add("fuzzy_skin_perimeter_mode", coEnum);
|
||||
def->label = L("Fuzzy skin perimeter mode");
|
||||
def->category = L("Fuzzy Skin");
|
||||
def->tooltip = L("Fuzzy skin perimeter mode.");
|
||||
|
||||
def->enum_keys_map = &ConfigOptionEnum<FuzzySkinPerimeterMode>::get_enum_values();
|
||||
def->enum_values.push_back("none");
|
||||
def->enum_values.push_back("external_only");
|
||||
def->enum_values.push_back("external_only_skip_first_layer");
|
||||
def->enum_values.push_back("all");
|
||||
def->enum_labels.push_back(L("None"));
|
||||
def->enum_labels.push_back(L("External"));
|
||||
def->enum_labels.push_back(L("External (skip first layer)"));
|
||||
def->enum_labels.push_back(L("All perimeters"));
|
||||
def->mode = comSimple;
|
||||
def->set_default_value(new ConfigOptionEnum<FuzzySkinPerimeterMode>(FuzzySkinPerimeterMode::None));
|
||||
|
||||
def = this->add("fuzzy_skin_shape", coEnum);
|
||||
def->label = L("Fuzzy skin shape");
|
||||
def->category = L("Fuzzy Skin");
|
||||
def->tooltip = L("Fuzzy skin shape.");
|
||||
|
||||
def->enum_keys_map = &ConfigOptionEnum<FuzzySkinShape>::get_enum_values();
|
||||
def->enum_values.push_back("triangle1");
|
||||
def->enum_values.push_back("triangle2");
|
||||
def->enum_values.push_back("triangle3");
|
||||
def->enum_values.push_back("sawtooth1");
|
||||
def->enum_values.push_back("sawtooth2");
|
||||
def->enum_values.push_back("sawtooth3");
|
||||
def->enum_values.push_back("random1");
|
||||
def->enum_values.push_back("random2");
|
||||
def->enum_values.push_back("random3");
|
||||
def->enum_labels.push_back(L("Triangle (1)"));
|
||||
def->enum_labels.push_back(L("Triangle (2)"));
|
||||
def->enum_labels.push_back(L("Triangle (3)"));
|
||||
def->enum_labels.push_back(L("Sawtooth (1)"));
|
||||
def->enum_labels.push_back(L("Sawtooth (2)"));
|
||||
def->enum_labels.push_back(L("Sawtooth (3)"));
|
||||
def->enum_labels.push_back(L("Random (1)"));
|
||||
def->enum_labels.push_back(L("Random (2)"));
|
||||
def->enum_labels.push_back(L("Random (3)"));
|
||||
def->mode = comSimple;
|
||||
def->set_default_value(new ConfigOptionEnum<FuzzySkinShape>(FuzzySkinShape::Triangle1));
|
||||
|
||||
def = this->add("fuzzy_skin_thickness", coFloat);
|
||||
def->label = L("Fuzzy skin thickness");
|
||||
def->category = L("Fuzzy Skin");
|
||||
def->tooltip = L("");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0.3));
|
||||
|
||||
def = this->add("fuzzy_skin_point_dist", coFloat);
|
||||
def->label = L("Fuzzy skin point distance");
|
||||
def->category = L("Fuzzy Skin");
|
||||
def->tooltip = L("");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0.8));
|
||||
|
||||
def = this->add("gap_fill_speed", coFloat);
|
||||
def->label = L("Gap fill");
|
||||
def->category = L("Speed");
|
||||
|
@ -43,6 +43,25 @@ enum AuthorizationType {
|
||||
atKeyPassword, atUserPassword
|
||||
};
|
||||
|
||||
enum class FuzzySkinPerimeterMode {
|
||||
None,
|
||||
External,
|
||||
ExternalSkipFirst,
|
||||
All
|
||||
};
|
||||
|
||||
enum class FuzzySkinShape {
|
||||
Triangle1,
|
||||
Triangle2,
|
||||
Triangle3,
|
||||
Sawtooth1,
|
||||
Sawtooth2,
|
||||
Sawtooth3,
|
||||
Random1,
|
||||
Random2,
|
||||
Random3
|
||||
};
|
||||
|
||||
enum InfillPattern : int {
|
||||
ipRectilinear, ipMonotonic, ipAlignedRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
|
||||
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipAdaptiveCubic, ipSupportCubic, ipCount,
|
||||
@ -140,6 +159,33 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<AuthorizationType
|
||||
return keys_map;
|
||||
}
|
||||
|
||||
template<> inline const t_config_enum_values& ConfigOptionEnum<FuzzySkinPerimeterMode>::get_enum_values() {
|
||||
static t_config_enum_values keys_map;
|
||||
if (keys_map.empty()) {
|
||||
keys_map["none"] = int(FuzzySkinPerimeterMode::None);
|
||||
keys_map["external_only"] = int(FuzzySkinPerimeterMode::External);
|
||||
keys_map["external_only_skip_first_layer"] = int(FuzzySkinPerimeterMode::ExternalSkipFirst);
|
||||
keys_map["all"] = int(FuzzySkinPerimeterMode::All);
|
||||
}
|
||||
return keys_map;
|
||||
}
|
||||
|
||||
template<> inline const t_config_enum_values& ConfigOptionEnum<FuzzySkinShape>::get_enum_values() {
|
||||
static t_config_enum_values keys_map;
|
||||
if (keys_map.empty()) {
|
||||
keys_map["triangle1"] = int(FuzzySkinShape::Triangle1);
|
||||
keys_map["triangle2"] = int(FuzzySkinShape::Triangle2);
|
||||
keys_map["triangle3"] = int(FuzzySkinShape::Triangle3);
|
||||
keys_map["sawtooth1"] = int(FuzzySkinShape::Sawtooth1);
|
||||
keys_map["sawtooth2"] = int(FuzzySkinShape::Sawtooth2);
|
||||
keys_map["sawtooth3"] = int(FuzzySkinShape::Sawtooth3);
|
||||
keys_map["random1"] = int(FuzzySkinShape::Random1);
|
||||
keys_map["random2"] = int(FuzzySkinShape::Random2);
|
||||
keys_map["random3"] = int(FuzzySkinShape::Random3);
|
||||
}
|
||||
return keys_map;
|
||||
}
|
||||
|
||||
template<> inline const t_config_enum_values& ConfigOptionEnum<InfillPattern>::get_enum_values() {
|
||||
static t_config_enum_values keys_map;
|
||||
if (keys_map.empty()) {
|
||||
@ -432,6 +478,10 @@ public:
|
||||
ConfigOptionFloat elefant_foot_compensation;
|
||||
ConfigOptionFloatOrPercent extrusion_width;
|
||||
ConfigOptionFloatOrPercent first_layer_height;
|
||||
ConfigOptionEnum<FuzzySkinPerimeterMode> fuzzy_skin_perimeter_mode;
|
||||
ConfigOptionEnum<FuzzySkinShape> fuzzy_skin_shape;
|
||||
ConfigOptionFloat fuzzy_skin_thickness;
|
||||
ConfigOptionFloat fuzzy_skin_point_dist;
|
||||
ConfigOptionBool infill_only_where_needed;
|
||||
// Force the generation of solid shells between adjacent materials/volumes.
|
||||
ConfigOptionBool interface_shells;
|
||||
@ -477,6 +527,10 @@ protected:
|
||||
OPT_PTR(elefant_foot_compensation);
|
||||
OPT_PTR(extrusion_width);
|
||||
OPT_PTR(first_layer_height);
|
||||
OPT_PTR(fuzzy_skin_perimeter_mode);
|
||||
OPT_PTR(fuzzy_skin_shape);
|
||||
OPT_PTR(fuzzy_skin_thickness);
|
||||
OPT_PTR(fuzzy_skin_point_dist);
|
||||
OPT_PTR(infill_only_where_needed);
|
||||
OPT_PTR(interface_shells);
|
||||
OPT_PTR(layer_height);
|
||||
|
@ -521,6 +521,10 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
|
||||
|| opt_key == "gap_fill_speed"
|
||||
|| opt_key == "overhangs"
|
||||
|| opt_key == "first_layer_extrusion_width"
|
||||
|| opt_key == "fuzzy_skin_perimeter_mode"
|
||||
|| opt_key == "fuzzy_skin_shape"
|
||||
|| opt_key == "fuzzy_skin_thickness"
|
||||
|| opt_key == "fuzzy_skin_point_dist"
|
||||
|| opt_key == "perimeter_extrusion_width"
|
||||
|| opt_key == "infill_overlap"
|
||||
|| opt_key == "thin_walls"
|
||||
|
@ -1200,6 +1200,10 @@ boost::any& Choice::get_value()
|
||||
}
|
||||
else if (m_opt_id.compare("ironing_type") == 0)
|
||||
m_value = static_cast<IroningType>(ret_enum);
|
||||
else if (m_opt_id.compare("fuzzy_skin_perimeter_mode") == 0)
|
||||
m_value = static_cast<FuzzySkinPerimeterMode>(ret_enum);
|
||||
else if (m_opt_id.compare("fuzzy_skin_shape") == 0)
|
||||
m_value = static_cast<FuzzySkinShape>(ret_enum);
|
||||
else if (m_opt_id.compare("gcode_flavor") == 0)
|
||||
m_value = static_cast<GCodeFlavor>(ret_enum);
|
||||
else if (m_opt_id.compare("machine_limits_usage") == 0)
|
||||
|
@ -182,6 +182,10 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt
|
||||
config.set_key_value(opt_key, new ConfigOptionEnum<InfillPattern>(boost::any_cast<InfillPattern>(value)));
|
||||
else if (opt_key.compare("ironing_type") == 0)
|
||||
config.set_key_value(opt_key, new ConfigOptionEnum<IroningType>(boost::any_cast<IroningType>(value)));
|
||||
else if (opt_key.compare("fuzzy_skin_perimeter_mode") == 0)
|
||||
config.set_key_value(opt_key, new ConfigOptionEnum<FuzzySkinPerimeterMode>(boost::any_cast<FuzzySkinPerimeterMode>(value)));
|
||||
else if (opt_key.compare("fuzzy_skin_shape") == 0)
|
||||
config.set_key_value(opt_key, new ConfigOptionEnum<FuzzySkinShape>(boost::any_cast<FuzzySkinShape>(value)));
|
||||
else if (opt_key.compare("gcode_flavor") == 0)
|
||||
config.set_key_value(opt_key, new ConfigOptionEnum<GCodeFlavor>(boost::any_cast<GCodeFlavor>(value)));
|
||||
else if (opt_key.compare("machine_limits_usage") == 0)
|
||||
|
@ -870,6 +870,12 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config
|
||||
else if (opt_key == "ironing_type") {
|
||||
ret = static_cast<int>(config.option<ConfigOptionEnum<IroningType>>(opt_key)->value);
|
||||
}
|
||||
else if (opt_key == "fuzzy_skin_perimeter_mode") {
|
||||
ret = static_cast<int>(config.option<ConfigOptionEnum<FuzzySkinPerimeterMode>>(opt_key)->value);
|
||||
}
|
||||
else if (opt_key == "fuzzy_skin_shape") {
|
||||
ret = static_cast<int>(config.option<ConfigOptionEnum<FuzzySkinShape>>(opt_key)->value);
|
||||
}
|
||||
else if (opt_key == "gcode_flavor") {
|
||||
ret = static_cast<int>(config.option<ConfigOptionEnum<GCodeFlavor>>(opt_key)->value);
|
||||
}
|
||||
|
@ -1434,6 +1434,18 @@ void TabPrint::build()
|
||||
optgroup->append_single_option_line("seam_position", category_path + "seam-position");
|
||||
optgroup->append_single_option_line("external_perimeters_first", category_path + "external-perimeters-first");
|
||||
|
||||
optgroup = page->new_optgroup(L("Fuzzy skin (experimental)"));
|
||||
Option option = optgroup->get_option("fuzzy_skin_perimeter_mode");
|
||||
option.opt.width = 30;
|
||||
optgroup->append_single_option_line(option);
|
||||
#if 0
|
||||
option = optgroup->get_option("fuzzy_skin_shape");
|
||||
option.opt.width = 30;
|
||||
optgroup->append_single_option_line(option);
|
||||
#endif
|
||||
optgroup->append_single_option_line(optgroup->get_option("fuzzy_skin_thickness"));
|
||||
optgroup->append_single_option_line(optgroup->get_option("fuzzy_skin_point_dist"));
|
||||
|
||||
page = add_options_page(L("Infill"), "infill");
|
||||
category_path = "infill_42#";
|
||||
optgroup = page->new_optgroup(L("Infill"));
|
||||
@ -1597,7 +1609,7 @@ void TabPrint::build()
|
||||
optgroup = page->new_optgroup(L("Output file"));
|
||||
optgroup->append_single_option_line("gcode_comments");
|
||||
optgroup->append_single_option_line("gcode_label_objects");
|
||||
Option option = optgroup->get_option("output_filename_format");
|
||||
option = optgroup->get_option("output_filename_format");
|
||||
option.opt.full_width = true;
|
||||
optgroup->append_single_option_line(option);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user