@@ -24,13 +24,10 @@ void Print::clear_objects()
void Print : : delete_object ( size_t idx )
void Print : : delete_object ( size_t idx )
{
{
PrintObject * object = this - > objects [ idx ] ;
// before deleting object, invalidate all of its steps in order to
// invalidate all of the dependent ones in Print
object - > invalidate_all_steps ( ) ;
// destroy object and remove it from our container
// destroy object and remove it from our container
delete object ;
delete this - > objects [ idx ] ;
this - > objects . erase ( this - > objects . begin ( ) + idx ) ;
this - > objects . erase ( this - > objects . begin ( ) + idx ) ;
this - > invalidate_all_steps ( ) ;
// TODO: purge unused regions
// TODO: purge unused regions
}
}
@@ -181,6 +178,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
steps . emplace_back ( psWipeTower ) ;
steps . emplace_back ( psWipeTower ) ;
} else {
} else {
// for legacy, if we can't handle this option let's invalidate all steps
// for legacy, if we can't handle this option let's invalidate all steps
//FIXME invalidate all steps of all objects as well?
return this - > invalidate_all_steps ( ) ;
return this - > invalidate_all_steps ( ) ;
}
}
}
}
@@ -191,8 +189,8 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
invalidated | = this - > invalidate_step ( step ) ;
invalidated | = this - > invalidate_step ( step ) ;
sort_remove_duplicates ( osteps ) ;
sort_remove_duplicates ( osteps ) ;
for ( PrintObjectStep ostep : osteps )
for ( PrintObjectStep ostep : osteps )
FOREACH_OBJECT ( this , object )
for ( PrintObject * object : this - > objects )
invalidated | = ( * object ) - > invalidate_step ( ostep ) ;
invalidated | = object - > invalidate_step ( ostep ) ;
return invalidated ;
return invalidated ;
}
}
@@ -292,64 +290,42 @@ double Print::max_allowed_layer_height() const
return nozzle_diameter_max ;
return nozzle_diameter_max ;
}
}
/* Caller is responsible for supplying models whose objects don't collide
// Caller is responsible for supplying models whose objects don't collide
and have explicit instance positions */
// and have explicit instance positions.
void Print : : add_model_object ( ModelObject * model_object , int idx )
void Print : : add_model_object ( ModelObject * model_object , int idx )
{
{
DynamicPrintConfig object_config = model_object - > config ; // cl one
// Initialize a new print object and store it at the given positi on.
object_config . normalize ( ) ;
PrintObject * object = new PrintObject ( this , model_object , model_object - > raw_bounding_box ( ) ) ;
// initialize print object and store it at the given position
PrintObject * o ;
{
BoundingBoxf3 bb = model_object - > raw_bounding_box ( ) ;
if ( idx ! = - 1 ) {
if ( idx ! = - 1 ) {
// replacing existing object
delete this - > objects [ idx ] ;
PrintObjectPtrs : : iterator old_it = this - > objects . begin ( ) + idx ;
this - > objects [ idx ] = object ;
// before deleting object, invalidate all of its steps in order to
} else
// invalidate all of the dependent ones in Print
this - > objects . emplace_back ( object ) ;
( * old_it ) - > i nvalidate_ all_steps ( ) ;
// I nvalidate all print steps.
delete * old_it ;
this - > invalidate_all_steps ( ) ;
this - > objects [ idx ] = o = new PrintObject ( this , model_object , bb ) ;
} else {
o = new PrintObject ( this , model_object , bb ) ;
this - > objects . push_back ( o ) ;
// invalidate steps
this - > invalidate_step ( psSkirt ) ;
this - > invalidate_step ( psBrim ) ;
this - > invalidate_step ( psWipeTower ) ;
}
}
for ( size_t volume_id = 0 ; volume_id < model_object - > volumes . size ( ) ; + + volume_id ) {
for ( size_t volume_id = 0 ; volume_id < model_object - > volumes . size ( ) ; + + volume_id ) {
ModelVolume * volume = model_object - > volumes [ volume_id ] ;
// Get the config applied to this volume.
PrintRegionConfig config = this - > _region_config_from_model_volume ( * model_object - > volumes [ volume_id ] ) ;
// get the config applied to this volume
// Find an existing print region with the same config.
PrintRegionConfig config = this - > _region_config_from_model_volume ( * volume ) ;
// find an existing print region with the same config
size_t region_id = size_t ( - 1 ) ;
size_t region_id = size_t ( - 1 ) ;
for ( size_t i = 0 ; i < this - > regions . size ( ) ; + + i )
for ( size_t i = 0 ; i < this - > regions . size ( ) ; + + i )
if ( config . equals ( this - > regions [ i ] - > config ) ) {
if ( config . equals ( this - > regions [ i ] - > config ) ) {
region_id = i ;
region_id = i ;
break ;
break ;
}
}
// If no region exists with the same config, create a new one.
// if no region exists with the same config, create a new one
if ( region_id = = size_t ( - 1 ) ) {
if ( region_id = = size_t ( - 1 ) ) {
region_id = this - > regions . size ( ) ;
region_id = this - > regions . size ( ) ;
this - > add_region ( ) - > config . apply ( config ) ;
this - > add_region ( ) - > config . apply ( config ) ;
}
}
// Assign volume to a region.
// assign volume to region
object - > add_region_ volume( region_id , volume_id ) ;
o - > add_region_volume ( region_id , volume_id ) ;
}
}
// a pply config to print object
// A pply config to print object.
o - > config . apply ( this - > default_object_config ) ;
object - > config . apply ( this - > default_object_config ) ;
o - > config . apply ( object_config , true ) ;
normalize_and_apply_config ( object - > config , model_object - > config ) ;
// update placeholders
// update placeholders
{
{
@@ -358,14 +334,14 @@ void Print::add_model_object(ModelObject* model_object, int idx)
std : : vector < std : : string > v_scale ;
std : : vector < std : : string > v_scale ;
for ( const PrintObject * object : this - > objects ) {
for ( const PrintObject * object : this - > objects ) {
const ModelObject & mobj = * object - > model_object ( ) ;
const ModelObject & mobj = * object - > model_object ( ) ;
v_scale . push_back ( boost : : lexical_cast < std : : string > ( mobj . instances [ 0 ] - > scaling_factor * 100 ) + " % " ) ;
v_scale . push_back ( boost : : lexical_cast < std : : string > ( mobj . instances [ 0 ] - > scaling_factor * 100 ) + " % " ) ;
if ( input_file . empty ( ) )
if ( input_file . empty ( ) )
input_file = mobj . input_file ;
input_file = mobj . input_file ;
}
}
PlaceholderParser & pp = this - > placeholder_parser ;
PlaceholderParser & pp = this - > placeholder_parser ;
pp . set ( " scale " , v_scale ) ;
pp . set ( " scale " , v_scale ) ;
if ( ! input_file . empty ( ) ) {
if ( ! input_file . empty ( ) ) {
// get basename with and without suffix
// get basename with and without suffix
const std : : string input_basename = boost : : filesystem : : path ( input_file ) . filename ( ) . string ( ) ;
const std : : string input_basename = boost : : filesystem : : path ( input_file ) . filename ( ) . string ( ) ;
pp . set ( " input_filename " , input_basename ) ;
pp . set ( " input_filename " , input_basename ) ;
@@ -383,12 +359,10 @@ bool Print::apply_config(DynamicPrintConfig config)
// apply variables to placeholder parser
// apply variables to placeholder parser
this - > placeholder_parser . apply_config ( config ) ;
this - > placeholder_parser . apply_config ( config ) ;
bool invalidated = false ;
// handle changes to print config
// handle changes to print config
t_config_option_keys print_diff = this - > config . diff ( config ) ;
t_config_option_keys print_diff = this - > config . diff ( config ) ;
this - > config . apply ( config , print_diff , true ) ;
this - > config . apply ( config , print_diff , true ) ;
invalidated | = this - > invalidate_state_by_config_options ( print_diff ) ;
bool invalidated = this - > invalidate_state_by_config_options ( print_diff ) ;
// handle changes to object config defaults
// handle changes to object config defaults
this - > default_object_config . apply ( config , true ) ;
this - > default_object_config . apply ( config , true ) ;
@@ -396,15 +370,8 @@ bool Print::apply_config(DynamicPrintConfig config)
// we don't assume that config contains a full ObjectConfig,
// we don't assume that config contains a full ObjectConfig,
// so we base it on the current print-wise default
// so we base it on the current print-wise default
PrintObjectConfig new_config = this - > default_object_config ;
PrintObjectConfig new_config = this - > default_object_config ;
new_config . apply ( config , true ) ;
// we override the new config with object-specific options
// we override the new config with object-specific options
{
normalize_and_apply_config ( new_config , object - > model_object ( ) - > config ) ;
DynamicPrintConfig model_object_config = object - > model_object ( ) - > config ;
model_object_config . normalize ( ) ;
new_config . apply ( model_object_config , true ) ;
}
// check whether the new config is different from the current one
// check whether the new config is different from the current one
t_config_option_keys diff = object - > config . diff ( new_config ) ;
t_config_option_keys diff = object - > config . diff ( new_config ) ;
object - > config . apply ( new_config , diff , true ) ;
object - > config . apply ( new_config , diff , true ) ;
@@ -417,56 +384,57 @@ bool Print::apply_config(DynamicPrintConfig config)
// All regions now have distinct settings.
// All regions now have distinct settings.
// Check whether applying the new region config defaults we'd get different regions.
// Check whether applying the new region config defaults we'd get different regions.
bool rearrange_regions = false ;
bool rearrange_regions = false ;
{
// Collect the already visited region configs into other_region_configs,
// so one may check for duplicates.
std : : vector < PrintRegionConfig > other_region_configs ;
std : : vector < PrintRegionConfig > other_region_configs ;
for ( size_t region_id = 0 ; region_id < this - > regions . size ( ) ; + + region_id )
for ( size_t region_id = 0 ; region_id < this - > regions . size ( ) ; + + region_id ) {
{
PrintRegion & region = * this - > regions [ region_id ] ;
PrintRegion* region = this - > regions [ region_id ] ;
PrintRegionConfig this_region_config ;
std : : vector < PrintRegionConfig > this_region_configs ;
bool this_region_config_set = false ;
for ( PrintObject * object : this - > objects )
for ( PrintObject * object : this - > objects ) {
{
if ( region_id < object - > region_volumes . size ( ) ) {
for ( int volume_id : object - > region_volumes [ region_id ] ) {
for ( int volume_id : object - > region_volumes [ region_id ] ) {
ModelVolume * volume = object - > model_object ( ) - > volumes . at ( volume_id ) ;
const ModelVolume & volume = * object - > model_object ( ) - > volumes [ volume_id ] ;
if ( this_region_config_set ) {
PrintRegionConfig new_ config = this - > _region_config_from_model_volume ( * volume ) ;
// If the new config for this volume differs from the other
for ( const PrintRegionConfig & cfg : this_region_configs ) {
// if the new config for this volume differs from the other
// volume configs currently associated to this region, it means
// volume configs currently associated to this region, it means
// the region subdivision does not make sense anymore
// the region subdivision does not make sense anymore.
if ( ! cfg . equals ( new_config ) ) {
if ( ! this_region_config . equals ( this - > _region_config_from_model_volume ( volume ) ) ) {
rearrange_regions = true ;
rearrange_regions = true ;
goto NEXT_REGION ;
goto exit_for_rearrange_regions ;
}
}
} else {
this_region_config = this - > _region_config_from_model_volume ( volume ) ;
this_region_config_set = true ;
}
}
this_region_configs . push_back ( new_config ) ;
for ( const PrintRegionConfig & cfg : other_region_configs ) {
for ( const PrintRegionConfig & cfg : other_region_configs ) {
// i f the new config for this volume equals any of the other
// I f the new config for this volume equals any of the other
// volume configs that are not currently associated to this
// volume configs that are not currently associated to this
// region, it means the region subdivision does not make
// region, it means the region subdivision does not make
// sense anymore
// sense anymore.
if ( cfg . equals ( new _config) ) {
if ( cfg . equals ( this_region _config) ) {
rearrange_regions = true ;
rearrange_regions = true ;
goto NEXT_REGION ;
goto exit_for_rearrange_regions ;
}
}
}
}
}
// if we're here and the new region config is different from the old
}
// one, we need to apply the new config and invalidate all objects
}
// (possible optimization: only invalidate objects using this region)
if ( this_region_config_set ) {
t_config_option_keys diff = region - > config . diff ( new _config) ;
t_config_option_keys diff = region . config . diff ( this_region _config) ;
if ( ! diff . empty ( ) ) {
if ( ! diff . empty ( ) ) {
region - > config . apply ( new _config, diff ) ;
region . config . apply ( this_region _config, diff ) ;
for ( PrintObject * object : this - > objects )
for ( PrintObject * object : this - > objects )
if ( region_id < object - > region_volumes . size ( ) & & ! object - > region_volumes [ region_id ] . empty ( ) )
invalidated | = object - > invalidate_state_by_config_options ( diff ) ;
invalidated | = object - > invalidate_state_by_config_options ( diff ) ;
}
}
other_region_configs . emplace_back ( this_region_config ) ;
}
}
}
}
}
append ( other_region_configs , this_region_configs ) ;
NEXT_REGION :
exit_for_rearrange_regions :
continue ;
}
if ( rearrange_regions ) {
if ( rearrange_regions ) {
// The current subdivision of regions does not make sense anymore.
// The current subdivision of regions does not make sense anymore.
@@ -518,65 +486,54 @@ bool Print::has_skirt() const
std : : string Print : : validate ( ) const
std : : string Print : : validate ( ) const
{
{
if ( this - > config . complete_objects ) {
if ( this - > config . complete_objects ) {
// c heck horizontal clearance
// C heck horizontal clearance.
{
{
Polygons a ;
Polygons convex_hulls_other ;
FOREACH_OBJECT ( this , i_ object) {
for ( PrintObject * object : this - > objects ) {
PrintObject * object = * i_ object;
// Get convex hull of all meshes assigned to this print object
// (this is the same as model_object()->raw_mesh.convex_hull()
/* get convex hull of all meshes assigned to this print object
// but probably more efficient.
(this is the same as model_object()->raw_mesh.convex_hull()
but probably more efficient */
Polygon convex_hull ;
Polygon convex_hull ;
{
{
Polygons mesh_convex_hulls ;
Polygons mesh_convex_hulls ;
for ( size_t i = 0 ; i < this - > regions . size ( ) ; + + i ) {
for ( const std : : vector < int > & volumes : object - > region_volumes )
for ( std : : vector < int > : : const_iterator it = object - > region_volumes [ i ] . begin ( ) ; it ! = object - > region_volumes [ i ] . end ( ) ; + + it ) {
for ( int volume_id : volumes )
Polygon hull = object - > model_object ( ) - > volumes [ * it ] - > mesh . convex_hull ( ) ;
mesh_convex_hulls . emplace_back ( object - > model_object ( ) - > volumes [ volume_id ] - > mesh . convex_hull ( ) ) ;
mesh_convex_hulls . push_back ( hull ) ;
}
}
// make a single convex hull for all of them
// make a single convex hull for all of them
convex_hull = Slic3r : : Geometry : : convex_hull ( mesh_convex_hulls ) ;
convex_hull = Slic3r : : Geometry : : convex_hull ( mesh_convex_hulls ) ;
}
}
// Apply the same transformations we apply to the actual meshes when slicing them.
// apply the same transformations we apply to the actual meshes when slicing them
object - > model_object ( ) - > instances . front ( ) - > transform_polygon ( & convex_hull ) ;
object - > model_object ( ) - > instances . front ( ) - > transform_polygon ( & convex_hull ) ;
// Grow convex hull with the clearance margin.
// grow convex hull with the clearance margin
convex_hull = offset ( convex_hull , scale_ ( this - > config . extruder_clearance_radius . value ) / 2 , jtRound , scale_ ( 0.1 ) ) . front ( ) ;
convex_hull = offset ( convex_hull , scale_ ( this - > config . extruder_clearance_radius . value ) / 2 , jtRound , scale_ ( 0.1 ) ) . front ( ) ;
// Now we check that no instance of convex_hull intersects any of the previously checked object instances.
// now we check that no instance of convex_hull intersects any of the previously checked object instances
for ( const Point & copy : object - > _shifted_copies ) {
for ( const Point & copy : object - > _shifted_copies ) {
Polygon p = convex_hull ;
Polygon p = convex_hull ;
p . translate ( copy ) ;
p . translate ( copy ) ;
if ( ! intersection ( a , p ) . empty ( ) )
if ( ! intersection ( convex_hulls_other , p ) . empty ( ) )
return " Some objects are too close; your extruder will collide with them. " ;
return " Some objects are too close; your extruder will collide with them. " ;
polygons_append ( a , p ) ;
polygons_append ( convex_hulls_other , p ) ;
}
}
}
}
}
}
// Check vertical clearance.
// check vertical clearance
{
{
std : : vector < coord_t > object_height ;
std : : vector < coord_t > object_height ;
FOREACH_OBJECT ( this , i_ object) {
for ( const PrintObject * object : this - > objects )
PrintObject * object = * i_object ;
object_height . insert ( object_height . end ( ) , object - > copies ( ) . size ( ) , object - > size . z ) ;
object_height . insert ( object_height . end ( ) , object - > copies ( ) . size ( ) , object - > size . z ) ;
}
std : : sort ( object_height . begin ( ) , object_height . end ( ) ) ;
std : : sort ( object_height . begin ( ) , object_height . end ( ) ) ;
// i gnore the tallest *copy* (this is why we repeat height for all of them):
// I gnore the tallest *copy* (this is why we repeat height for all of them):
// it will be printed as last one so its height doesn't matter
// it will be printed as last one so its height doesn't matter.
object_height . pop_back ( ) ;
object_height . pop_back ( ) ;
if ( ! object_height . empty ( ) & & object_height . back ( ) > scale_ ( this - > config . extruder_clearance_height . value ) )
if ( ! object_height . empty ( ) & & object_height . back ( ) > scale_ ( this - > config . extruder_clearance_height . value ) )
return " Some objects are too tall and cannot be printed without extruder collisions. " ;
return " Some objects are too tall and cannot be printed without extruder collisions. " ;
}
}
} // end if (this->config.complete_objects)
} // end if (this->config.complete_objects)
if ( this - > config . spiral_vase ) {
if ( this - > config . spiral_vase ) {
size_t total_copies_count = 0 ;
size_t total_copies_count = 0 ;
FOREACH_OBJECT ( this , i_object ) total_copies_count + = ( * i_object ) - > copies ( ) . size ( ) ;
for ( const PrintObject * object : this - > objects )
total_copies_count + = object - > copies ( ) . size ( ) ;
if ( total_copies_count > 1 )
if ( total_copies_count > 1 )
return " The Spiral Vase option can only be used when printing a single object. " ;
return " The Spiral Vase option can only be used when printing a single object. " ;
if ( this - > regions . size ( ) > 1 )
if ( this - > regions . size ( ) > 1 )
@@ -594,9 +551,7 @@ std::string Print::validate() const
nozzle_diameters . push_back ( this - > config . nozzle_diameter . get_at ( extruder_id ) ) ;
nozzle_diameters . push_back ( this - > config . nozzle_diameter . get_at ( extruder_id ) ) ;
double min_nozzle_diameter = * std : : min_element ( nozzle_diameters . begin ( ) , nozzle_diameters . end ( ) ) ;
double min_nozzle_diameter = * std : : min_element ( nozzle_diameters . begin ( ) , nozzle_diameters . end ( ) ) ;
FOREACH_OBJECT ( this , i_ object) {
for ( PrintObject * object : this - > objects ) {
PrintObject * object = * i_object ;
if ( ( object - > config . support_material_extruder = = - 1 | | object - > config . support_material_interface_extruder = = - 1 ) & &
if ( ( object - > config . support_material_extruder = = - 1 | | object - > config . support_material_interface_extruder = = - 1 ) & &
( object - > config . raft_layers > 0 | | object - > config . support_material . value ) ) {
( object - > config . raft_layers > 0 | | object - > config . support_material . value ) ) {
// The object has some form of support and either support_material_extruder or support_material_interface_extruder
// The object has some form of support and either support_material_extruder or support_material_interface_extruder
@@ -640,14 +595,11 @@ std::string Print::validate() const
BoundingBox Print : : bounding_box ( ) const
BoundingBox Print : : bounding_box ( ) const
{
{
BoundingBox bb ;
BoundingBox bb ;
FOREACH_OBJECT ( this , object ) {
for ( const PrintObject * object : this - > objects )
for ( Points : : const_iterator copy = ( * object ) - > _shifted_copies . begin ( ) ; copy ! = ( * object ) - > _shifted_copies . end ( ) ; + + copy ) {
for ( Point copy : object - > _shifted_copies ) {
bb . merge ( * copy ) ;
bb . merge ( copy ) ;
copy . translate ( object - > size ) ;
Point p = * copy ;
bb . merge ( copy ) ;
p . translate ( ( * object ) - > size ) ;
bb . merge ( p ) ;
}
}
}
return bb ;
return bb ;
}
}
@@ -737,25 +689,13 @@ Flow Print::skirt_flow() const
) ;
) ;
}
}
PrintRegionConfig Print : : _region_config_from_model_volume ( const ModelVolume & volume )
PrintRegionConfig Print : : _region_config_from_model_volume ( const ModelVolume & volume )
{
{
PrintRegionConfig config = this - > default_region_config ;
PrintRegionConfig config = this - > default_region_config ;
{
normalize_and_apply_config ( config , volume . get_object ( ) - > config ) ;
DynamicPrintConfig other_ config = volume . get_object ( ) - > config;
normalize_and_apply_config ( config, volume . config ) ;
other_config . normalize ( ) ;
if ( ! volume . material_id ( ) . empty ( ) )
config . apply ( other_config , true ) ;
normalize_and_apply_config ( config , volume . material ( ) - > config ) ;
}
{
DynamicPrintConfig other_config = volume . config ;
other_config . normalize ( ) ;
config . apply ( other_config , true ) ;
}
if ( ! volume . material_id ( ) . empty ( ) ) {
DynamicPrintConfig material_config = volume . material ( ) - > config ;
material_config . normalize ( ) ;
config . apply ( material_config , true ) ;
}
return config ;
return config ;
}
}
@@ -1039,9 +979,10 @@ std::string Print::output_filepath(const std::string &path)
if ( path . empty ( ) ) {
if ( path . empty ( ) ) {
// get the first input file name
// get the first input file name
std : : string input_file ;
std : : string input_file ;
FOREACH_OBJECT ( this , object ) {
for ( const PrintObject * object : this - > objects ) {
input_file = ( * object ) - > model_object ( ) - > input_file ;
input_file = object - > model_object ( ) - > input_file ;
if ( ! input_file . empty ( ) ) break ;
if ( ! input_file . empty ( ) )
break ;
}
}
return ( boost : : filesystem : : path ( input_file ) . parent_path ( ) / this - > output_filename ( ) ) . string ( ) ;
return ( boost : : filesystem : : path ( input_file ) . parent_path ( ) / this - > output_filename ( ) ) . string ( ) ;
}
}