2014-01-05 13:16:13 +01:00
#include "Flow.hpp"
2017-05-03 18:28:22 +02:00
#include "Print.hpp"
2014-01-05 13:16:13 +01:00
#include <cmath>
2015-12-11 21:36:51 +01:00
#include <assert.h>
2014-01-05 13:16:13 +01:00
namespace Slic3r {
2017-07-19 15:53:43 +02:00
// This static method returns a sane extrusion width default.
static inline float auto_extrusion_width ( FlowRole role , float nozzle_diameter , float height )
{
switch ( role ) {
case frSupportMaterial :
case frSupportMaterialInterface :
case frTopSolidInfill :
return nozzle_diameter ;
default :
case frExternalPerimeter :
case frPerimeter :
case frSolidInfill :
case frInfill :
2017-07-20 11:03:54 +02:00
return 1.125f * nozzle_diameter ;
2017-07-19 15:53:43 +02:00
}
}
// This constructor builds a Flow object from an extrusion width config setting
// and other context properties.
Flow Flow :: new_from_config_width ( FlowRole role , const ConfigOptionFloatOrPercent & width , float nozzle_diameter , float height , float bridge_flow_ratio )
{
2014-04-05 10:54:24 +02:00
// we need layer height unless it's a bridge
2017-07-19 15:53:43 +02:00
if ( height <= 0 && bridge_flow_ratio == 0 )
2018-09-18 10:09:58 +02:00
throw std :: invalid_argument ( "Invalid flow height supplied to new_from_config_width()" );
2017-07-19 15:53:43 +02:00
2014-01-05 13:16:13 +01:00
float w ;
2014-06-12 01:00:13 +02:00
if ( bridge_flow_ratio > 0 ) {
2017-07-19 15:53:43 +02:00
// If bridge flow was requested, calculate the bridge width.
height = w = ( bridge_flow_ratio == 1. ) ?
// optimization to avoid sqrt()
nozzle_diameter :
sqrt ( bridge_flow_ratio ) * nozzle_diameter ;
} else if ( ! width . percent && width . value == 0. ) {
// If user left option to 0, calculate a sane default width.
w = auto_extrusion_width ( role , nozzle_diameter , height );
2014-01-05 13:16:13 +01:00
} else {
2017-07-19 15:53:43 +02:00
// If user set a manual value, use it.
2017-07-19 16:06:29 +02:00
w = float ( width . get_abs_value ( height ));
2014-01-05 13:16:13 +01:00
}
2014-06-12 01:00:13 +02:00
return Flow ( w , height , nozzle_diameter , bridge_flow_ratio > 0 );
2014-01-05 13:16:13 +01:00
}
2017-07-19 15:53:43 +02:00
// This constructor builds a Flow object from a given centerline spacing.
Flow Flow :: new_from_spacing ( float spacing , float nozzle_diameter , float height , bool bridge )
{
2014-04-05 10:54:24 +02:00
// we need layer height unless it's a bridge
2017-07-19 15:53:43 +02:00
if ( height <= 0 && ! bridge )
2018-09-18 10:09:58 +02:00
throw std :: invalid_argument ( "Invalid flow height supplied to new_from_spacing()" );
2017-07-19 15:53:43 +02:00
// Calculate width from spacing.
// For normal extrusons, extrusion width is wider than the spacing due to the rounding and squishing of the extrusions.
// For bridge extrusions, the extrusions are placed with a tiny BRIDGE_EXTRA_SPACING gaps between the threads.
2017-07-19 16:06:29 +02:00
float width = float ( bridge ?
2017-07-19 15:53:43 +02:00
( spacing - BRIDGE_EXTRA_SPACING ) :
#ifdef HAS_PERIMETER_LINE_OVERLAP
( spacing + PERIMETER_LINE_OVERLAP_FACTOR * height * ( 1. - 0.25 * PI ));
#else
2017-07-19 16:06:29 +02:00
( spacing + height * ( 1. - 0.25 * PI )));
2017-07-19 15:53:43 +02:00
#endif
return Flow ( width , bridge ? width : height , nozzle_diameter , bridge );
2014-01-05 13:16:13 +01:00
}
2017-07-19 15:53:43 +02:00
// This method returns the centerline spacing between two adjacent extrusions
// having the same extrusion width (and other properties).
float Flow :: spacing () const
2016-11-23 15:51:47 +01:00
{
#ifdef HAS_PERIMETER_LINE_OVERLAP
if ( this -> bridge )
2014-06-12 09:15:40 +02:00
return this -> width + BRIDGE_EXTRA_SPACING ;
2014-07-26 15:29:24 +02:00
// rectangle with semicircles at the ends
2017-07-19 15:53:43 +02:00
float min_flow_spacing = this -> width - this -> height * ( 1. - 0.25 * PI );
2016-11-23 15:51:47 +01:00
return this -> width - PERIMETER_LINE_OVERLAP_FACTOR * ( this -> width - min_flow_spacing );
#else
2017-07-19 16:06:29 +02:00
return float ( this -> bridge ? ( this -> width + BRIDGE_EXTRA_SPACING ) : ( this -> width - this -> height * ( 1. - 0.25 * PI )));
2016-11-23 15:51:47 +01:00
#endif
2014-06-12 01:00:13 +02:00
}
2017-07-19 15:53:43 +02:00
// This method returns the centerline spacing between an extrusion using this
// flow and another one using another flow.
// this->spacing(other) shall return the same value as other.spacing(*this)
float Flow :: spacing ( const Flow & other ) const
{
2014-06-12 09:15:40 +02:00
assert ( this -> height == other . height );
assert ( this -> bridge == other . bridge );
2017-07-19 16:06:29 +02:00
return float ( this -> bridge ?
0.5 * this -> width + 0.5 * other . width + BRIDGE_EXTRA_SPACING :
0.5 * this -> spacing () + 0.5 * other . spacing ());
2014-06-12 09:15:40 +02:00
}
2017-07-19 15:53:43 +02:00
// This method returns extrusion volume per head move unit.
2016-11-23 15:51:47 +01:00
double Flow :: mm3_per_mm () const
{
2017-09-12 18:20:06 +02:00
double res = this -> bridge ?
// Area of a circle with dmr of this->width.
2017-07-19 15:53:43 +02:00
( this -> width * this -> width ) * 0.25 * PI :
2017-09-12 18:20:06 +02:00
// Rectangle with semicircles at the ends. ~ h (w - 0.215 h)
this -> height * ( this -> width - this -> height * ( 1. - 0.25 * PI ));
assert ( res > 0. );
return res ;
2014-01-05 13:16:13 +01:00
}
2017-05-03 18:28:22 +02:00
Flow support_material_flow ( const PrintObject * object , float layer_height )
{
return Flow :: new_from_config_width (
frSupportMaterial ,
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
2018-09-11 14:04:47 +02:00
( object -> config (). support_material_extrusion_width . value > 0 ) ? object -> config (). support_material_extrusion_width : object -> config (). extrusion_width ,
// if object->config().support_material_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component.
float ( object -> print () -> config (). nozzle_diameter . get_at ( object -> config (). support_material_extruder - 1 )),
( layer_height > 0.f ) ? layer_height : float ( object -> config (). layer_height . value ),
2018-09-17 15:12:13 +02:00
// bridge_flow_ratio
0.f );
2017-05-03 18:28:22 +02:00
}
Flow support_material_1st_layer_flow ( const PrintObject * object , float layer_height )
{
2018-09-11 14:04:47 +02:00
const auto & width = ( object -> print () -> config (). first_layer_extrusion_width . value > 0 ) ? object -> print () -> config (). first_layer_extrusion_width : object -> config (). support_material_extrusion_width ;
2017-05-03 18:28:22 +02:00
return Flow :: new_from_config_width (
frSupportMaterial ,
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
2018-09-11 14:04:47 +02:00
( width . value > 0 ) ? width : object -> config (). extrusion_width ,
float ( object -> print () -> config (). nozzle_diameter . get_at ( object -> config (). support_material_extruder - 1 )),
( layer_height > 0.f ) ? layer_height : float ( object -> config (). first_layer_height . get_abs_value ( object -> config (). layer_height . value )),
2018-09-17 15:12:13 +02:00
// bridge_flow_ratio
0.f );
2017-05-03 18:28:22 +02:00
}
Flow support_material_interface_flow ( const PrintObject * object , float layer_height )
{
return Flow :: new_from_config_width (
frSupportMaterialInterface ,
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
2018-09-11 14:04:47 +02:00
( object -> config (). support_material_extrusion_width > 0 ) ? object -> config (). support_material_extrusion_width : object -> config (). extrusion_width ,
// if object->config().support_material_interface_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component.
float ( object -> print () -> config (). nozzle_diameter . get_at ( object -> config (). support_material_interface_extruder - 1 )),
( layer_height > 0.f ) ? layer_height : float ( object -> config (). layer_height . value ),
2018-09-17 15:12:13 +02:00
// bridge_flow_ratio
0.f );
2017-05-03 18:28:22 +02:00
}
2014-01-05 13:16:13 +01:00
}