2017-11-09 09:48:06 +00:00
# include <cassert>
2018-11-26 13:41:58 +00:00
# include "libslic3r/Flow.hpp"
2020-02-05 15:53:26 +00:00
# include "libslic3r/Slicing.hpp"
2018-11-26 13:41:58 +00:00
# include "libslic3r/libslic3r.h"
2017-11-09 09:48:06 +00:00
# include "PresetHints.hpp"
2018-02-22 10:34:41 +00:00
# include <wx/intl.h>
2017-11-09 09:48:06 +00:00
2018-02-22 10:34:41 +00:00
# include "GUI.hpp"
2020-12-04 12:17:18 +00:00
# include "format.hpp"
2018-11-26 13:41:58 +00:00
# include "I18N.hpp"
2017-11-09 09:48:06 +00:00
namespace Slic3r {
2018-03-06 08:44:53 +00:00
# define MIN_BUF_LENGTH 4096
2017-11-09 09:48:06 +00:00
std : : string PresetHints : : cooling_description ( const Preset & preset )
{
std : : string out ;
2019-05-11 21:29:25 +00:00
2020-12-04 10:53:02 +00:00
bool cooling = preset . config . opt_bool ( " cooling " , 0 ) ;
int fan_below_layer_time = preset . config . opt_int ( " fan_below_layer_time " , 0 ) ;
int full_fan_speed_layer = preset . config . opt_int ( " full_fan_speed_layer " , 0 ) ;
if ( cooling ) {
2017-11-09 09:48:06 +00:00
int slowdown_below_layer_time = preset . config . opt_int ( " slowdown_below_layer_time " , 0 ) ;
int min_fan_speed = preset . config . opt_int ( " min_fan_speed " , 0 ) ;
int max_fan_speed = preset . config . opt_int ( " max_fan_speed " , 0 ) ;
int min_print_speed = int ( preset . config . opt_float ( " min_print_speed " , 0 ) + 0.5 ) ;
2019-05-11 21:29:25 +00:00
2020-12-04 10:53:02 +00:00
out + = GUI : : format ( _L ( " If estimated layer time is below ~%1%s, "
" fan will run at %2%%% and print speed will be reduced "
" so that no less than %3%s are spent on that layer "
" (however, speed will never be reduced below %4%mm/s). " ) ,
slowdown_below_layer_time , max_fan_speed , slowdown_below_layer_time , min_print_speed ) ;
if ( fan_below_layer_time > slowdown_below_layer_time )
out + = " \n " +
GUI : : format ( _L ( " If estimated layer time is greater, but still below ~%1%s, "
" fan will run at a proportionally decreasing speed between %2%%% and %3%%%. " ) ,
fan_below_layer_time , max_fan_speed , min_fan_speed ) ;
out + = " \n " ;
2017-11-09 09:48:06 +00:00
}
if ( preset . config . opt_bool ( " fan_always_on " , 0 ) ) {
int disable_fan_first_layers = preset . config . opt_int ( " disable_fan_first_layers " , 0 ) ;
int min_fan_speed = preset . config . opt_int ( " min_fan_speed " , 0 ) ;
2019-05-11 21:29:25 +00:00
2020-12-04 12:05:25 +00:00
if ( full_fan_speed_layer > disable_fan_first_layers + 1 )
2020-12-04 10:53:02 +00:00
out + = GUI : : format ( _L ( " Fan speed will be ramped from zero at layer %1% to %2%%% at layer %3%. " ) , disable_fan_first_layers , min_fan_speed , full_fan_speed_layer ) ;
else {
out + = GUI : : format ( cooling ? _L ( " During the other layers, fan will always run at %1%%% " ) : _L ( " Fan will always run at %1%%% " ) , min_fan_speed ) + " " ;
if ( disable_fan_first_layers > 1 )
out + = GUI : : format ( _L ( " except for the first %1% layers. " ) , disable_fan_first_layers ) ;
else if ( disable_fan_first_layers = = 1 )
out + = GUI : : format ( _L ( " except for the first layer. " ) ) ;
}
2017-11-09 09:48:06 +00:00
} else
2020-12-04 10:53:02 +00:00
out + = cooling ? _u8L ( " During the other layers, fan will be turned off. " ) : _u8L ( " Fan will be turned off. " ) ;
2017-11-09 09:48:06 +00:00
return out ;
}
2017-11-09 14:10:20 +00:00
static const ConfigOptionFloatOrPercent & first_positive ( const ConfigOptionFloatOrPercent * v1 , const ConfigOptionFloatOrPercent & v2 , const ConfigOptionFloatOrPercent & v3 )
{
return ( v1 ! = nullptr & & v1 - > value > 0 ) ? * v1 : ( ( v2 . value > 0 ) ? v2 : v3 ) ;
}
2017-11-09 09:48:06 +00:00
std : : string PresetHints : : maximum_volumetric_flow_description ( const PresetBundle & preset_bundle )
{
// Find out, to which nozzle index is the current filament profile assigned.
2017-11-09 14:10:20 +00:00
int idx_extruder = 0 ;
int num_extruders = ( int ) preset_bundle . filament_presets . size ( ) ;
for ( ; idx_extruder < num_extruders ; + + idx_extruder )
2019-05-22 09:31:36 +00:00
if ( preset_bundle . filament_presets [ idx_extruder ] = = preset_bundle . filaments . get_selected_preset_name ( ) )
2017-11-09 09:48:06 +00:00
break ;
2017-11-09 14:10:20 +00:00
if ( idx_extruder = = num_extruders )
2017-11-09 09:48:06 +00:00
// The current filament preset is not active for any extruder.
2017-11-09 14:10:20 +00:00
idx_extruder = - 1 ;
2017-11-09 09:48:06 +00:00
const DynamicPrintConfig & print_config = preset_bundle . prints . get_edited_preset ( ) . config ;
const DynamicPrintConfig & filament_config = preset_bundle . filaments . get_edited_preset ( ) . config ;
const DynamicPrintConfig & printer_config = preset_bundle . printers . get_edited_preset ( ) . config ;
// Current printer values.
2017-11-09 14:10:20 +00:00
float nozzle_diameter = ( float ) printer_config . opt_float ( " nozzle_diameter " , idx_extruder ) ;
2017-11-09 09:48:06 +00:00
// Print config values
2017-11-09 14:10:20 +00:00
double layer_height = print_config . opt_float ( " layer_height " ) ;
2017-11-09 09:48:06 +00:00
double first_layer_height = print_config . get_abs_value ( " first_layer_height " , layer_height ) ;
double support_material_speed = print_config . opt_float ( " support_material_speed " ) ;
double support_material_interface_speed = print_config . get_abs_value ( " support_material_interface_speed " , support_material_speed ) ;
double bridge_speed = print_config . opt_float ( " bridge_speed " ) ;
double bridge_flow_ratio = print_config . opt_float ( " bridge_flow_ratio " ) ;
double perimeter_speed = print_config . opt_float ( " perimeter_speed " ) ;
double external_perimeter_speed = print_config . get_abs_value ( " external_perimeter_speed " , perimeter_speed ) ;
2021-02-10 16:28:56 +00:00
// double gap_fill_speed = print_config.opt_bool("gap_fill_enabled") ? print_config.opt_float("gap_fill_speed") : 0.;
2017-11-09 09:48:06 +00:00
double infill_speed = print_config . opt_float ( " infill_speed " ) ;
double small_perimeter_speed = print_config . get_abs_value ( " small_perimeter_speed " , perimeter_speed ) ;
double solid_infill_speed = print_config . get_abs_value ( " solid_infill_speed " , infill_speed ) ;
double top_solid_infill_speed = print_config . get_abs_value ( " top_solid_infill_speed " , solid_infill_speed ) ;
// Maximum print speed when auto-speed is enabled by setting any of the above speed values to zero.
double max_print_speed = print_config . opt_float ( " max_print_speed " ) ;
// Maximum volumetric speed allowed for the print profile.
double max_volumetric_speed = print_config . opt_float ( " max_volumetric_speed " ) ;
2017-11-09 14:10:20 +00:00
const auto & extrusion_width = * print_config . option < ConfigOptionFloatOrPercent > ( " extrusion_width " ) ;
2017-11-09 09:48:06 +00:00
const auto & external_perimeter_extrusion_width = * print_config . option < ConfigOptionFloatOrPercent > ( " external_perimeter_extrusion_width " ) ;
2017-11-09 14:10:20 +00:00
const auto & first_layer_extrusion_width = * print_config . option < ConfigOptionFloatOrPercent > ( " first_layer_extrusion_width " ) ;
2017-11-09 09:48:06 +00:00
const auto & infill_extrusion_width = * print_config . option < ConfigOptionFloatOrPercent > ( " infill_extrusion_width " ) ;
const auto & perimeter_extrusion_width = * print_config . option < ConfigOptionFloatOrPercent > ( " perimeter_extrusion_width " ) ;
2017-11-09 14:10:20 +00:00
const auto & solid_infill_extrusion_width = * print_config . option < ConfigOptionFloatOrPercent > ( " solid_infill_extrusion_width " ) ;
const auto & support_material_extrusion_width = * print_config . option < ConfigOptionFloatOrPercent > ( " support_material_extrusion_width " ) ;
2017-11-09 09:48:06 +00:00
const auto & top_infill_extrusion_width = * print_config . option < ConfigOptionFloatOrPercent > ( " top_infill_extrusion_width " ) ;
2017-12-20 13:51:18 +00:00
const auto & first_layer_speed = * print_config . option < ConfigOptionFloatOrPercent > ( " first_layer_speed " ) ;
2017-11-09 09:48:06 +00:00
2017-11-09 14:10:20 +00:00
// Index of an extruder assigned to a feature. If set to 0, an active extruder will be used for a multi-material print.
// If different from idx_extruder, it will not be taken into account for this hint.
auto feature_extruder_active = [ idx_extruder , num_extruders ] ( int i ) {
return i < = 0 | | i > num_extruders | | idx_extruder = = - 1 | | idx_extruder = = i - 1 ;
} ;
bool perimeter_extruder_active = feature_extruder_active ( print_config . opt_int ( " perimeter_extruder " ) ) ;
bool infill_extruder_active = feature_extruder_active ( print_config . opt_int ( " infill_extruder " ) ) ;
bool solid_infill_extruder_active = feature_extruder_active ( print_config . opt_int ( " solid_infill_extruder " ) ) ;
bool support_material_extruder_active = feature_extruder_active ( print_config . opt_int ( " support_material_extruder " ) ) ;
bool support_material_interface_extruder_active = feature_extruder_active ( print_config . opt_int ( " support_material_interface_extruder " ) ) ;
2017-11-09 09:48:06 +00:00
// Current filament values
double filament_diameter = filament_config . opt_float ( " filament_diameter " , 0 ) ;
2017-11-09 14:10:20 +00:00
double filament_crossection = M_PI * 0.25 * filament_diameter * filament_diameter ;
2019-09-03 08:27:16 +00:00
// double extrusion_multiplier = filament_config.opt_float("extrusion_multiplier", 0);
2017-11-09 14:10:20 +00:00
// The following value will be annotated by this hint, so it does not take part in the calculation.
// double filament_max_volumetric_speed = filament_config.opt_float("filament_max_volumetric_speed", 0);
2017-11-09 09:48:06 +00:00
std : : string out ;
2017-11-09 14:10:20 +00:00
for ( size_t idx_type = ( first_layer_extrusion_width . value = = 0 ) ? 1 : 0 ; idx_type < 3 ; + + idx_type ) {
// First test the maximum volumetric extrusion speed for non-bridging extrusions.
bool first_layer = idx_type = = 0 ;
bool bridging = idx_type = = 2 ;
const ConfigOptionFloatOrPercent * first_layer_extrusion_width_ptr = ( first_layer & & first_layer_extrusion_width . value > 0 ) ?
& first_layer_extrusion_width : nullptr ;
const float lh = float ( first_layer ? first_layer_height : layer_height ) ;
const float bfr = bridging ? bridge_flow_ratio : 0.f ;
double max_flow = 0. ;
std : : string max_flow_extrusion_type ;
2017-12-20 13:51:18 +00:00
auto limit_by_first_layer_speed = [ & first_layer_speed , first_layer ] ( double speed_normal , double speed_max ) {
if ( first_layer & & first_layer_speed . value > 0 )
// Apply the first layer limit.
speed_normal = first_layer_speed . get_abs_value ( speed_normal ) ;
return ( speed_normal > 0. ) ? speed_normal : speed_max ;
} ;
2017-11-09 14:10:20 +00:00
if ( perimeter_extruder_active ) {
double external_perimeter_rate = Flow : : new_from_config_width ( frExternalPerimeter ,
first_positive ( first_layer_extrusion_width_ptr , external_perimeter_extrusion_width , extrusion_width ) ,
nozzle_diameter , lh , bfr ) . mm3_per_mm ( ) *
( bridging ? bridge_speed :
2017-12-20 13:51:18 +00:00
limit_by_first_layer_speed ( std : : max ( external_perimeter_speed , small_perimeter_speed ) , max_print_speed ) ) ;
2017-11-09 14:10:20 +00:00
if ( max_flow < external_perimeter_rate ) {
max_flow = external_perimeter_rate ;
2019-05-11 21:29:25 +00:00
max_flow_extrusion_type = _utf8 ( L ( " external perimeters " ) ) ;
2017-11-09 14:10:20 +00:00
}
double perimeter_rate = Flow : : new_from_config_width ( frPerimeter ,
first_positive ( first_layer_extrusion_width_ptr , perimeter_extrusion_width , extrusion_width ) ,
nozzle_diameter , lh , bfr ) . mm3_per_mm ( ) *
( bridging ? bridge_speed :
2017-12-20 13:51:18 +00:00
limit_by_first_layer_speed ( std : : max ( perimeter_speed , small_perimeter_speed ) , max_print_speed ) ) ;
2017-11-09 14:10:20 +00:00
if ( max_flow < perimeter_rate ) {
max_flow = perimeter_rate ;
2019-05-11 21:29:25 +00:00
max_flow_extrusion_type = _utf8 ( L ( " perimeters " ) ) ;
2017-11-09 14:10:20 +00:00
}
}
if ( ! bridging & & infill_extruder_active ) {
double infill_rate = Flow : : new_from_config_width ( frInfill ,
first_positive ( first_layer_extrusion_width_ptr , infill_extrusion_width , extrusion_width ) ,
2017-12-20 13:51:18 +00:00
nozzle_diameter , lh , bfr ) . mm3_per_mm ( ) * limit_by_first_layer_speed ( infill_speed , max_print_speed ) ;
2017-11-09 14:10:20 +00:00
if ( max_flow < infill_rate ) {
max_flow = infill_rate ;
2019-05-11 21:29:25 +00:00
max_flow_extrusion_type = _utf8 ( L ( " infill " ) ) ;
2017-11-09 14:10:20 +00:00
}
}
if ( solid_infill_extruder_active ) {
double solid_infill_rate = Flow : : new_from_config_width ( frInfill ,
first_positive ( first_layer_extrusion_width_ptr , solid_infill_extrusion_width , extrusion_width ) ,
nozzle_diameter , lh , 0 ) . mm3_per_mm ( ) *
2017-12-20 13:51:18 +00:00
( bridging ? bridge_speed : limit_by_first_layer_speed ( solid_infill_speed , max_print_speed ) ) ;
2017-11-09 14:10:20 +00:00
if ( max_flow < solid_infill_rate ) {
max_flow = solid_infill_rate ;
2019-05-11 21:29:25 +00:00
max_flow_extrusion_type = _utf8 ( L ( " solid infill " ) ) ;
2017-11-09 14:10:20 +00:00
}
if ( ! bridging ) {
double top_solid_infill_rate = Flow : : new_from_config_width ( frInfill ,
first_positive ( first_layer_extrusion_width_ptr , top_infill_extrusion_width , extrusion_width ) ,
2017-12-20 13:51:18 +00:00
nozzle_diameter , lh , bfr ) . mm3_per_mm ( ) * limit_by_first_layer_speed ( top_solid_infill_speed , max_print_speed ) ;
2017-11-09 14:10:20 +00:00
if ( max_flow < top_solid_infill_rate ) {
max_flow = top_solid_infill_rate ;
2019-05-11 21:29:25 +00:00
max_flow_extrusion_type = _utf8 ( L ( " top solid infill " ) ) ;
2017-11-09 14:10:20 +00:00
}
}
}
if ( support_material_extruder_active ) {
double support_material_rate = Flow : : new_from_config_width ( frSupportMaterial ,
first_positive ( first_layer_extrusion_width_ptr , support_material_extrusion_width , extrusion_width ) ,
nozzle_diameter , lh , bfr ) . mm3_per_mm ( ) *
2017-12-20 13:51:18 +00:00
( bridging ? bridge_speed : limit_by_first_layer_speed ( support_material_speed , max_print_speed ) ) ;
2017-11-09 14:10:20 +00:00
if ( max_flow < support_material_rate ) {
max_flow = support_material_rate ;
2019-05-11 21:29:25 +00:00
max_flow_extrusion_type = _utf8 ( L ( " support " ) ) ;
2017-11-09 14:10:20 +00:00
}
}
if ( support_material_interface_extruder_active ) {
double support_material_interface_rate = Flow : : new_from_config_width ( frSupportMaterialInterface ,
first_positive ( first_layer_extrusion_width_ptr , support_material_extrusion_width , extrusion_width ) ,
nozzle_diameter , lh , bfr ) . mm3_per_mm ( ) *
2017-12-20 13:51:18 +00:00
( bridging ? bridge_speed : limit_by_first_layer_speed ( support_material_interface_speed , max_print_speed ) ) ;
2017-11-09 14:10:20 +00:00
if ( max_flow < support_material_interface_rate ) {
max_flow = support_material_interface_rate ;
2019-05-11 21:29:25 +00:00
max_flow_extrusion_type = _utf8 ( L ( " support interface " ) ) ;
2017-11-09 14:10:20 +00:00
}
2017-11-09 09:48:06 +00:00
}
2017-11-09 14:10:20 +00:00
//FIXME handle gap_fill_speed
if ( ! out . empty ( ) )
out + = " \n " ;
2019-05-11 21:29:25 +00:00
out + = ( first_layer ? _utf8 ( L ( " First layer volumetric " ) ) : ( bridging ? _utf8 ( L ( " Bridging volumetric " ) ) : _utf8 ( L ( " Volumetric " ) ) ) ) ;
out + = " " + _utf8 ( L ( " flow rate is maximized " ) ) + " " ;
2017-12-20 13:51:18 +00:00
bool limited_by_max_volumetric_speed = max_volumetric_speed > 0 & & max_volumetric_speed < max_flow ;
out + = ( limited_by_max_volumetric_speed ?
2019-05-11 21:29:25 +00:00
_utf8 ( L ( " by the print profile maximum " ) ) :
( _utf8 ( L ( " when printing " ) ) + " " + max_flow_extrusion_type ) )
+ " " + _utf8 ( L ( " with a volumetric rate " ) ) + " " ;
2017-12-20 13:51:18 +00:00
if ( limited_by_max_volumetric_speed )
2017-11-09 14:10:20 +00:00
max_flow = max_volumetric_speed ;
2019-05-11 21:29:25 +00:00
out + = ( boost : : format ( _utf8 ( L ( " %3.2f mm³/s at filament speed %3.2f mm/s. " ) ) ) % max_flow % ( max_flow / filament_crossection ) ) . str ( ) ;
2017-11-09 14:10:20 +00:00
}
2017-11-09 09:48:06 +00:00
2017-11-09 14:10:20 +00:00
return out ;
2017-11-09 09:48:06 +00:00
}
2018-01-04 14:38:06 +00:00
std : : string PresetHints : : recommended_thin_wall_thickness ( 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 ;
float layer_height = float ( print_config . opt_float ( " layer_height " ) ) ;
int num_perimeters = print_config . opt_int ( " perimeters " ) ;
bool thin_walls = print_config . opt_bool ( " thin_walls " ) ;
float nozzle_diameter = float ( printer_config . opt_float ( " nozzle_diameter " , 0 ) ) ;
2018-02-22 10:34:41 +00:00
std : : string out ;
2020-02-05 15:53:26 +00:00
if ( layer_height < = 0.f ) {
2019-05-11 21:29:25 +00:00
out + = _utf8 ( L ( " Recommended object thin wall thickness: Not available due to invalid layer height. " ) ) ;
2018-02-22 10:34:41 +00:00
return out ;
}
2018-02-12 14:37:42 +00:00
2018-01-04 14:38:06 +00:00
Flow external_perimeter_flow = Flow : : new_from_config_width (
frExternalPerimeter ,
* print_config . opt < ConfigOptionFloatOrPercent > ( " external_perimeter_extrusion_width " ) ,
nozzle_diameter , layer_height , false ) ;
Flow perimeter_flow = Flow : : new_from_config_width (
frPerimeter ,
* print_config . opt < ConfigOptionFloatOrPercent > ( " perimeter_extrusion_width " ) ,
nozzle_diameter , layer_height , false ) ;
2018-02-22 10:34:41 +00:00
2018-01-04 14:38:06 +00:00
if ( num_perimeters > 0 ) {
int num_lines = std : : min ( num_perimeters * 2 , 10 ) ;
2019-05-11 21:29:25 +00:00
out + = ( boost : : format ( _utf8 ( L ( " Recommended object thin wall thickness for layer height %.2f and " ) ) ) % layer_height ) . str ( ) + " " ;
2018-01-04 14:38:06 +00:00
// Start with the width of two closely spaced
2020-02-18 11:26:48 +00:00
try {
double width = external_perimeter_flow . width + external_perimeter_flow . spacing ( ) ;
for ( int i = 2 ; i < = num_lines ; thin_walls ? + + i : i + = 2 ) {
if ( i > 2 )
out + = " , " ;
out + = ( boost : : format ( _utf8 ( L ( " %d lines: %.2f mm " ) ) ) % i % width ) . str ( ) + " " ;
width + = perimeter_flow . spacing ( ) * ( thin_walls ? 1.f : 2.f ) ;
}
} catch ( const FlowErrorNegativeSpacing & ) {
out = _utf8 ( L ( " Recommended object thin wall thickness: Not available due to excessively small extrusion width. " ) ) ;
2018-01-04 14:38:06 +00:00
}
}
return out ;
}
2020-02-05 15:53:26 +00:00
// 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 ;
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 " ) ;
2020-04-22 10:49:52 +00:00
//FIXME the following line takes into account the 1st extruder only.
2020-02-06 10:00:27 +00:00
double min_layer_height = variable_layer_height ? Slicing : : min_layer_height_from_nozzle ( printer_config , 1 ) : layer_height ;
2020-02-05 15:53:26 +00:00
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 ( ) ;
}
2020-02-06 10:00:27 +00:00
} else
out + = _utf8 ( L ( " Top is open. " ) ) ;
out + = " \n " ;
2020-02-05 15:53:26 +00:00
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 ) ;
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 ( ) ;
}
2020-02-06 10:00:27 +00:00
} else
out + = _utf8 ( L ( " Bottom is open. " ) ) ;
2020-02-05 15:53:26 +00:00
return out ;
}
2017-11-09 09:48:06 +00:00
} ; // namespace Slic3r