mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-14 10:17:55 -06:00
Implemented top_solid_min_thickness / bottom_solid_min_thickness.
The two new config keys define a minimum vertical shell thickness. The top shell thickness is calculated as a maximum of sum over top_solid_layers * layer heights and top_solid_min_thickness, the bottom shell thickness is calculated as a maximum of sum over bottom_solid_layers * layer heights and bottom_solid_min_thickness. The results of the formula above are shown at the Print parameter page below the two new values to hint the user about the interaction of the old versus new config values. top_solid_min_thickness has no meaning if top_solid_layers is zero, bottom_solid_min_thickness has no meaning if bottom_solid_layers is zero.
This commit is contained in:
parent
6f777264a1
commit
495a71ed00
14 changed files with 246 additions and 52 deletions
|
@ -42,7 +42,7 @@ enum Mode
|
||||||
SingleExtruder, // Single extruder printer preset is selected
|
SingleExtruder, // Single extruder printer preset is selected
|
||||||
MultiAsSingle, // Multiple extruder printer preset is selected, but
|
MultiAsSingle, // Multiple extruder printer preset is selected, but
|
||||||
// this mode works just for Single extruder print
|
// this mode works just for Single extruder print
|
||||||
// (For all print from objects settings is used just one extruder)
|
// (The same extruder is assigned to all ModelObjects and ModelVolumes).
|
||||||
MultiExtruder // Multiple extruder printer preset is selected
|
MultiExtruder // Multiple extruder printer preset is selected
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,7 @@ public:
|
||||||
coordf_t slice_z; // Z used for slicing in unscaled coordinates
|
coordf_t slice_z; // Z used for slicing in unscaled coordinates
|
||||||
coordf_t print_z; // Z used for printing in unscaled coordinates
|
coordf_t print_z; // Z used for printing in unscaled coordinates
|
||||||
coordf_t height; // layer height in unscaled coordinates
|
coordf_t height; // layer height in unscaled coordinates
|
||||||
|
coordf_t bottom_z() const { return this->print_z - this->height; }
|
||||||
|
|
||||||
// Collection of expolygons generated by slicing the possibly multiple meshes of the source geometry
|
// Collection of expolygons generated by slicing the possibly multiple meshes of the source geometry
|
||||||
// (with possibly differing extruder ID and slicing parameters) and merged.
|
// (with possibly differing extruder ID and slicing parameters) and merged.
|
||||||
|
|
|
@ -168,6 +168,17 @@ void PrintConfigDef::init_fff_params()
|
||||||
def->min = 0;
|
def->min = 0;
|
||||||
def->set_default_value(new ConfigOptionInt(3));
|
def->set_default_value(new ConfigOptionInt(3));
|
||||||
|
|
||||||
|
def = this->add("bottom_solid_min_thickness", coFloat);
|
||||||
|
//TRN To be shown in Print Settings "Top solid layers"
|
||||||
|
def->label = L("Bottom");
|
||||||
|
def->category = L("Layers and Perimeters");
|
||||||
|
def->tooltip = L("The number of bottom solid layers is increased above bottom_solid_layers if necessary to satisfy "
|
||||||
|
"minimum thickness of bottom shell.");
|
||||||
|
def->full_label = L("Minimum bottom shell thickness");
|
||||||
|
def->sidetext = L("mm");
|
||||||
|
def->min = 0;
|
||||||
|
def->set_default_value(new ConfigOptionFloat(0.));
|
||||||
|
|
||||||
def = this->add("bridge_acceleration", coFloat);
|
def = this->add("bridge_acceleration", coFloat);
|
||||||
def->label = L("Bridge");
|
def->label = L("Bridge");
|
||||||
def->tooltip = L("This is the acceleration your printer will use for bridges. "
|
def->tooltip = L("This is the acceleration your printer will use for bridges. "
|
||||||
|
@ -1782,6 +1793,13 @@ void PrintConfigDef::init_fff_params()
|
||||||
def->shortcut.push_back("bottom_solid_layers");
|
def->shortcut.push_back("bottom_solid_layers");
|
||||||
def->min = 0;
|
def->min = 0;
|
||||||
|
|
||||||
|
def = this->add("solid_min_thickness", coFloat);
|
||||||
|
def->label = L("Minimum thickness of a top / bottom shell");
|
||||||
|
def->tooltip = L("Minimum thickness of a top / bottom shell");
|
||||||
|
def->shortcut.push_back("top_solid_min_thickness");
|
||||||
|
def->shortcut.push_back("bottom_solid_min_thickness");
|
||||||
|
def->min = 0;
|
||||||
|
|
||||||
def = this->add("spiral_vase", coBool);
|
def = this->add("spiral_vase", coBool);
|
||||||
def->label = L("Spiral vase");
|
def->label = L("Spiral vase");
|
||||||
def->tooltip = L("This feature will raise Z gradually while printing a single-walled object "
|
def->tooltip = L("This feature will raise Z gradually while printing a single-walled object "
|
||||||
|
@ -2128,6 +2146,18 @@ void PrintConfigDef::init_fff_params()
|
||||||
def->min = 0;
|
def->min = 0;
|
||||||
def->set_default_value(new ConfigOptionInt(3));
|
def->set_default_value(new ConfigOptionInt(3));
|
||||||
|
|
||||||
|
def = this->add("top_solid_min_thickness", coFloat);
|
||||||
|
//TRN To be shown in Print Settings "Top solid layers"
|
||||||
|
def->label = L("Top");
|
||||||
|
def->category = L("Layers and Perimeters");
|
||||||
|
def->tooltip = L("The number of top solid layers is increased above top_solid_layers if necessary to satisfy "
|
||||||
|
"minimum thickness of top shell."
|
||||||
|
" This is useful to prevent pillowing effect when printing with variable layer height.");
|
||||||
|
def->full_label = L("Minimum top shell thickness");
|
||||||
|
def->sidetext = L("mm");
|
||||||
|
def->min = 0;
|
||||||
|
def->set_default_value(new ConfigOptionFloat(0.));
|
||||||
|
|
||||||
def = this->add("travel_speed", coFloat);
|
def = this->add("travel_speed", coFloat);
|
||||||
def->label = L("Travel");
|
def->label = L("Travel");
|
||||||
def->tooltip = L("Speed for travel moves (jumps between distant extrusion points).");
|
def->tooltip = L("Speed for travel moves (jumps between distant extrusion points).");
|
||||||
|
|
|
@ -466,6 +466,7 @@ class PrintRegionConfig : public StaticPrintConfig
|
||||||
public:
|
public:
|
||||||
ConfigOptionFloat bridge_angle;
|
ConfigOptionFloat bridge_angle;
|
||||||
ConfigOptionInt bottom_solid_layers;
|
ConfigOptionInt bottom_solid_layers;
|
||||||
|
ConfigOptionFloat bottom_solid_min_thickness;
|
||||||
ConfigOptionFloat bridge_flow_ratio;
|
ConfigOptionFloat bridge_flow_ratio;
|
||||||
ConfigOptionFloat bridge_speed;
|
ConfigOptionFloat bridge_speed;
|
||||||
ConfigOptionBool ensure_vertical_shell_thickness;
|
ConfigOptionBool ensure_vertical_shell_thickness;
|
||||||
|
@ -501,6 +502,7 @@ public:
|
||||||
ConfigOptionBool thin_walls;
|
ConfigOptionBool thin_walls;
|
||||||
ConfigOptionFloatOrPercent top_infill_extrusion_width;
|
ConfigOptionFloatOrPercent top_infill_extrusion_width;
|
||||||
ConfigOptionInt top_solid_layers;
|
ConfigOptionInt top_solid_layers;
|
||||||
|
ConfigOptionFloat top_solid_min_thickness;
|
||||||
ConfigOptionFloatOrPercent top_solid_infill_speed;
|
ConfigOptionFloatOrPercent top_solid_infill_speed;
|
||||||
ConfigOptionBool wipe_into_infill;
|
ConfigOptionBool wipe_into_infill;
|
||||||
|
|
||||||
|
@ -509,6 +511,7 @@ protected:
|
||||||
{
|
{
|
||||||
OPT_PTR(bridge_angle);
|
OPT_PTR(bridge_angle);
|
||||||
OPT_PTR(bottom_solid_layers);
|
OPT_PTR(bottom_solid_layers);
|
||||||
|
OPT_PTR(bottom_solid_min_thickness);
|
||||||
OPT_PTR(bridge_flow_ratio);
|
OPT_PTR(bridge_flow_ratio);
|
||||||
OPT_PTR(bridge_speed);
|
OPT_PTR(bridge_speed);
|
||||||
OPT_PTR(ensure_vertical_shell_thickness);
|
OPT_PTR(ensure_vertical_shell_thickness);
|
||||||
|
@ -542,6 +545,7 @@ protected:
|
||||||
OPT_PTR(top_infill_extrusion_width);
|
OPT_PTR(top_infill_extrusion_width);
|
||||||
OPT_PTR(top_solid_infill_speed);
|
OPT_PTR(top_solid_infill_speed);
|
||||||
OPT_PTR(top_solid_layers);
|
OPT_PTR(top_solid_layers);
|
||||||
|
OPT_PTR(top_solid_min_thickness);
|
||||||
OPT_PTR(wipe_into_infill);
|
OPT_PTR(wipe_into_infill);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -507,7 +507,9 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
|
||||||
|| opt_key == "infill_every_layers"
|
|| opt_key == "infill_every_layers"
|
||||||
|| opt_key == "solid_infill_every_layers"
|
|| opt_key == "solid_infill_every_layers"
|
||||||
|| opt_key == "bottom_solid_layers"
|
|| opt_key == "bottom_solid_layers"
|
||||||
|
|| opt_key == "bottom_solid_min_thickness"
|
||||||
|| opt_key == "top_solid_layers"
|
|| opt_key == "top_solid_layers"
|
||||||
|
|| opt_key == "top_solid_min_thickness"
|
||||||
|| opt_key == "solid_infill_below_area"
|
|| opt_key == "solid_infill_below_area"
|
||||||
|| opt_key == "infill_extruder"
|
|| opt_key == "infill_extruder"
|
||||||
|| opt_key == "solid_infill_extruder"
|
|| opt_key == "solid_infill_extruder"
|
||||||
|
@ -914,6 +916,19 @@ void PrintObject::discover_vertical_shells()
|
||||||
Polygons bottom_surfaces;
|
Polygons bottom_surfaces;
|
||||||
Polygons holes;
|
Polygons holes;
|
||||||
};
|
};
|
||||||
|
coordf_t min_layer_height = this->slicing_parameters().min_layer_height;
|
||||||
|
// Does this region possibly produce more than 1 top or bottom layer?
|
||||||
|
auto has_extra_layers_fn = [min_layer_height](const PrintRegionConfig &config) {
|
||||||
|
auto num_extra_layers = [min_layer_height](int num_solid_layers, coordf_t min_shell_thickness) {
|
||||||
|
if (num_solid_layers == 0)
|
||||||
|
return 0;
|
||||||
|
int n = num_solid_layers - 1;
|
||||||
|
int n2 = int(ceil(min_shell_thickness / min_layer_height));
|
||||||
|
return std::max(n, n2 - 1);
|
||||||
|
};
|
||||||
|
return num_extra_layers(config.top_solid_layers, config.top_solid_min_thickness) +
|
||||||
|
num_extra_layers(config.bottom_solid_layers, config.bottom_solid_min_thickness) > 0;
|
||||||
|
};
|
||||||
std::vector<DiscoverVerticalShellsCacheEntry> cache_top_botom_regions(m_layers.size(), DiscoverVerticalShellsCacheEntry());
|
std::vector<DiscoverVerticalShellsCacheEntry> cache_top_botom_regions(m_layers.size(), DiscoverVerticalShellsCacheEntry());
|
||||||
bool top_bottom_surfaces_all_regions = this->region_volumes.size() > 1 && ! m_config.interface_shells.value;
|
bool top_bottom_surfaces_all_regions = this->region_volumes.size() > 1 && ! m_config.interface_shells.value;
|
||||||
if (top_bottom_surfaces_all_regions) {
|
if (top_bottom_surfaces_all_regions) {
|
||||||
|
@ -921,11 +936,11 @@ void PrintObject::discover_vertical_shells()
|
||||||
// is calculated over all materials.
|
// is calculated over all materials.
|
||||||
// Is the "ensure vertical wall thickness" applicable to any region?
|
// Is the "ensure vertical wall thickness" applicable to any region?
|
||||||
bool has_extra_layers = false;
|
bool has_extra_layers = false;
|
||||||
for (size_t idx_region = 0; idx_region < this->region_volumes.size(); ++ idx_region) {
|
for (size_t idx_region = 0; idx_region < this->region_volumes.size(); ++idx_region) {
|
||||||
const PrintRegion ®ion = *m_print->get_region(idx_region);
|
const PrintRegionConfig &config = m_print->get_region(idx_region)->config();
|
||||||
if (region.config().ensure_vertical_shell_thickness.value &&
|
if (config.ensure_vertical_shell_thickness.value && has_extra_layers_fn(config)) {
|
||||||
(region.config().top_solid_layers.value > 1 || region.config().bottom_solid_layers.value > 1)) {
|
|
||||||
has_extra_layers = true;
|
has_extra_layers = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (! has_extra_layers)
|
if (! has_extra_layers)
|
||||||
|
@ -1006,9 +1021,7 @@ void PrintObject::discover_vertical_shells()
|
||||||
if (! region.config().ensure_vertical_shell_thickness.value)
|
if (! region.config().ensure_vertical_shell_thickness.value)
|
||||||
// This region will be handled by discover_horizontal_shells().
|
// This region will be handled by discover_horizontal_shells().
|
||||||
continue;
|
continue;
|
||||||
int n_extra_top_layers = std::max(0, region.config().top_solid_layers.value - 1);
|
if (! has_extra_layers_fn(region.config()))
|
||||||
int n_extra_bottom_layers = std::max(0, region.config().bottom_solid_layers.value - 1);
|
|
||||||
if (n_extra_top_layers + n_extra_bottom_layers == 0)
|
|
||||||
// Zero or 1 layer, there is no additional vertical wall thickness enforced.
|
// Zero or 1 layer, there is no additional vertical wall thickness enforced.
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1049,7 +1062,7 @@ void PrintObject::discover_vertical_shells()
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << idx_region << " in parallel - start : ensure vertical wall thickness";
|
BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << idx_region << " in parallel - start : ensure vertical wall thickness";
|
||||||
tbb::parallel_for(
|
tbb::parallel_for(
|
||||||
tbb::blocked_range<size_t>(0, m_layers.size(), grain_size),
|
tbb::blocked_range<size_t>(0, m_layers.size(), grain_size),
|
||||||
[this, idx_region, n_extra_top_layers, n_extra_bottom_layers, &cache_top_botom_regions]
|
[this, idx_region, &cache_top_botom_regions]
|
||||||
(const tbb::blocked_range<size_t>& range) {
|
(const tbb::blocked_range<size_t>& range) {
|
||||||
// printf("discover_vertical_shells from %d to %d\n", range.begin(), range.end());
|
// printf("discover_vertical_shells from %d to %d\n", range.begin(), range.end());
|
||||||
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
|
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
|
||||||
|
@ -1062,6 +1075,7 @@ void PrintObject::discover_vertical_shells()
|
||||||
|
|
||||||
Layer *layer = m_layers[idx_layer];
|
Layer *layer = m_layers[idx_layer];
|
||||||
LayerRegion *layerm = layer->m_regions[idx_region];
|
LayerRegion *layerm = layer->m_regions[idx_region];
|
||||||
|
const PrintRegionConfig ®ion_config = layerm->region()->config();
|
||||||
|
|
||||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||||
layerm->export_region_slices_to_svg_debug("4_discover_vertical_shells-initial");
|
layerm->export_region_slices_to_svg_debug("4_discover_vertical_shells-initial");
|
||||||
|
@ -1101,30 +1115,47 @@ void PrintObject::discover_vertical_shells()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||||
// Reset the top / bottom inflated regions caches of entries, which are out of the moving window.
|
polygons_append(holes, cache_top_botom_regions[idx_layer].holes);
|
||||||
bool hole_first = true;
|
{
|
||||||
for (int n = (int)idx_layer - n_extra_bottom_layers; n <= (int)idx_layer + n_extra_top_layers; ++ n)
|
// Gather top regions projected to this layer.
|
||||||
if (n >= 0 && n < (int)m_layers.size()) {
|
coordf_t print_z = layer->print_z;
|
||||||
const DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[n];
|
int n_top_layers = region_config.top_solid_layers.value;
|
||||||
if (hole_first) {
|
for (int i = int(idx_layer) + 1;
|
||||||
hole_first = false;
|
i < int(m_layers.size()) &&
|
||||||
polygons_append(holes, cache.holes);
|
(i < int(idx_layer) + n_top_layers ||
|
||||||
}
|
m_layers[i]->print_z - print_z < region_config.top_solid_min_thickness - EPSILON);
|
||||||
else if (! holes.empty()) {
|
++ i) {
|
||||||
|
const DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[i];
|
||||||
|
if (! holes.empty())
|
||||||
holes = intersection(holes, cache.holes);
|
holes = intersection(holes, cache.holes);
|
||||||
}
|
if (! cache.top_surfaces.empty()) {
|
||||||
size_t n_shell_old = shell.size();
|
|
||||||
if (n > int(idx_layer))
|
|
||||||
// Collect top surfaces.
|
|
||||||
polygons_append(shell, cache.top_surfaces);
|
polygons_append(shell, cache.top_surfaces);
|
||||||
else if (n < int(idx_layer))
|
// Running the union_ using the Clipper library piece by piece is cheaper
|
||||||
// Collect bottom and bottom bridge surfaces.
|
// than running the union_ all at once.
|
||||||
|
shell = union_(shell, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Gather bottom regions projected to this layer.
|
||||||
|
coordf_t bottom_z = layer->bottom_z();
|
||||||
|
int n_bottom_layers = region_config.bottom_solid_layers.value;
|
||||||
|
for (int i = int(idx_layer) - 1;
|
||||||
|
i >= 0 &&
|
||||||
|
(i > int(idx_layer) - n_bottom_layers ||
|
||||||
|
bottom_z - m_layers[i]->bottom_z() < region_config.bottom_solid_min_thickness - EPSILON);
|
||||||
|
-- i) {
|
||||||
|
const DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[i];
|
||||||
|
if (! holes.empty())
|
||||||
|
holes = intersection(holes, cache.holes);
|
||||||
|
if (! cache.bottom_surfaces.empty()) {
|
||||||
polygons_append(shell, cache.bottom_surfaces);
|
polygons_append(shell, cache.bottom_surfaces);
|
||||||
// Running the union_ using the Clipper library piece by piece is cheaper
|
// Running the union_ using the Clipper library piece by piece is cheaper
|
||||||
// than running the union_ all at once.
|
// than running the union_ all at once.
|
||||||
if (n_shell_old < shell.size())
|
|
||||||
shell = union_(shell, false);
|
shell = union_(shell, false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||||
{
|
{
|
||||||
Slic3r::SVG svg(debug_out_path("discover_vertical_shells-perimeters-before-union-%d.svg", debug_idx), get_extents(shell));
|
Slic3r::SVG svg(debug_out_path("discover_vertical_shells-perimeters-before-union-%d.svg", debug_idx), get_extents(shell));
|
||||||
|
@ -2280,7 +2311,8 @@ void PrintObject::discover_horizontal_shells()
|
||||||
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
|
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
|
||||||
for (size_t i = 0; i < m_layers.size(); ++ i) {
|
for (size_t i = 0; i < m_layers.size(); ++ i) {
|
||||||
m_print->throw_if_canceled();
|
m_print->throw_if_canceled();
|
||||||
LayerRegion *layerm = m_layers[i]->regions()[region_id];
|
Layer *layer = m_layers[i];
|
||||||
|
LayerRegion *layerm = layer->regions()[region_id];
|
||||||
const PrintRegionConfig ®ion_config = layerm->region()->config();
|
const PrintRegionConfig ®ion_config = layerm->region()->config();
|
||||||
if (region_config.solid_infill_every_layers.value > 0 && region_config.fill_density.value > 0 &&
|
if (region_config.solid_infill_every_layers.value > 0 && region_config.fill_density.value > 0 &&
|
||||||
(i % region_config.solid_infill_every_layers) == 0) {
|
(i % region_config.solid_infill_every_layers) == 0) {
|
||||||
|
@ -2295,6 +2327,8 @@ void PrintObject::discover_horizontal_shells()
|
||||||
if (region_config.ensure_vertical_shell_thickness.value)
|
if (region_config.ensure_vertical_shell_thickness.value)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
coordf_t print_z = layer->print_z;
|
||||||
|
coordf_t bottom_z = layer->bottom_z();
|
||||||
for (size_t idx_surface_type = 0; idx_surface_type < 3; ++ idx_surface_type) {
|
for (size_t idx_surface_type = 0; idx_surface_type < 3; ++ idx_surface_type) {
|
||||||
m_print->throw_if_canceled();
|
m_print->throw_if_canceled();
|
||||||
SurfaceType type = (idx_surface_type == 0) ? stTop : (idx_surface_type == 1) ? stBottom : stBottomBridge;
|
SurfaceType type = (idx_surface_type == 0) ? stTop : (idx_surface_type == 1) ? stBottom : stBottomBridge;
|
||||||
|
@ -2323,10 +2357,15 @@ void PrintObject::discover_horizontal_shells()
|
||||||
continue;
|
continue;
|
||||||
// Slic3r::debugf "Layer %d has %s surfaces\n", $i, ($type == stTop) ? 'top' : 'bottom';
|
// Slic3r::debugf "Layer %d has %s surfaces\n", $i, ($type == stTop) ? 'top' : 'bottom';
|
||||||
|
|
||||||
size_t solid_layers = (type == stTop) ? region_config.top_solid_layers.value : region_config.bottom_solid_layers.value;
|
// Scatter top / bottom regions to other layers. Scattering process is inherently serial, it is difficult to parallelize without locking.
|
||||||
for (int n = (type == stTop) ? i-1 : i+1; std::abs(n - (int)i) < solid_layers; (type == stTop) ? -- n : ++ n) {
|
for (int n = (type == stTop) ? int(i) - 1 : int(i) + 1;
|
||||||
if (n < 0 || n >= int(m_layers.size()))
|
(type == stTop) ?
|
||||||
continue;
|
(n >= 0 && (int(i) - n < region_config.top_solid_layers.value ||
|
||||||
|
print_z - m_layers[n]->print_z < region_config.top_solid_min_thickness.value - EPSILON)) :
|
||||||
|
(n < int(m_layers.size()) && (n - int(i) < region_config.bottom_solid_layers.value ||
|
||||||
|
m_layers[n]->bottom_z() - bottom_z < region_config.bottom_solid_min_thickness.value - EPSILON));
|
||||||
|
(type == stTop) ? -- n : ++ n)
|
||||||
|
{
|
||||||
// Slic3r::debugf " looking for neighbors on layer %d...\n", $n;
|
// Slic3r::debugf " looking for neighbors on layer %d...\n", $n;
|
||||||
// Reference to the lower layer of a TOP surface, or an upper layer of a BOTTOM surface.
|
// Reference to the lower layer of a TOP surface, or an upper layer of a BOTTOM surface.
|
||||||
LayerRegion *neighbor_layerm = m_layers[n]->regions()[region_id];
|
LayerRegion *neighbor_layerm = m_layers[n]->regions()[region_id];
|
||||||
|
|
|
@ -41,6 +41,23 @@ inline coordf_t max_layer_height_from_nozzle(const PrintConfig &print_config, in
|
||||||
return std::max(min_layer_height, (max_layer_height == 0.) ? (0.75 * nozzle_dmr) : max_layer_height);
|
return std::max(min_layer_height, (max_layer_height == 0.) ? (0.75 * nozzle_dmr) : max_layer_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Minimum layer height for the variable layer height algorithm.
|
||||||
|
coordf_t Slicing::min_layer_height_from_nozzle(const DynamicPrintConfig &print_config, int idx_nozzle)
|
||||||
|
{
|
||||||
|
coordf_t min_layer_height = print_config.opt_float("min_layer_height", idx_nozzle - 1);
|
||||||
|
return (min_layer_height == 0.) ? MIN_LAYER_HEIGHT_DEFAULT : std::max(MIN_LAYER_HEIGHT, min_layer_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maximum layer height for the variable layer height algorithm, 3/4 of a nozzle dimaeter by default,
|
||||||
|
// it should not be smaller than the minimum layer height.
|
||||||
|
coordf_t Slicing::max_layer_height_from_nozzle(const DynamicPrintConfig &print_config, int idx_nozzle)
|
||||||
|
{
|
||||||
|
coordf_t min_layer_height = min_layer_height_from_nozzle(print_config, idx_nozzle);
|
||||||
|
coordf_t max_layer_height = print_config.opt_float("max_layer_height", idx_nozzle - 1);
|
||||||
|
coordf_t nozzle_dmr = print_config.opt_float("nozzle_diameter", idx_nozzle - 1);
|
||||||
|
return std::max(min_layer_height, (max_layer_height == 0.) ? (0.75 * nozzle_dmr) : max_layer_height);
|
||||||
|
}
|
||||||
|
|
||||||
SlicingParameters SlicingParameters::create_from_config(
|
SlicingParameters SlicingParameters::create_from_config(
|
||||||
const PrintConfig &print_config,
|
const PrintConfig &print_config,
|
||||||
const PrintObjectConfig &object_config,
|
const PrintObjectConfig &object_config,
|
||||||
|
|
|
@ -99,7 +99,6 @@ struct SlicingParameters
|
||||||
};
|
};
|
||||||
static_assert(IsTriviallyCopyable<SlicingParameters>::value, "SlicingParameters class is not POD (and it should be - see constructor).");
|
static_assert(IsTriviallyCopyable<SlicingParameters>::value, "SlicingParameters class is not POD (and it should be - see constructor).");
|
||||||
|
|
||||||
|
|
||||||
// The two slicing parameters lead to the same layering as long as the variable layer thickness is not in action.
|
// The two slicing parameters lead to the same layering as long as the variable layer thickness is not in action.
|
||||||
inline bool equal_layering(const SlicingParameters &sp1, const SlicingParameters &sp2)
|
inline bool equal_layering(const SlicingParameters &sp1, const SlicingParameters &sp2)
|
||||||
{
|
{
|
||||||
|
@ -183,7 +182,17 @@ extern int generate_layer_height_texture(
|
||||||
const std::vector<coordf_t> &layers,
|
const std::vector<coordf_t> &layers,
|
||||||
void *data, int rows, int cols, bool level_of_detail_2nd_level);
|
void *data, int rows, int cols, bool level_of_detail_2nd_level);
|
||||||
|
|
||||||
}; // namespace Slic3r
|
namespace Slicing {
|
||||||
|
// Minimum layer height for the variable layer height algorithm. Nozzle index is 1 based.
|
||||||
|
coordf_t min_layer_height_from_nozzle(const DynamicPrintConfig &print_config, int idx_nozzle);
|
||||||
|
|
||||||
|
// Maximum layer height for the variable layer height algorithm, 3/4 of a nozzle dimaeter by default,
|
||||||
|
// it should not be smaller than the minimum layer height.
|
||||||
|
// Nozzle index is 1 based.
|
||||||
|
coordf_t max_layer_height_from_nozzle(const DynamicPrintConfig &print_config, int idx_nozzle);
|
||||||
|
} // namespace Slicing
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
namespace cereal
|
namespace cereal
|
||||||
{
|
{
|
||||||
|
|
|
@ -233,22 +233,27 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
|
||||||
"solid_infill_every_layers", "solid_infill_below_area", "infill_extruder" })
|
"solid_infill_every_layers", "solid_infill_below_area", "infill_extruder" })
|
||||||
toggle_field(el, have_infill);
|
toggle_field(el, have_infill);
|
||||||
|
|
||||||
bool have_solid_infill = config->opt_int("top_solid_layers") > 0 || config->opt_int("bottom_solid_layers") > 0;
|
bool has_spiral_vase = config->opt_bool("spiral_vase");
|
||||||
|
bool has_top_solid_infill = config->opt_int("top_solid_layers") > 0;
|
||||||
|
bool has_bottom_solid_infill = config->opt_int("bottom_solid_layers") > 0;
|
||||||
|
bool has_solid_infill = has_top_solid_infill || has_bottom_solid_infill;
|
||||||
// solid_infill_extruder uses the same logic as in Print::extruders()
|
// solid_infill_extruder uses the same logic as in Print::extruders()
|
||||||
for (auto el : { "top_fill_pattern", "bottom_fill_pattern", "infill_first", "solid_infill_extruder",
|
for (auto el : { "top_fill_pattern", "bottom_fill_pattern", "infill_first", "solid_infill_extruder",
|
||||||
"solid_infill_extrusion_width", "solid_infill_speed" })
|
"solid_infill_extrusion_width", "solid_infill_speed" })
|
||||||
toggle_field(el, have_solid_infill);
|
toggle_field(el, has_solid_infill);
|
||||||
|
|
||||||
for (auto el : { "fill_angle", "bridge_angle", "infill_extrusion_width",
|
for (auto el : { "fill_angle", "bridge_angle", "infill_extrusion_width",
|
||||||
"infill_speed", "bridge_speed" })
|
"infill_speed", "bridge_speed" })
|
||||||
toggle_field(el, have_infill || have_solid_infill);
|
toggle_field(el, have_infill || has_solid_infill);
|
||||||
|
|
||||||
|
toggle_field("top_solid_min_thickness", ! has_spiral_vase && has_top_solid_infill);
|
||||||
|
toggle_field("bottom_solid_min_thickness", ! has_spiral_vase && has_bottom_solid_infill);
|
||||||
|
|
||||||
// Gap fill is newly allowed in between perimeter lines even for empty infill (see GH #1476).
|
// Gap fill is newly allowed in between perimeter lines even for empty infill (see GH #1476).
|
||||||
toggle_field("gap_fill_speed", have_perimeters);
|
toggle_field("gap_fill_speed", have_perimeters);
|
||||||
|
|
||||||
bool have_top_solid_infill = config->opt_int("top_solid_layers") > 0;
|
|
||||||
for (auto el : { "top_infill_extrusion_width", "top_solid_infill_speed" })
|
for (auto el : { "top_infill_extrusion_width", "top_solid_infill_speed" })
|
||||||
toggle_field(el, have_top_solid_infill);
|
toggle_field(el, has_top_solid_infill);
|
||||||
|
|
||||||
bool have_default_acceleration = config->opt_float("default_acceleration") > 0;
|
bool have_default_acceleration = config->opt_float("default_acceleration") > 0;
|
||||||
for (auto el : { "perimeter_acceleration", "infill_acceleration",
|
for (auto el : { "perimeter_acceleration", "infill_acceleration",
|
||||||
|
|
|
@ -1980,7 +1980,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||||
"extruder_colour", "filament_colour", "max_print_height", "printer_model", "printer_technology",
|
"extruder_colour", "filament_colour", "max_print_height", "printer_model", "printer_technology",
|
||||||
// These values are necessary to construct SlicingParameters by the Canvas3D variable layer height editor.
|
// These values are necessary to construct SlicingParameters by the Canvas3D variable layer height editor.
|
||||||
"layer_height", "first_layer_height", "min_layer_height", "max_layer_height",
|
"layer_height", "first_layer_height", "min_layer_height", "max_layer_height",
|
||||||
"brim_width", "perimeters", "perimeter_extruder", "fill_density", "infill_extruder", "top_solid_layers", "bottom_solid_layers", "solid_infill_extruder",
|
"brim_width", "perimeters", "perimeter_extruder", "fill_density", "infill_extruder", "top_solid_layers",
|
||||||
"support_material", "support_material_extruder", "support_material_interface_extruder", "support_material_contact_distance", "raft_layers"
|
"support_material", "support_material_extruder", "support_material_interface_extruder", "support_material_contact_distance", "raft_layers"
|
||||||
}))
|
}))
|
||||||
, sidebar(new Sidebar(q))
|
, sidebar(new Sidebar(q))
|
||||||
|
|
|
@ -386,7 +386,8 @@ void Preset::set_visible_from_appconfig(const AppConfig &app_config)
|
||||||
const std::vector<std::string>& Preset::print_options()
|
const std::vector<std::string>& Preset::print_options()
|
||||||
{
|
{
|
||||||
static std::vector<std::string> s_opts {
|
static std::vector<std::string> s_opts {
|
||||||
"layer_height", "first_layer_height", "perimeters", "spiral_vase", "slice_closing_radius", "top_solid_layers", "bottom_solid_layers",
|
"layer_height", "first_layer_height", "perimeters", "spiral_vase", "slice_closing_radius",
|
||||||
|
"top_solid_layers", "top_solid_min_thickness", "bottom_solid_layers", "bottom_solid_min_thickness",
|
||||||
"extra_perimeters", "ensure_vertical_shell_thickness", "avoid_crossing_perimeters", "thin_walls", "overhangs",
|
"extra_perimeters", "ensure_vertical_shell_thickness", "avoid_crossing_perimeters", "thin_walls", "overhangs",
|
||||||
"seam_position", "external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern",
|
"seam_position", "external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern",
|
||||||
"infill_every_layers", "infill_only_where_needed", "solid_infill_every_layers", "fill_angle", "bridge_angle",
|
"infill_every_layers", "infill_only_where_needed", "solid_infill_every_layers", "fill_angle", "bridge_angle",
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include "libslic3r/Flow.hpp"
|
#include "libslic3r/Flow.hpp"
|
||||||
|
#include "libslic3r/Slicing.hpp"
|
||||||
#include "libslic3r/libslic3r.h"
|
#include "libslic3r/libslic3r.h"
|
||||||
|
|
||||||
#include "PresetBundle.hpp"
|
#include "PresetBundle.hpp"
|
||||||
|
@ -242,7 +243,7 @@ std::string PresetHints::recommended_thin_wall_thickness(const PresetBundle &pre
|
||||||
float nozzle_diameter = float(printer_config.opt_float("nozzle_diameter", 0));
|
float nozzle_diameter = float(printer_config.opt_float("nozzle_diameter", 0));
|
||||||
|
|
||||||
std::string out;
|
std::string out;
|
||||||
if (layer_height <= 0.f){
|
if (layer_height <= 0.f) {
|
||||||
out += _utf8(L("Recommended object thin wall thickness: Not available due to invalid layer height."));
|
out += _utf8(L("Recommended object thin wall thickness: Not available due to invalid layer height."));
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
@ -272,4 +273,70 @@ std::string PresetHints::recommended_thin_wall_thickness(const PresetBundle &pre
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Produce a textual explanation of the combined effects of the top/bottom_solid_layers
|
||||||
|
// versus top/bottom_min_shell_thickness. Which of the two values wins depends
|
||||||
|
// on the active layer height.
|
||||||
|
std::string PresetHints::top_bottom_shell_thickness_explanation(const PresetBundle &preset_bundle)
|
||||||
|
{
|
||||||
|
const DynamicPrintConfig &print_config = preset_bundle.prints .get_edited_preset().config;
|
||||||
|
const DynamicPrintConfig &printer_config = preset_bundle.printers .get_edited_preset().config;
|
||||||
|
|
||||||
|
std::string out;
|
||||||
|
|
||||||
|
int top_solid_layers = print_config.opt_int("top_solid_layers");
|
||||||
|
int bottom_solid_layers = print_config.opt_int("bottom_solid_layers");
|
||||||
|
bool has_top_layers = top_solid_layers > 0;
|
||||||
|
bool has_bottom_layers = bottom_solid_layers > 0;
|
||||||
|
bool has_shell = has_top_layers && has_bottom_layers;
|
||||||
|
double top_solid_min_thickness = print_config.opt_float("top_solid_min_thickness");
|
||||||
|
double bottom_solid_min_thickness = print_config.opt_float("bottom_solid_min_thickness");
|
||||||
|
double layer_height = print_config.opt_float("layer_height");
|
||||||
|
bool variable_layer_height = printer_config.opt_bool("variable_layer_height");
|
||||||
|
//FIXME the following lines take into account the 1st extruder only.
|
||||||
|
double min_layer_height = (has_shell && variable_layer_height) ? Slicing::min_layer_height_from_nozzle(printer_config, 1) : layer_height;
|
||||||
|
double max_layer_height = (has_shell && variable_layer_height) ? Slicing::max_layer_height_from_nozzle(printer_config, 1) : layer_height;
|
||||||
|
|
||||||
|
if (layer_height <= 0.f) {
|
||||||
|
out += _utf8(L("Top / bottom shell thickness hint: Not available due to invalid layer height."));
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_top_layers) {
|
||||||
|
double top_shell_thickness = top_solid_layers * layer_height;
|
||||||
|
if (top_shell_thickness < top_solid_min_thickness) {
|
||||||
|
// top_solid_min_shell_thickness triggers even in case of normal layer height. Round the top_shell_thickness up
|
||||||
|
// to an integer multiply of layer_height.
|
||||||
|
double n = ceil(top_solid_min_thickness / layer_height);
|
||||||
|
top_shell_thickness = n * layer_height;
|
||||||
|
}
|
||||||
|
double top_shell_thickness_minimum = std::max(top_solid_min_thickness, top_solid_layers * min_layer_height);
|
||||||
|
out += (boost::format(_utf8(L("Top shell is %1% mm thick for layer height %2% mm."))) % top_shell_thickness % layer_height).str();
|
||||||
|
if (variable_layer_height && top_shell_thickness_minimum < top_shell_thickness) {
|
||||||
|
out += " ";
|
||||||
|
out += (boost::format(_utf8(L("Minimum top shell thickness is %1% mm."))) % top_shell_thickness_minimum).str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_bottom_layers) {
|
||||||
|
double bottom_shell_thickness = bottom_solid_layers * layer_height;
|
||||||
|
if (bottom_shell_thickness < bottom_solid_min_thickness) {
|
||||||
|
// bottom_solid_min_shell_thickness triggers even in case of normal layer height. Round the bottom_shell_thickness up
|
||||||
|
// to an integer multiply of layer_height.
|
||||||
|
double n = ceil(bottom_solid_min_thickness / layer_height);
|
||||||
|
bottom_shell_thickness = n * layer_height;
|
||||||
|
}
|
||||||
|
double bottom_shell_thickness_minimum = std::max(bottom_solid_min_thickness, bottom_solid_layers * min_layer_height);
|
||||||
|
if (! out.empty())
|
||||||
|
out += "\n";
|
||||||
|
out += (boost::format(_utf8(L("Bottom shell is %1% mm thick for layer height %2% mm."))) % bottom_shell_thickness % layer_height).str();
|
||||||
|
if (variable_layer_height && bottom_shell_thickness_minimum < bottom_shell_thickness) {
|
||||||
|
out += " ";
|
||||||
|
out += (boost::format(_utf8(L("Minimum bottom shell thickness is %1% mm."))) % bottom_shell_thickness_minimum).str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
}; // namespace Slic3r
|
}; // namespace Slic3r
|
||||||
|
|
|
@ -23,6 +23,11 @@ public:
|
||||||
// Produce a textual description of a recommended thin wall thickness
|
// Produce a textual description of a recommended thin wall thickness
|
||||||
// from the provided number of perimeters and the external / internal perimeter width.
|
// from the provided number of perimeters and the external / internal perimeter width.
|
||||||
static std::string recommended_thin_wall_thickness(const PresetBundle &preset_bundle);
|
static std::string recommended_thin_wall_thickness(const PresetBundle &preset_bundle);
|
||||||
|
|
||||||
|
// Produce a textual explanation of the combined effects of the top/bottom_solid_layers
|
||||||
|
// versus top/bottom_min_shell_thickness. Which of the two values wins depends
|
||||||
|
// on the active layer height.
|
||||||
|
static std::string top_bottom_shell_thickness_explanation(const PresetBundle &preset_bundle);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
|
@ -1056,6 +1056,16 @@ void TabPrint::build()
|
||||||
line.append_option(optgroup->get_option("top_solid_layers"));
|
line.append_option(optgroup->get_option("top_solid_layers"));
|
||||||
line.append_option(optgroup->get_option("bottom_solid_layers"));
|
line.append_option(optgroup->get_option("bottom_solid_layers"));
|
||||||
optgroup->append_line(line);
|
optgroup->append_line(line);
|
||||||
|
line = { _(L("Minimum shell thickness")), "" };
|
||||||
|
line.append_option(optgroup->get_option("top_solid_min_thickness"));
|
||||||
|
line.append_option(optgroup->get_option("bottom_solid_min_thickness"));
|
||||||
|
optgroup->append_line(line);
|
||||||
|
line = { "", "" };
|
||||||
|
line.full_width = 1;
|
||||||
|
line.widget = [this](wxWindow* parent) {
|
||||||
|
return description_line_widget(parent, &m_top_bottom_shell_thickness_explanation);
|
||||||
|
};
|
||||||
|
optgroup->append_line(line);
|
||||||
|
|
||||||
optgroup = page->new_optgroup(_(L("Quality (slower slicing)")));
|
optgroup = page->new_optgroup(_(L("Quality (slower slicing)")));
|
||||||
optgroup->append_single_option_line("extra_perimeters");
|
optgroup->append_single_option_line("extra_perimeters");
|
||||||
|
@ -1277,6 +1287,8 @@ void TabPrint::update()
|
||||||
|
|
||||||
m_recommended_thin_wall_thickness_description_line->SetText(
|
m_recommended_thin_wall_thickness_description_line->SetText(
|
||||||
from_u8(PresetHints::recommended_thin_wall_thickness(*m_preset_bundle)));
|
from_u8(PresetHints::recommended_thin_wall_thickness(*m_preset_bundle)));
|
||||||
|
m_top_bottom_shell_thickness_explanation->SetText(
|
||||||
|
from_u8(PresetHints::top_bottom_shell_thickness_explanation(*m_preset_bundle)));
|
||||||
Layout();
|
Layout();
|
||||||
|
|
||||||
// Thaw();
|
// Thaw();
|
||||||
|
@ -1295,6 +1307,8 @@ void TabPrint::OnActivate()
|
||||||
{
|
{
|
||||||
m_recommended_thin_wall_thickness_description_line->SetText(
|
m_recommended_thin_wall_thickness_description_line->SetText(
|
||||||
from_u8(PresetHints::recommended_thin_wall_thickness(*m_preset_bundle)));
|
from_u8(PresetHints::recommended_thin_wall_thickness(*m_preset_bundle)));
|
||||||
|
m_top_bottom_shell_thickness_explanation->SetText(
|
||||||
|
from_u8(PresetHints::top_bottom_shell_thickness_explanation(*m_preset_bundle)));
|
||||||
Tab::OnActivate();
|
Tab::OnActivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -327,7 +327,8 @@ public:
|
||||||
Tab(parent, _(L("Print Settings")), Slic3r::Preset::TYPE_PRINT) {}
|
Tab(parent, _(L("Print Settings")), Slic3r::Preset::TYPE_PRINT) {}
|
||||||
~TabPrint() {}
|
~TabPrint() {}
|
||||||
|
|
||||||
ogStaticText* m_recommended_thin_wall_thickness_description_line;
|
ogStaticText* m_recommended_thin_wall_thickness_description_line = nullptr;
|
||||||
|
ogStaticText* m_top_bottom_shell_thickness_explanation = nullptr;
|
||||||
bool m_support_material_overhangs_queried = false;
|
bool m_support_material_overhangs_queried = false;
|
||||||
|
|
||||||
void build() override;
|
void build() override;
|
||||||
|
@ -336,6 +337,7 @@ public:
|
||||||
void OnActivate() override;
|
void OnActivate() override;
|
||||||
bool supports_printer_technology(const PrinterTechnology tech) override { return tech == ptFFF; }
|
bool supports_printer_technology(const PrinterTechnology tech) override { return tech == ptFFF; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class TabFilament : public Tab
|
class TabFilament : public Tab
|
||||||
{
|
{
|
||||||
ogStaticText* m_volumetric_speed_description_line;
|
ogStaticText* m_volumetric_speed_description_line;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue