mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-18 02:05:53 +08:00
Merge branch 'ms_seam_tunning'
This commit is contained in:
commit
7ca4faf009
@ -69,6 +69,8 @@ namespace Slic3r {
|
||||
double value;
|
||||
bool percent;
|
||||
|
||||
double get_abs_value(double ratio_over) const { return this->percent ? (ratio_over * this->value / 100) : this->value; }
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive& ar) { ar(this->value); ar(this->percent); }
|
||||
@ -2265,17 +2267,18 @@ public:
|
||||
bool is_scalar() const { return (int(this->type) & int(coVectorType)) == 0; }
|
||||
|
||||
template<class Archive> ConfigOption* load_option_from_archive(Archive &archive) const {
|
||||
if (this->nullable) {
|
||||
switch (this->type) {
|
||||
case coFloat: { auto opt = new ConfigOptionFloatNullable(); archive(*opt); return opt; }
|
||||
case coInt: { auto opt = new ConfigOptionIntNullable(); archive(*opt); return opt; }
|
||||
case coFloats: { auto opt = new ConfigOptionFloatsNullable(); archive(*opt); return opt; }
|
||||
case coInts: { auto opt = new ConfigOptionIntsNullable(); archive(*opt); return opt; }
|
||||
case coPercents: { auto opt = new ConfigOptionPercentsNullable();archive(*opt); return opt; }
|
||||
case coBools: { auto opt = new ConfigOptionBoolsNullable(); archive(*opt); return opt; }
|
||||
default: throw ConfigurationError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown nullable option type for option ") + this->opt_key);
|
||||
}
|
||||
} else {
|
||||
if (this->nullable) {
|
||||
switch (this->type) {
|
||||
case coFloat: { auto opt = new ConfigOptionFloatNullable(); archive(*opt); return opt; }
|
||||
case coInt: { auto opt = new ConfigOptionIntNullable(); archive(*opt); return opt; }
|
||||
case coFloats: { auto opt = new ConfigOptionFloatsNullable(); archive(*opt); return opt; }
|
||||
case coInts: { auto opt = new ConfigOptionIntsNullable(); archive(*opt); return opt; }
|
||||
case coPercents: { auto opt = new ConfigOptionPercentsNullable(); archive(*opt); return opt; }
|
||||
case coBools: { auto opt = new ConfigOptionBoolsNullable(); archive(*opt); return opt; }
|
||||
case coFloatsOrPercents: { auto opt = new ConfigOptionFloatsOrPercentsNullable(); archive(*opt); return opt; }
|
||||
default: throw ConfigurationError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown nullable option type for option ") + this->opt_key);
|
||||
}
|
||||
} else {
|
||||
switch (this->type) {
|
||||
case coFloat: { auto opt = new ConfigOptionFloat(); archive(*opt); return opt; }
|
||||
case coFloats: { auto opt = new ConfigOptionFloats(); archive(*opt); return opt; }
|
||||
@ -2300,16 +2303,17 @@ public:
|
||||
}
|
||||
|
||||
template<class Archive> ConfigOption* save_option_to_archive(Archive &archive, const ConfigOption *opt) const {
|
||||
if (this->nullable) {
|
||||
switch (this->type) {
|
||||
case coFloat: archive(*static_cast<const ConfigOptionFloatNullable*>(opt)); break;
|
||||
case coInt: archive(*static_cast<const ConfigOptionIntNullable*>(opt)); break;
|
||||
case coFloats: archive(*static_cast<const ConfigOptionFloatsNullable*>(opt)); break;
|
||||
case coInts: archive(*static_cast<const ConfigOptionIntsNullable*>(opt)); break;
|
||||
case coPercents: archive(*static_cast<const ConfigOptionPercentsNullable*>(opt));break;
|
||||
case coBools: archive(*static_cast<const ConfigOptionBoolsNullable*>(opt)); break;
|
||||
default: throw ConfigurationError(std::string("ConfigOptionDef::save_option_to_archive(): Unknown nullable option type for option ") + this->opt_key);
|
||||
}
|
||||
if (this->nullable) {
|
||||
switch (this->type) {
|
||||
case coFloat: archive(*static_cast<const ConfigOptionFloatNullable*>(opt)); break;
|
||||
case coInt: archive(*static_cast<const ConfigOptionIntNullable*>(opt)); break;
|
||||
case coFloats: archive(*static_cast<const ConfigOptionFloatsNullable*>(opt)); break;
|
||||
case coInts: archive(*static_cast<const ConfigOptionIntsNullable*>(opt)); break;
|
||||
case coPercents: archive(*static_cast<const ConfigOptionPercentsNullable*>(opt)); break;
|
||||
case coBools: archive(*static_cast<const ConfigOptionBoolsNullable*>(opt)); break;
|
||||
case coFloatsOrPercents: archive(*static_cast<const ConfigOptionFloatsOrPercentsNullable*>(opt)); break;
|
||||
default: throw ConfigurationError(std::string("ConfigOptionDef::save_option_to_archive(): Unknown nullable option type for option ") + this->opt_key);
|
||||
}
|
||||
} else {
|
||||
switch (this->type) {
|
||||
case coFloat: archive(*static_cast<const ConfigOptionFloat*>(opt)); break;
|
||||
|
@ -2311,6 +2311,17 @@ std::pair<GCode::SmoothPath, std::size_t> split_with_seam(
|
||||
}
|
||||
} // namespace GCode
|
||||
|
||||
static inline double get_seam_gap_distance_value(const PrintConfig &config, const unsigned extruder_id)
|
||||
{
|
||||
const double nozzle_diameter = config.nozzle_diameter.get_at(extruder_id);
|
||||
const FloatOrPercent seam_gap_distance_override = config.filament_seam_gap_distance.get_at(extruder_id);
|
||||
if (!std::isnan(seam_gap_distance_override.value)) {
|
||||
return seam_gap_distance_override.get_abs_value(nozzle_diameter);
|
||||
}
|
||||
|
||||
return config.seam_gap_distance.get_abs_value(nozzle_diameter);
|
||||
}
|
||||
|
||||
using GCode::ExtrusionOrder::InstancePoint;
|
||||
|
||||
struct SmoothPathGenerator
|
||||
@ -2361,12 +2372,20 @@ struct SmoothPathGenerator
|
||||
// Clip the path to avoid the extruder to get exactly on the first point of the
|
||||
// loop; if polyline was shorter than the clipping distance we'd get a null
|
||||
// polyline, so we discard it in that case.
|
||||
const auto nozzle_diameter{config.nozzle_diameter.get_at(extruder_id)};
|
||||
if (enable_loop_clipping) {
|
||||
if (const double extrusion_clipping = get_seam_gap_distance_value(config, extruder_id); enable_loop_clipping && extrusion_clipping > 0.) {
|
||||
clip_end(
|
||||
result, scale_(nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER,
|
||||
result,
|
||||
scaled<double>(extrusion_clipping),
|
||||
scaled<double>(GCode::ExtrusionOrder::min_gcode_segment_length)
|
||||
);
|
||||
} else if (enable_loop_clipping && extrusion_clipping < 0.) {
|
||||
// Extend the extrusion slightly after the seam.
|
||||
const double smooth_path_extension_length = -1. * scaled<double>(extrusion_clipping);
|
||||
const double smooth_path_extension_cut_length = length(result) - smooth_path_extension_length;
|
||||
GCode::SmoothPath smooth_path_extension = result;
|
||||
|
||||
clip_end(smooth_path_extension, smooth_path_extension_cut_length, scaled<double>(GCode::ExtrusionOrder::min_gcode_segment_length));
|
||||
Slic3r::append(result, smooth_path_extension);
|
||||
}
|
||||
|
||||
assert(validate_smooth_path(result, !enable_loop_clipping));
|
||||
@ -3057,7 +3076,19 @@ std::string GCodeGenerator::extrude_perimeters(
|
||||
perimeter.extrusion_entity, print_instance.object_layer_to_print_id, print_instance.instance_id
|
||||
);
|
||||
|
||||
if (!m_wipe.enabled() && perimeter.extrusion_entity->role().is_external_perimeter() && m_layer != nullptr && m_config.perimeters.value > 1) {
|
||||
const bool is_extruding{
|
||||
!perimeter.smooth_path.empty()
|
||||
&& !perimeter.smooth_path.front().path.empty()
|
||||
&& perimeter.smooth_path.front().path.front().e_fraction > 0
|
||||
};
|
||||
|
||||
if (
|
||||
!m_wipe.enabled()
|
||||
&& perimeter.extrusion_entity->role().is_external_perimeter()
|
||||
&& m_layer != nullptr
|
||||
&& m_config.perimeters.value > 1
|
||||
&& is_extruding
|
||||
) {
|
||||
// Only wipe inside if the wipe along the perimeter is disabled.
|
||||
// Make a little move inwards before leaving loop.
|
||||
if (std::optional<Point> pt = wipe_hide_seam(perimeter.smooth_path, perimeter.reversed, scale_(EXTRUDER_CONFIG(nozzle_diameter))); pt) {
|
||||
|
@ -131,7 +131,7 @@ Params Placer::get_params(const DynamicPrintConfig &config) {
|
||||
params.staggered_inner_seams = config.opt_bool("staggered_inner_seams");
|
||||
|
||||
params.max_nearest_detour = 1.0;
|
||||
params.rear_tolerance = 0.2;
|
||||
params.rear_tolerance = 1.0;
|
||||
params.rear_y_offset = 20;
|
||||
params.aligned.jump_visibility_threshold = 0.6;
|
||||
params.max_distance = 5.0;
|
||||
@ -139,8 +139,8 @@ Params Placer::get_params(const DynamicPrintConfig &config) {
|
||||
params.perimeter.embedding_threshold = 0.5;
|
||||
params.perimeter.painting_radius = 0.1;
|
||||
params.perimeter.simplification_epsilon = 0.001;
|
||||
params.perimeter.smooth_angle_arm_length = 0.2;
|
||||
params.perimeter.sharp_angle_arm_length = 0.05;
|
||||
params.perimeter.smooth_angle_arm_length = 0.5;
|
||||
params.perimeter.sharp_angle_arm_length = 0.25;
|
||||
|
||||
params.visibility.raycasting_visibility_samples_count = 30000;
|
||||
params.visibility.fast_decimation_triangle_count_target = 16000;
|
||||
@ -297,7 +297,7 @@ boost::variant<Point, Scarf::Scarf> finalize_seam_position(
|
||||
Scarf::Scarf scarf{};
|
||||
scarf.entire_loop = region->config().scarf_seam_entire_loop;
|
||||
scarf.max_segment_length = region->config().scarf_seam_max_segment_length;
|
||||
scarf.start_height = region->config().scarf_seam_start_height.get_abs_value(1.0);
|
||||
scarf.start_height = std::min(region->config().scarf_seam_start_height.get_abs_value(1.0), 1.0);
|
||||
|
||||
const double offset{scarf.entire_loop ? 0.0 : region->config().scarf_seam_length.value};
|
||||
const std::optional<Geometry::PointOnLine> outter_scarf_start_point{Geometry::offset_along_lines(
|
||||
|
@ -59,16 +59,28 @@ struct RearestPointCalculator {
|
||||
const Vec2d prefered_position{center_x, bounding_box.max.y() + rear_y_offset};
|
||||
auto [_, line_index, point] = possible_distancer.distance_from_lines_extra<false>(prefered_position);
|
||||
const Vec2d location_at_bb{center_x, bounding_box.max.y()};
|
||||
auto [_d, line_index_at_bb, point_at_bb] = possible_distancer.distance_from_lines_extra<false>(location_at_bb);
|
||||
const double y_distance{point.y() - point_at_bb.y()};
|
||||
auto [_d, line_index_at_bb, point_bb] = possible_distancer.distance_from_lines_extra<false>(location_at_bb);
|
||||
const double y_distance{point.y() - point_bb.y()};
|
||||
|
||||
Vec2d result{point};
|
||||
if (y_distance < 0) {
|
||||
result = point_at_bb;
|
||||
result = point_bb;
|
||||
} else if (y_distance <= rear_tolerance) {
|
||||
const double factor{y_distance / rear_tolerance};
|
||||
result = factor * point + (1 - factor) * point_at_bb;
|
||||
result = factor * point + (1 - factor) * point_bb;
|
||||
}
|
||||
|
||||
if (bounding_box.max.y() - result.y() > rear_tolerance) {
|
||||
for (const PerimeterLine &line : possible_lines) {
|
||||
if (line.a.y() > result.y()) {
|
||||
result = line.a;
|
||||
}
|
||||
if (line.b.y() > result.y()) {
|
||||
result = line.b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SeamChoice{possible_lines[line_index].previous_index, possible_lines[line_index].next_index, result};
|
||||
}
|
||||
};
|
||||
|
@ -456,7 +456,8 @@ static std::vector<std::string> s_Preset_print_options {
|
||||
"top_solid_layers", "top_solid_min_thickness", "bottom_solid_layers", "bottom_solid_min_thickness",
|
||||
"ensure_vertical_shell_thickness", "extra_perimeters", "extra_perimeters_on_overhangs",
|
||||
"avoid_crossing_curled_overhangs", "avoid_crossing_perimeters", "thin_walls", "overhangs",
|
||||
"seam_position","staggered_inner_seams", "external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern",
|
||||
"seam_position", "staggered_inner_seams", "seam_gap_distance",
|
||||
"external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern",
|
||||
"scarf_seam_placement", "scarf_seam_only_on_smooth", "scarf_seam_start_height", "scarf_seam_entire_loop", "scarf_seam_length", "scarf_seam_max_segment_length", "scarf_seam_on_inner_perimeters",
|
||||
"infill_every_layers", /*"infill_only_where_needed",*/ "solid_infill_every_layers", "fill_angle", "bridge_angle",
|
||||
"solid_infill_below_area", "only_retract_when_crossing_perimeters", "infill_first",
|
||||
@ -512,6 +513,8 @@ static std::vector<std::string> s_Preset_filament_options {
|
||||
"filament_vendor", "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits",
|
||||
// Shrinkage compensation
|
||||
"filament_shrinkage_compensation_xy", "filament_shrinkage_compensation_z",
|
||||
// Seams overrides
|
||||
"filament_seam_gap_distance"
|
||||
};
|
||||
|
||||
static std::vector<std::string> s_Preset_machine_limits_options {
|
||||
|
@ -120,6 +120,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
"filament_density",
|
||||
"filament_notes",
|
||||
"filament_cost",
|
||||
"filament_seam_gap_distance",
|
||||
"filament_spool_weight",
|
||||
"first_layer_acceleration",
|
||||
"first_layer_acceleration_over_raft",
|
||||
@ -161,6 +162,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
"retract_restart_extra",
|
||||
"retract_restart_extra_toolchange",
|
||||
"retract_speed",
|
||||
"seam_gap_distance",
|
||||
"single_extruder_multi_material_priming",
|
||||
"slowdown_below_layer_time",
|
||||
"solid_infill_acceleration",
|
||||
|
@ -2654,6 +2654,17 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloats { 0. });
|
||||
|
||||
def = this->add("seam_gap_distance", coFloatOrPercent);
|
||||
def->label = L("Seam gap distance");
|
||||
def->tooltip = L("The distance between the endpoints of a closed loop perimeter. "
|
||||
"Positive values will shorten and interrupt the loop slightly to reduce the seam. "
|
||||
"Negative values will extend the loop, causing the endpoints to overlap slightly. "
|
||||
"When percents are used, the distance is derived from the nozzle diameter. "
|
||||
"Set to zero to disable this feature.");
|
||||
def->sidetext = L("mm or %");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloatOrPercent{ 15., true });
|
||||
|
||||
def = this->add("seam_position", coEnum);
|
||||
def->label = L("Seam position");
|
||||
def->category = L("Layers and Perimeters");
|
||||
@ -2699,6 +2710,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->tooltip = L("Start height of the scarf joint specified as fraction of the current layer height.");
|
||||
def->sidetext = L(" %");
|
||||
def->min = 0;
|
||||
def->max = 100;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionPercent(0));
|
||||
|
||||
@ -3774,9 +3786,9 @@ void PrintConfigDef::init_fff_params()
|
||||
auto it_opt = options.find(opt_key);
|
||||
assert(it_opt != options.end());
|
||||
def = this->add_nullable(std::string("filament_") + opt_key, it_opt->second.type);
|
||||
def->label = it_opt->second.label;
|
||||
def->label = it_opt->second.label;
|
||||
def->full_label = it_opt->second.full_label;
|
||||
def->tooltip = it_opt->second.tooltip;
|
||||
def->tooltip = it_opt->second.tooltip;
|
||||
def->sidetext = it_opt->second.sidetext;
|
||||
def->mode = it_opt->second.mode;
|
||||
switch (def->type) {
|
||||
@ -3786,6 +3798,44 @@ void PrintConfigDef::init_fff_params()
|
||||
default: assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Declare values for filament profile, overriding printer's profile.
|
||||
for (const char *opt_key : {
|
||||
// Floats or Percents
|
||||
"seam_gap_distance"}) {
|
||||
|
||||
auto it_opt = options.find(opt_key);
|
||||
assert(it_opt != options.end());
|
||||
|
||||
switch (it_opt->second.type) {
|
||||
case coFloatOrPercent: {
|
||||
def = this->add_nullable(std::string("filament_") + opt_key, coFloatsOrPercents);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
def->label = it_opt->second.label;
|
||||
def->full_label = it_opt->second.full_label;
|
||||
def->tooltip = it_opt->second.tooltip;
|
||||
def->sidetext = it_opt->second.sidetext;
|
||||
def->mode = it_opt->second.mode;
|
||||
|
||||
switch (def->type) {
|
||||
case coFloatsOrPercents: {
|
||||
const auto &default_value = *static_cast<const ConfigOptionFloatOrPercent *>(it_opt->second.default_value.get());
|
||||
def->set_default_value(new ConfigOptionFloatsOrPercentsNullable{{default_value.value, default_value.percent}});
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrintConfigDef::init_extruder_option_keys()
|
||||
|
@ -830,6 +830,7 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
((ConfigOptionFloats, filament_multitool_ramming_flow))
|
||||
((ConfigOptionFloats, filament_stamping_loading_speed))
|
||||
((ConfigOptionFloats, filament_stamping_distance))
|
||||
((ConfigOptionFloatsOrPercentsNullable, filament_seam_gap_distance))
|
||||
((ConfigOptionPercents, filament_shrinkage_compensation_xy))
|
||||
((ConfigOptionPercents, filament_shrinkage_compensation_z))
|
||||
((ConfigOptionBool, gcode_comments))
|
||||
@ -860,6 +861,7 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
((ConfigOptionFloats, retract_restart_extra))
|
||||
((ConfigOptionFloats, retract_restart_extra_toolchange))
|
||||
((ConfigOptionFloats, retract_speed))
|
||||
((ConfigOptionFloatOrPercent, seam_gap_distance))
|
||||
((ConfigOptionString, start_gcode))
|
||||
((ConfigOptionStrings, start_filament_gcode))
|
||||
((ConfigOptionBool, single_extruder_multi_material))
|
||||
|
@ -331,19 +331,22 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
|
||||
if ((m_opt.type == coFloatOrPercent || m_opt.type == coFloatsOrPercents) && !str.IsEmpty() && str.Last() != '%')
|
||||
{
|
||||
double val = 0.;
|
||||
|
||||
bool is_na_value = m_opt.nullable && str == na_value();
|
||||
|
||||
const char dec_sep = is_decimal_separator_point() ? '.' : ',';
|
||||
const char dec_sep_alt = dec_sep == '.' ? ',' : '.';
|
||||
// Replace the first incorrect separator in decimal number.
|
||||
if (str.Replace(dec_sep_alt, dec_sep, false) != 0)
|
||||
if (!is_na_value && str.Replace(dec_sep_alt, dec_sep, false) != 0)
|
||||
set_value(str, false);
|
||||
|
||||
|
||||
// remove space and "mm" substring, if any exists
|
||||
str.Replace(" ", "", true);
|
||||
str.Replace("m", "", true);
|
||||
|
||||
if (!str.ToDouble(&val))
|
||||
{
|
||||
if (is_na_value) {
|
||||
val = ConfigOptionFloatsOrPercentsNullable::nil_value().value;
|
||||
} else if (!str.ToDouble(&val)) {
|
||||
if (!check_value) {
|
||||
m_value.clear();
|
||||
break;
|
||||
@ -453,8 +456,11 @@ void TextCtrl::BUILD() {
|
||||
case coFloatsOrPercents: {
|
||||
const auto val = m_opt.get_default_value<ConfigOptionFloatsOrPercents>()->get_at(m_opt_idx);
|
||||
text_value = double_to_string(val.value);
|
||||
if (val.percent)
|
||||
if (val.percent) {
|
||||
text_value += "%";
|
||||
}
|
||||
|
||||
m_last_meaningful_value = text_value;
|
||||
break;
|
||||
}
|
||||
case coPercent:
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include "slic3r/GUI/Search.hpp" // IWYU pragma: keep
|
||||
#include "slic3r/GUI/Field.hpp"
|
||||
#include "libslic3r/Exception.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "libslic3r/AppConfig.hpp"
|
||||
@ -175,8 +176,10 @@ void OptionsGroup::change_opt_value(DynamicPrintConfig& config, const t_config_o
|
||||
str.pop_back();
|
||||
percent = true;
|
||||
}
|
||||
double val = std::stod(str); // locale-dependent (on purpose - the input is the actual content of the field)
|
||||
ConfigOptionFloatsOrPercents* vec_new = new ConfigOptionFloatsOrPercents({ {val, percent} });
|
||||
|
||||
const bool is_na_value = opt_def->nullable && str == _(L("N/A"));
|
||||
const FloatOrPercent val = is_na_value ? ConfigOptionFloatsOrPercentsNullable::nil_value() : FloatOrPercent{std::stod(str), percent};
|
||||
ConfigOptionFloatsOrPercents *vec_new = new ConfigOptionFloatsOrPercents({val});
|
||||
config.option<ConfigOptionFloatsOrPercents>(opt_key)->set_at(vec_new, opt_index, opt_index);
|
||||
break;
|
||||
}
|
||||
@ -1020,6 +1023,21 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config
|
||||
ret = double_to_string(val); }
|
||||
}
|
||||
break;
|
||||
case coFloatsOrPercents: {
|
||||
if (config.option(opt_key)->is_nil()) {
|
||||
ret = _(L("N/A"));
|
||||
} else {
|
||||
const auto &config_option = config.option<ConfigOptionFloatsOrPercentsNullable>(opt_key)->get_at(idx);
|
||||
|
||||
text_value = double_to_string(config_option.value);
|
||||
if (config_option.percent) {
|
||||
text_value += "%";
|
||||
}
|
||||
|
||||
ret = text_value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case coBools:
|
||||
ret = config.option<ConfigOptionBoolsNullable>(opt_key)->values[idx];
|
||||
break;
|
||||
|
@ -1458,6 +1458,7 @@ void TabPrint::build()
|
||||
|
||||
optgroup = page->new_optgroup(L("Advanced"));
|
||||
optgroup->append_single_option_line("seam_position", category_path + "seam-position");
|
||||
optgroup->append_single_option_line("seam_gap_distance", category_path + "seam-gap-distance");
|
||||
optgroup->append_single_option_line("staggered_inner_seams", category_path + "staggered-inner-seams");
|
||||
|
||||
optgroup->append_single_option_line("scarf_seam_placement", category_path + "scarf-seam-placement");
|
||||
@ -1968,6 +1969,9 @@ std::vector<std::pair<std::string, std::vector<std::string>>> filament_overrides
|
||||
{"Retraction when tool is disabled", {
|
||||
"filament_retract_length_toolchange",
|
||||
"filament_retract_restart_extra_toolchange"
|
||||
}},
|
||||
{"Seams", {
|
||||
"filament_seam_gap_distance"
|
||||
}}
|
||||
};
|
||||
|
||||
|
@ -124,44 +124,48 @@ constexpr const char *to_string(Perimeters::AngleType angle_type) {
|
||||
throw std::runtime_error("Unreachable");
|
||||
}
|
||||
|
||||
void serialize_shell(std::ostream &output, const Shells::Shell<Perimeters::Perimeter> &shell) {
|
||||
void serialize_shells(std::ostream &output, const Shells::Shells<> &shells) {
|
||||
output << "x,y,z,point_type,point_classification,angle_type,layer_index,"
|
||||
"point_index,distance,distance_to_previous,is_degenerate"
|
||||
"point_index,distance,distance_to_previous,is_degenerate,shell_index"
|
||||
<< std::endl;
|
||||
|
||||
for (std::size_t perimeter_index{0}; perimeter_index < shell.size(); ++perimeter_index) {
|
||||
const Shells::Slice<> &slice{shell[perimeter_index]};
|
||||
const Perimeters::Perimeter &perimeter{slice.boundary};
|
||||
const std::vector<Vec2d> &points{perimeter.positions};
|
||||
for (std::size_t shell_index{0}; shell_index < shells.size(); ++shell_index) {
|
||||
const Shells::Shell<> &shell{shells[shell_index]};
|
||||
for (std::size_t perimeter_index{0}; perimeter_index < shell.size(); ++perimeter_index) {
|
||||
const Shells::Slice<> &slice{shell[perimeter_index]};
|
||||
const Perimeters::Perimeter &perimeter{slice.boundary};
|
||||
const std::vector<Vec2d> &points{perimeter.positions};
|
||||
|
||||
double total_distance{0.0};
|
||||
for (std::size_t point_index{0}; point_index < perimeter.point_types.size(); ++point_index) {
|
||||
const Vec3d point{to_3d(points[point_index], perimeter.slice_z)};
|
||||
const Perimeters::PointType point_type{perimeter.point_types[point_index]};
|
||||
const Perimeters::PointClassification point_classification{
|
||||
perimeter.point_classifications[point_index]};
|
||||
const Perimeters::AngleType angle_type{perimeter.angle_types[point_index]};
|
||||
const std::size_t layer_index{slice.layer_index};
|
||||
const std::size_t previous_index{point_index == 0 ? points.size() - 1 : point_index - 1};
|
||||
const double distance_to_previous{(points[point_index] - points[previous_index]).norm()};
|
||||
total_distance += point_index == 0 ? 0.0 : distance_to_previous;
|
||||
const double distance{total_distance};
|
||||
const bool is_degenerate{perimeter.is_degenerate};
|
||||
double total_distance{0.0};
|
||||
for (std::size_t point_index{0}; point_index < perimeter.point_types.size(); ++point_index) {
|
||||
const Vec3d point{to_3d(points[point_index], perimeter.slice_z)};
|
||||
const Perimeters::PointType point_type{perimeter.point_types[point_index]};
|
||||
const Perimeters::PointClassification point_classification{
|
||||
perimeter.point_classifications[point_index]};
|
||||
const Perimeters::AngleType angle_type{perimeter.angle_types[point_index]};
|
||||
const std::size_t layer_index{slice.layer_index};
|
||||
const std::size_t previous_index{point_index == 0 ? points.size() - 1 : point_index - 1};
|
||||
const double distance_to_previous{(points[point_index] - points[previous_index]).norm()};
|
||||
total_distance += point_index == 0 ? 0.0 : distance_to_previous;
|
||||
const double distance{total_distance};
|
||||
const bool is_degenerate{perimeter.is_degenerate};
|
||||
|
||||
// clang-format off
|
||||
output
|
||||
<< point.x() << ","
|
||||
<< point.y() << ","
|
||||
<< point.z() << ","
|
||||
<< to_string(point_type) << ","
|
||||
<< to_string(point_classification) << ","
|
||||
<< to_string(angle_type) << ","
|
||||
<< layer_index << ","
|
||||
<< point_index << ","
|
||||
<< distance << ","
|
||||
<< distance_to_previous << ","
|
||||
<< is_degenerate << std::endl;
|
||||
// clang-format on
|
||||
// clang-format off
|
||||
output
|
||||
<< point.x() << ","
|
||||
<< point.y() << ","
|
||||
<< point.z() << ","
|
||||
<< to_string(point_type) << ","
|
||||
<< to_string(point_classification) << ","
|
||||
<< to_string(angle_type) << ","
|
||||
<< layer_index << ","
|
||||
<< point_index << ","
|
||||
<< distance << ","
|
||||
<< distance_to_previous << ","
|
||||
<< is_degenerate << ","
|
||||
<< shell_index << std::endl;
|
||||
// clang-format on
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -175,6 +179,6 @@ TEST_CASE_METHOD(Test::SeamsFixture, "Create perimeters", "[Seams][SeamPerimeter
|
||||
|
||||
if constexpr (debug_files) {
|
||||
std::ofstream csv{"perimeters.csv"};
|
||||
serialize_shell(csv, shells[0]);
|
||||
serialize_shells(csv, shells);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user