mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 12:41:20 -06:00 
			
		
		
		
	Initial integration of the Prusa MultiMatrial Wipe Tower.
This commit is contained in:
		
							parent
							
								
									74346efccb
								
							
						
					
					
						commit
						c22b6edeeb
					
				
					 11 changed files with 922 additions and 439 deletions
				
			
		|  | @ -558,6 +558,7 @@ sub build { | ||||||
|         top_infill_extrusion_width support_material_extrusion_width |         top_infill_extrusion_width support_material_extrusion_width | ||||||
|         infill_overlap bridge_flow_ratio |         infill_overlap bridge_flow_ratio | ||||||
|         clip_multipart_objects xy_size_compensation threads resolution |         clip_multipart_objects xy_size_compensation threads resolution | ||||||
|  |         wipe_tower wipe_tower_x wipe_tower_y wipe_tower_width wipe_tower_per_color_wipe | ||||||
|     )); |     )); | ||||||
|     $self->{config}->set('print_settings_id', ''); |     $self->{config}->set('print_settings_id', ''); | ||||||
|      |      | ||||||
|  | @ -720,6 +721,14 @@ sub build { | ||||||
|             $optgroup->append_single_option_line('ooze_prevention'); |             $optgroup->append_single_option_line('ooze_prevention'); | ||||||
|             $optgroup->append_single_option_line('standby_temperature_delta'); |             $optgroup->append_single_option_line('standby_temperature_delta'); | ||||||
|         } |         } | ||||||
|  |         { | ||||||
|  |             my $optgroup = $page->new_optgroup('Wipe tower'); | ||||||
|  |             $optgroup->append_single_option_line('wipe_tower'); | ||||||
|  |             $optgroup->append_single_option_line('wipe_tower_x'); | ||||||
|  |             $optgroup->append_single_option_line('wipe_tower_y'); | ||||||
|  |             $optgroup->append_single_option_line('wipe_tower_width'); | ||||||
|  |             $optgroup->append_single_option_line('wipe_tower_per_color_wipe'); | ||||||
|  |         } | ||||||
|         { |         { | ||||||
|             my $optgroup = $page->new_optgroup('Advanced'); |             my $optgroup = $page->new_optgroup('Advanced'); | ||||||
|             $optgroup->append_single_option_line('interface_shells'); |             $optgroup->append_single_option_line('interface_shells'); | ||||||
|  | @ -955,6 +964,10 @@ sub _update { | ||||||
|     my $have_ooze_prevention = $config->ooze_prevention; |     my $have_ooze_prevention = $config->ooze_prevention; | ||||||
|     $self->get_field($_)->toggle($have_ooze_prevention) |     $self->get_field($_)->toggle($have_ooze_prevention) | ||||||
|         for qw(standby_temperature_delta); |         for qw(standby_temperature_delta); | ||||||
|  | 
 | ||||||
|  |     my $have_wipe_tower = $config->wipe_tower; | ||||||
|  |     $self->get_field($_)->toggle($have_wipe_tower) | ||||||
|  |         for qw(wipe_tower_x wipe_tower_y wipe_tower_width wipe_tower_per_color_wipe); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| sub hidden_options { !$Slic3r::have_threads ? qw(threads) : () } | sub hidden_options { !$Slic3r::have_threads ? qw(threads) : () } | ||||||
|  | @ -969,7 +982,7 @@ sub build { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|      |      | ||||||
|     $self->init_config_options(qw( |     $self->init_config_options(qw( | ||||||
|         filament_colour filament_diameter filament_notes filament_max_volumetric_speed extrusion_multiplier filament_density filament_cost |         filament_colour filament_diameter filament_type filament_soluble filament_notes filament_max_volumetric_speed extrusion_multiplier filament_density filament_cost | ||||||
|         temperature first_layer_temperature bed_temperature first_layer_bed_temperature |         temperature first_layer_temperature bed_temperature first_layer_bed_temperature | ||||||
|         fan_always_on cooling |         fan_always_on cooling | ||||||
|         min_fan_speed max_fan_speed bridge_fan_speed disable_fan_first_layers |         min_fan_speed max_fan_speed bridge_fan_speed disable_fan_first_layers | ||||||
|  | @ -984,6 +997,8 @@ sub build { | ||||||
|             $optgroup->append_single_option_line('filament_colour', 0); |             $optgroup->append_single_option_line('filament_colour', 0); | ||||||
|             $optgroup->append_single_option_line('filament_diameter', 0); |             $optgroup->append_single_option_line('filament_diameter', 0); | ||||||
|             $optgroup->append_single_option_line('extrusion_multiplier', 0); |             $optgroup->append_single_option_line('extrusion_multiplier', 0); | ||||||
|  |             $optgroup->append_single_option_line('filament_type', 0); | ||||||
|  |             $optgroup->append_single_option_line('filament_soluble', 0); | ||||||
|             $optgroup->append_single_option_line('filament_density', 0); |             $optgroup->append_single_option_line('filament_density', 0); | ||||||
|             $optgroup->append_single_option_line('filament_cost', 0); |             $optgroup->append_single_option_line('filament_cost', 0); | ||||||
|         } |         } | ||||||
|  | @ -1137,7 +1152,7 @@ sub build { | ||||||
|         octoprint_host octoprint_apikey |         octoprint_host octoprint_apikey | ||||||
|         use_firmware_retraction |         use_firmware_retraction | ||||||
|         use_volumetric_e variable_layer_height |         use_volumetric_e variable_layer_height | ||||||
|         start_gcode end_gcode before_layer_gcode layer_gcode toolchange_gcode |         single_extruder_multi_material start_gcode end_gcode before_layer_gcode layer_gcode toolchange_gcode | ||||||
|         nozzle_diameter extruder_offset |         nozzle_diameter extruder_offset | ||||||
|         retract_length retract_lift retract_speed retract_restart_extra retract_before_travel retract_layer_change wipe |         retract_length retract_lift retract_speed retract_restart_extra retract_before_travel retract_layer_change wipe | ||||||
|         retract_length_toolchange retract_restart_extra_toolchange |         retract_length_toolchange retract_restart_extra_toolchange | ||||||
|  | @ -1198,6 +1213,7 @@ sub build { | ||||||
|                     min         => 1, |                     min         => 1, | ||||||
|                 ); |                 ); | ||||||
|                 $optgroup->append_single_option_line($option); |                 $optgroup->append_single_option_line($option); | ||||||
|  |                 $optgroup->append_single_option_line('single_extruder_multi_material'); | ||||||
|             } |             } | ||||||
|             $optgroup->on_change(sub { |             $optgroup->on_change(sub { | ||||||
|                 my ($opt_id) = @_; |                 my ($opt_id) = @_; | ||||||
|  | @ -1538,6 +1554,7 @@ sub _update { | ||||||
|      |      | ||||||
|     my $have_multiple_extruders = $self->{extruders_count} > 1; |     my $have_multiple_extruders = $self->{extruders_count} > 1; | ||||||
|     $self->get_field('toolchange_gcode')->toggle($have_multiple_extruders); |     $self->get_field('toolchange_gcode')->toggle($have_multiple_extruders); | ||||||
|  |     $self->get_field('single_extruder_multi_material')->toggle($have_multiple_extruders); | ||||||
|      |      | ||||||
|     for my $i (0 .. ($self->{extruders_count}-1)) { |     for my $i (0 .. ($self->{extruders_count}-1)) { | ||||||
|         my $have_retract_length = $config->get_at('retract_length', $i) > 0; |         my $have_retract_length = $config->get_at('retract_length', $i) > 0; | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| #include "ExtrusionEntity.hpp" | #include "ExtrusionEntity.hpp" | ||||||
| #include "EdgeGrid.hpp" | #include "EdgeGrid.hpp" | ||||||
| #include "Geometry.hpp" | #include "Geometry.hpp" | ||||||
|  | #include "GCode/WipeTowerPrusaMM.hpp" | ||||||
| 
 | 
 | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
| #include <cstdlib> | #include <cstdlib> | ||||||
|  | @ -384,6 +385,8 @@ bool GCode::do_export(FILE *file, Print &print) | ||||||
|                     // Set first layer extruder.
 |                     // Set first layer extruder.
 | ||||||
|                     this->_print_first_layer_extruder_temperatures(file, print, false); |                     this->_print_first_layer_extruder_temperatures(file, print, false); | ||||||
|                 } |                 } | ||||||
|  |                 // Get optimal tool ordering to minimize tool switches of a multi-exruder print.
 | ||||||
|  |                 std::vector<ToolOrdering::LayerTools> tool_ordering = ToolOrdering::tool_ordering(*object); | ||||||
|                 // Pair the object layers with the support layers by z, extrude them.
 |                 // Pair the object layers with the support layers by z, extrude them.
 | ||||||
|                 size_t idx_object_layer  = 0; |                 size_t idx_object_layer  = 0; | ||||||
|                 size_t idx_support_layer = 0; |                 size_t idx_support_layer = 0; | ||||||
|  | @ -401,7 +404,9 @@ bool GCode::do_export(FILE *file, Print &print) | ||||||
|                             -- idx_object_layer; |                             -- idx_object_layer; | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                     this->process_layer(file, print, layers_to_print, © - object->_shifted_copies.data()); |                     auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), ToolOrdering::LayerTools(layer_to_print.layer()->print_z)); | ||||||
|  |                     assert(it_layer_tools != tool_ordering.end() && it_layer_tools->print_z == layer_to_print.layer()->print_z); | ||||||
|  |                     this->process_layer(file, print, layers_to_print, *it_layer_tools, © - object->_shifted_copies.data()); | ||||||
|                 } |                 } | ||||||
|                 write(file, this->filter(m_cooling_buffer->flush(), true)); |                 write(file, this->filter(m_cooling_buffer->flush(), true)); | ||||||
|                 ++ finished_objects; |                 ++ finished_objects; | ||||||
|  | @ -437,15 +442,57 @@ bool GCode::do_export(FILE *file, Print &print) | ||||||
|             } |             } | ||||||
|             ++ object_order; |             ++ object_order; | ||||||
|         } |         } | ||||||
|  |         // Get optimal tool ordering to minimize tool switches of a multi-exruder print.
 | ||||||
|  |         std::vector<ToolOrdering::LayerTools> tool_ordering = ToolOrdering::tool_ordering(print); | ||||||
|  |         // Prusa Multi-Material wipe tower.
 | ||||||
|  |         if (print.config.single_extruder_multi_material.value && print.config.wipe_tower.value &&  | ||||||
|  |             ! tool_ordering.empty() && tool_ordering.front().wipe_tower_partitions > 0) { | ||||||
|  |             // Initialize the wipe tower.
 | ||||||
|  |             auto *wipe_tower = new WipeTowerPrusaMM( | ||||||
|  |                     float(print.config.wipe_tower_x.value), float(print.config.wipe_tower_y.value),  | ||||||
|  |                     float(print.config.wipe_tower_width.value), float(print.config.wipe_tower_per_color_wipe.value)); | ||||||
|  |             //wipe_tower->set_retract();
 | ||||||
|  |             //wipe_tower->set_zhop();
 | ||||||
|  |             //wipe_tower->set_zhop();
 | ||||||
|  |             // Set the extruder & material properties at the wipe tower object.
 | ||||||
|  |             for (size_t i = 0; i < 4; ++ i) | ||||||
|  |                 wipe_tower->set_extruder( | ||||||
|  |                     i,  | ||||||
|  |                     WipeTowerPrusaMM::parse_material(print.config.filament_type.get_at(i).c_str()), | ||||||
|  |                     print.config.temperature.get_at(i), | ||||||
|  |                     print.config.first_layer_temperature.get_at(i)); | ||||||
|  |             m_wipe_tower.reset(wipe_tower); | ||||||
|  |         } | ||||||
|         // Extrude the layers.
 |         // Extrude the layers.
 | ||||||
|         for (auto &layer : layers) |         for (auto &layer : layers) { | ||||||
|             // layer.second is of type std::vector<LayerToPrint>,
 |             // layer.second is of type std::vector<LayerToPrint>,
 | ||||||
|             // wher the objects are sorted by their sorted order given by object_indices.
 |             // wher the objects are sorted by their sorted order given by object_indices.
 | ||||||
|             this->process_layer(file, print, layer.second); |             auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), ToolOrdering::LayerTools(layer.first)); | ||||||
|  |             assert(it_layer_tools != tool_ordering.end() && layer.first); | ||||||
|  |             if (m_wipe_tower) { | ||||||
|  |                 bool first_layer = layer.first == layers.begin()->first; | ||||||
|  |                 auto it_layer_tools_next = it_layer_tools; | ||||||
|  |                 ++ it_layer_tools_next; | ||||||
|  |                 m_wipe_tower->set_layer( | ||||||
|  |                     layer.first,  | ||||||
|  |                     first_layer ?  | ||||||
|  |                         print.objects.front()->config.first_layer_height.get_abs_value(print.objects.front()->config.layer_height.value) : | ||||||
|  |                         print.objects.front()->config.layer_height.value, | ||||||
|  |                     it_layer_tools->wipe_tower_partitions, | ||||||
|  |                     first_layer, | ||||||
|  |                     it_layer_tools->wipe_tower_partitions == 0 || (it_layer_tools_next == tool_ordering.end() || it_layer_tools_next->wipe_tower_partitions == 0)); | ||||||
|  |             } | ||||||
|  |             this->process_layer(file, print, layer.second, *it_layer_tools, size_t(-1)); | ||||||
|  |         } | ||||||
|         write(file, this->filter(m_cooling_buffer->flush(), true)); |         write(file, this->filter(m_cooling_buffer->flush(), true)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // write end commands to file
 |     // write end commands to file
 | ||||||
|  |     if (m_wipe_tower) { | ||||||
|  |         // Unload the current filament over the purge tower.
 | ||||||
|  |         write(file, this->wipe_tower_tool_change(-1)); | ||||||
|  |         m_wipe_tower.release(); | ||||||
|  |     } else | ||||||
|         write(file, this->retract());   // TODO: process this retract through PressureRegulator in order to discharge fully
 |         write(file, this->retract());   // TODO: process this retract through PressureRegulator in order to discharge fully
 | ||||||
|     write(file, m_writer.set_fan(false)); |     write(file, m_writer.set_fan(false)); | ||||||
|     writeln(file, m_placeholder_parser.process(print.config.end_gcode)); |     writeln(file, m_placeholder_parser.process(print.config.end_gcode)); | ||||||
|  | @ -543,6 +590,7 @@ void GCode::process_layer( | ||||||
|     const Print                     &print, |     const Print                     &print, | ||||||
|     // Set of object & print layers of the same PrintObject and with the same print_z.
 |     // Set of object & print layers of the same PrintObject and with the same print_z.
 | ||||||
|     const std::vector<LayerToPrint> &layers, |     const std::vector<LayerToPrint> &layers, | ||||||
|  |     const ToolOrdering::LayerTools  &layer_tools, | ||||||
|     // If set to size_t(-1), then print all copies of all objects.
 |     // If set to size_t(-1), then print all copies of all objects.
 | ||||||
|     // Otherwise print a single copy of a single object.
 |     // Otherwise print a single copy of a single object.
 | ||||||
|     const size_t                     single_object_idx) |     const size_t                     single_object_idx) | ||||||
|  | @ -562,7 +610,8 @@ void GCode::process_layer( | ||||||
|     } |     } | ||||||
|     const Layer         &layer         = (object_layer != nullptr) ? *object_layer : *support_layer;     |     const Layer         &layer         = (object_layer != nullptr) ? *object_layer : *support_layer;     | ||||||
|     coordf_t             print_z       = layer.print_z; |     coordf_t             print_z       = layer.print_z; | ||||||
|     bool                 first_layer   = print_z < m_config.first_layer_height.get_abs_value(m_config.layer_height.value) + EPSILON; |     bool                 first_layer   = layer.id() == 0; | ||||||
|  |     unsigned int         first_extruder_id = layer_tools.extruders.empty() ? 0 : layer_tools.extruders.front(); | ||||||
| 
 | 
 | ||||||
|     // Initialize config with the 1st object to be printed at this layer.
 |     // Initialize config with the 1st object to be printed at this layer.
 | ||||||
|     m_config.apply(layer.object()->config, true); |     m_config.apply(layer.object()->config, true); | ||||||
|  | @ -620,7 +669,7 @@ void GCode::process_layer( | ||||||
|     if (! m_brim_done) |     if (! m_brim_done) | ||||||
|         // Switch the extruder to the extruder of the perimeters, so the perimeters extruder will be primed
 |         // Switch the extruder to the extruder of the perimeters, so the perimeters extruder will be primed
 | ||||||
|         // by the skirt before the brim is extruded with the same extruder.
 |         // by the skirt before the brim is extruded with the same extruder.
 | ||||||
|         gcode += this->set_extruder(print.regions.front()->config.perimeter_extruder.value - 1); |         gcode += this->set_extruder(layer_tools.extruders.front()); | ||||||
|      |      | ||||||
|     // Extrude skirt at the print_z of the raft layers and normal object layers
 |     // Extrude skirt at the print_z of the raft layers and normal object layers
 | ||||||
|     // not at the print_z of the interlaced support material layers.
 |     // not at the print_z of the interlaced support material layers.
 | ||||||
|  | @ -643,10 +692,10 @@ void GCode::process_layer( | ||||||
|             std::vector<unsigned int> extruder_ids = m_writer.extruder_ids(); |             std::vector<unsigned int> extruder_ids = m_writer.extruder_ids(); | ||||||
|             // Reorder the extruders, so that the last used extruder is at the front.
 |             // Reorder the extruders, so that the last used extruder is at the front.
 | ||||||
|             for (size_t i = 1; i < extruder_ids.size(); ++ i) |             for (size_t i = 1; i < extruder_ids.size(); ++ i) | ||||||
|                 if (extruder_ids[i] == m_writer.extruder()->id) { |                 if (extruder_ids[i] == first_extruder_id) { | ||||||
|                     // Move the last extruder to the front.
 |                     // Move the last extruder to the front.
 | ||||||
|                     memmove(extruder_ids.data() + 1, extruder_ids.data(), i * sizeof(unsigned int)); |                     memmove(extruder_ids.data() + 1, extruder_ids.data(), i * sizeof(unsigned int)); | ||||||
|                     extruder_ids.front() = m_writer.extruder()->id; |                     extruder_ids.front() = first_extruder_id; | ||||||
|                     break; |                     break; | ||||||
|                 } |                 } | ||||||
|             size_t n_loops = print.skirt.entities.size(); |             size_t n_loops = print.skirt.entities.size(); | ||||||
|  | @ -668,7 +717,7 @@ void GCode::process_layer( | ||||||
|             } |             } | ||||||
|         } else |         } else | ||||||
|             // Extrude all skirts with the current extruder.
 |             // Extrude all skirts with the current extruder.
 | ||||||
|             skirt_loops_per_extruder[m_writer.extruder()->id] = std::pair<size_t, size_t>(0, print.config.skirts.value); |             skirt_loops_per_extruder[first_extruder_id] = std::pair<size_t, size_t>(0, print.config.skirts.value); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Group extrusions by an extruder, then by an object, an island and a region.
 |     // Group extrusions by an extruder, then by an object, an island and a region.
 | ||||||
|  | @ -684,12 +733,12 @@ void GCode::process_layer( | ||||||
|                 // Don't change extruder if the extruder is set to 0. Use the current extruder instead.
 |                 // Don't change extruder if the extruder is set to 0. Use the current extruder instead.
 | ||||||
|                 bool single_extruder =  |                 bool single_extruder =  | ||||||
|                     (object.config.support_material_extruder.value == object.config.support_material_interface_extruder.value || |                     (object.config.support_material_extruder.value == object.config.support_material_interface_extruder.value || | ||||||
|                     (object.config.support_material_extruder.value == int(m_writer.extruder()->id) && object.config.support_material_interface_extruder.value == 0) || |                     (object.config.support_material_extruder.value == int(first_extruder_id) && object.config.support_material_interface_extruder.value == 0) || | ||||||
|                     (object.config.support_material_interface_extruder.value == int(m_writer.extruder()->id) && object.config.support_material_extruder.value == 0)); |                     (object.config.support_material_interface_extruder.value == int(first_extruder_id) && object.config.support_material_extruder.value == 0)); | ||||||
|                 // Assign an extruder to the base.
 |                 // Assign an extruder to the base.
 | ||||||
|                 ObjectByExtruder &obj = object_by_extruder( |                 ObjectByExtruder &obj = object_by_extruder( | ||||||
|                     by_extruder, |                     by_extruder, | ||||||
|                     (object.config.support_material_extruder == 0) ? m_writer.extruder()->id : (object.config.support_material_extruder - 1), |                     (object.config.support_material_extruder == 0) ? first_extruder_id : (object.config.support_material_extruder - 1), | ||||||
|                     &layer_to_print - layers.data(), |                     &layer_to_print - layers.data(), | ||||||
|                     layers.size()); |                     layers.size()); | ||||||
|                 obj.support = &support_layer.support_fills; |                 obj.support = &support_layer.support_fills; | ||||||
|  | @ -697,7 +746,7 @@ void GCode::process_layer( | ||||||
|                 if (! single_extruder) { |                 if (! single_extruder) { | ||||||
|                     ObjectByExtruder &obj_interface = object_by_extruder( |                     ObjectByExtruder &obj_interface = object_by_extruder( | ||||||
|                         by_extruder, |                         by_extruder, | ||||||
|                         (object.config.support_material_interface_extruder == 0) ? m_writer.extruder()->id : (object.config.support_material_interface_extruder - 1), |                         (object.config.support_material_interface_extruder == 0) ? first_extruder_id : (object.config.support_material_interface_extruder - 1), | ||||||
|                         &layer_to_print - layers.data(), |                         &layer_to_print - layers.data(), | ||||||
|                         layers.size()); |                         layers.size()); | ||||||
|                     obj_interface.support = &support_layer.support_fills; |                     obj_interface.support = &support_layer.support_fills; | ||||||
|  | @ -793,31 +842,14 @@ void GCode::process_layer( | ||||||
|         } |         } | ||||||
|     } // for objects
 |     } // for objects
 | ||||||
| 
 | 
 | ||||||
|     // Tweak extruder ordering to save toolchanges.
 |  | ||||||
|     std::vector<unsigned int> extruders; |  | ||||||
|     extruders.reserve(by_extruder.size()); |  | ||||||
|     for (const auto &ex : by_extruder) |  | ||||||
|         extruders.push_back(ex.first); |  | ||||||
|     if (extrude_skirt) { |  | ||||||
|         // Merge with the skirt extruders.
 |  | ||||||
|         for (const auto &ex : skirt_loops_per_extruder) |  | ||||||
|             extruders.push_back(ex.first); |  | ||||||
|         sort_remove_duplicates(extruders); |  | ||||||
|     } |  | ||||||
|     // Reorder the extruders, so that the last used extruder is at the front.
 |  | ||||||
|     for (size_t i = 1; i < extruders.size(); ++ i) |  | ||||||
|         if (extruders[i] == m_writer.extruder()->id) { |  | ||||||
|             // Move the last extruder to the front.
 |  | ||||||
| 			memmove(extruders.data() + 1, extruders.data(), i * sizeof(unsigned int)); |  | ||||||
|             extruders.front() = m_writer.extruder()->id; |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     // Extrude the skirt, brim, support, perimeters, infill ordered by the extruders.
 |     // Extrude the skirt, brim, support, perimeters, infill ordered by the extruders.
 | ||||||
|     std::vector<std::unique_ptr<EdgeGrid::Grid>> lower_layer_edge_grids(layers.size()); |     std::vector<std::unique_ptr<EdgeGrid::Grid>> lower_layer_edge_grids(layers.size()); | ||||||
|     for (unsigned int extruder_id : extruders) |     for (unsigned int extruder_id : layer_tools.extruders) | ||||||
|     { |     { | ||||||
|         gcode += this->set_extruder(extruder_id); |         gcode += this->set_extruder(extruder_id); | ||||||
|         //FIXME here will come the priming tower call.
 |         if (m_wipe_tower && ! m_wipe_tower->finished() && extruder_id == layer_tools.extruders.back()) | ||||||
|  |             // Last extruder change on the layer or no extruder change at all.
 | ||||||
|  |             m_wipe_tower->close_layer(); | ||||||
| 
 | 
 | ||||||
|         if (extrude_skirt) { |         if (extrude_skirt) { | ||||||
|             auto loops_it = skirt_loops_per_extruder.find(extruder_id); |             auto loops_it = skirt_loops_per_extruder.find(extruder_id); | ||||||
|  | @ -1675,7 +1707,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, | ||||||
|     this->set_last_pos(path.last_point()); |     this->set_last_pos(path.last_point()); | ||||||
|      |      | ||||||
|     if (m_config.cooling) |     if (m_config.cooling) | ||||||
|         m_elapsed_time += path_length / F * 60; |         m_elapsed_time += path_length / F * 60.f; | ||||||
|      |      | ||||||
|     return gcode; |     return gcode; | ||||||
| } | } | ||||||
|  | @ -1814,21 +1846,39 @@ std::string GCode::set_extruder(unsigned int extruder_id) | ||||||
|         gcode += pp.process(m_config.toolchange_gcode.value) + '\n'; |         gcode += pp.process(m_config.toolchange_gcode.value) + '\n'; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     if (m_wipe_tower) { | ||||||
|  |         assert(! m_wipe_tower->finished()); | ||||||
|  |         if (! m_wipe_tower->finished()) | ||||||
|  |             gcode += this->wipe_tower_tool_change(extruder_id); | ||||||
|  |     } else { | ||||||
|         // if ooze prevention is enabled, park current extruder in the nearest
 |         // if ooze prevention is enabled, park current extruder in the nearest
 | ||||||
|         // standby point and set it to the standby temperature
 |         // standby point and set it to the standby temperature
 | ||||||
|         if (m_ooze_prevention.enable && m_writer.extruder() != NULL) |         if (m_ooze_prevention.enable && m_writer.extruder() != NULL) | ||||||
|             gcode += m_ooze_prevention.pre_toolchange(*this); |             gcode += m_ooze_prevention.pre_toolchange(*this); | ||||||
|      |  | ||||||
|         // append the toolchange command
 |         // append the toolchange command
 | ||||||
|         gcode += m_writer.toolchange(extruder_id); |         gcode += m_writer.toolchange(extruder_id); | ||||||
|      |  | ||||||
|         // set the new extruder to the operating temperature
 |         // set the new extruder to the operating temperature
 | ||||||
|         if (m_ooze_prevention.enable) |         if (m_ooze_prevention.enable) | ||||||
|             gcode += m_ooze_prevention.post_toolchange(*this); |             gcode += m_ooze_prevention.post_toolchange(*this); | ||||||
|  |     } | ||||||
|      |      | ||||||
|     return gcode; |     return gcode; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | std::string GCode::wipe_tower_tool_change(int extruder_id) | ||||||
|  | { | ||||||
|  |     // Move over the wipe tower.
 | ||||||
|  |     std::string gcode = m_writer.travel_to_xy(Pointf3(m_wipe_tower->position().x, m_wipe_tower->position().y)); | ||||||
|  |     gcode += m_writer.unlift(); | ||||||
|  |     // Let the tool change be executed by the wipe tower class.
 | ||||||
|  |     std::pair<std::string, WipeTower::xy> code_and_pos = m_wipe_tower->tool_change(extruder_id); | ||||||
|  |     // Inform the G-code writer about the changes done behind its back.
 | ||||||
|  |     gcode += code_and_pos.first; | ||||||
|  |     // A phony move to the end position at the wipe tower.
 | ||||||
|  |     m_writer.travel_to_xy(Pointf(code_and_pos.second.x, code_and_pos.second.y)); | ||||||
|  |     return gcode; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // convert a model-space scaled point into G-code coordinates
 | // convert a model-space scaled point into G-code coordinates
 | ||||||
| Pointf GCode::point_to_gcode(const Point &point) const | Pointf GCode::point_to_gcode(const Point &point) const | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -13,6 +13,8 @@ | ||||||
| #include "GCode/CoolingBuffer.hpp" | #include "GCode/CoolingBuffer.hpp" | ||||||
| #include "GCode/PressureEqualizer.hpp" | #include "GCode/PressureEqualizer.hpp" | ||||||
| #include "GCode/SpiralVase.hpp" | #include "GCode/SpiralVase.hpp" | ||||||
|  | #include "GCode/ToolOrdering.hpp" | ||||||
|  | #include "GCode/WipeTower.hpp" | ||||||
| #include "EdgeGrid.hpp" | #include "EdgeGrid.hpp" | ||||||
| 
 | 
 | ||||||
| #include <memory> | #include <memory> | ||||||
|  | @ -129,6 +131,7 @@ private: | ||||||
|         const Print                     &print, |         const Print                     &print, | ||||||
|         // Set of object & print layers of the same PrintObject and with the same print_z.
 |         // Set of object & print layers of the same PrintObject and with the same print_z.
 | ||||||
|         const std::vector<LayerToPrint> &layers, |         const std::vector<LayerToPrint> &layers, | ||||||
|  |         const ToolOrdering::LayerTools  &layer_tools, | ||||||
|         // If set to size_t(-1), then print all copies of all objects.
 |         // If set to size_t(-1), then print all copies of all objects.
 | ||||||
|         // Otherwise print a single copy of a single object.
 |         // Otherwise print a single copy of a single object.
 | ||||||
|         const size_t                     single_object_idx = size_t(-1)); |         const size_t                     single_object_idx = size_t(-1)); | ||||||
|  | @ -172,6 +175,7 @@ private: | ||||||
|     std::string     retract(bool toolchange = false); |     std::string     retract(bool toolchange = false); | ||||||
|     std::string     unretract() { return m_writer.unlift() + m_writer.unretract(); } |     std::string     unretract() { return m_writer.unlift() + m_writer.unretract(); } | ||||||
|     std::string     set_extruder(unsigned int extruder_id); |     std::string     set_extruder(unsigned int extruder_id); | ||||||
|  |     std::string     wipe_tower_tool_change(int extruder_id); | ||||||
| 
 | 
 | ||||||
|     /* Origin of print coordinates expressed in unscaled G-code coordinates.
 |     /* Origin of print coordinates expressed in unscaled G-code coordinates.
 | ||||||
|        This affects the input arguments supplied to the extrude*() and travel_to() |        This affects the input arguments supplied to the extrude*() and travel_to() | ||||||
|  | @ -218,6 +222,7 @@ private: | ||||||
|     std::unique_ptr<CoolingBuffer>      m_cooling_buffer; |     std::unique_ptr<CoolingBuffer>      m_cooling_buffer; | ||||||
|     std::unique_ptr<SpiralVase>         m_spiral_vase; |     std::unique_ptr<SpiralVase>         m_spiral_vase; | ||||||
|     std::unique_ptr<PressureEqualizer>  m_pressure_equalizer; |     std::unique_ptr<PressureEqualizer>  m_pressure_equalizer; | ||||||
|  |     std::unique_ptr<WipeTower>          m_wipe_tower; | ||||||
| 
 | 
 | ||||||
|     // Heights at which the skirt has already been extruded.
 |     // Heights at which the skirt has already been extruded.
 | ||||||
|     std::vector<coordf_t>               m_skirt_done; |     std::vector<coordf_t>               m_skirt_done; | ||||||
|  |  | ||||||
							
								
								
									
										194
									
								
								xs/src/libslic3r/GCode/ToolOrdering.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								xs/src/libslic3r/GCode/ToolOrdering.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,194 @@ | ||||||
|  | #include "ToolOrdering.hpp" | ||||||
|  | 
 | ||||||
|  | namespace Slic3r { | ||||||
|  | namespace ToolOrdering { | ||||||
|  | 
 | ||||||
|  | // Collect extruders reuqired to print layers.
 | ||||||
|  | static void collect_extruders(const PrintObject &object, std::vector<LayerTools> &layers) | ||||||
|  | { | ||||||
|  |     // Collect the support extruders.
 | ||||||
|  |     for (auto support_layer : object.support_layers) { | ||||||
|  |         auto it_layer = std::find(layers.begin(), layers.end(), LayerTools(support_layer->print_z)); | ||||||
|  |         assert(it_layer != layers.end()); | ||||||
|  |         ExtrusionRole role = support_layer->support_fills.role(); | ||||||
|  |         bool         has_support        = role == erMixed || role == erSupportMaterial; | ||||||
|  |         bool         has_interface      = role == erMixed || role == erSupportMaterialInterface; | ||||||
|  |         unsigned int extruder_support   = object.config.support_material_extruder.value; | ||||||
|  |         unsigned int extruder_interface = object.config.support_material_interface_extruder.value; | ||||||
|  |         if (has_support && has_interface) { | ||||||
|  |             // If both base and interface supports are to be extruded and one of them will be extruded with a "don't care" extruder,
 | ||||||
|  |             // print both with the same extruder to minimize extruder switches.
 | ||||||
|  |             if (extruder_support == 0) | ||||||
|  |                 extruder_support = extruder_interface; | ||||||
|  |             else if (extruder_interface == 0) | ||||||
|  |                 extruder_interface = extruder_support; | ||||||
|  |         } | ||||||
|  |         if (has_support) | ||||||
|  |             it_layer->extruders.push_back(extruder_support); | ||||||
|  |         if (has_interface) | ||||||
|  |             it_layer->extruders.push_back(extruder_interface); | ||||||
|  |     } | ||||||
|  |     // Collect the object extruders.
 | ||||||
|  |     for (auto layer : object.layers) { | ||||||
|  |         auto it_layer = std::find(layers.begin(), layers.end(), LayerTools(layer->print_z)); | ||||||
|  |         assert(it_layer != layers.end()); | ||||||
|  |         // What extruders are required to print this object layer?
 | ||||||
|  |         for (size_t region_id = 0; region_id < object.print()->regions.size(); ++ region_id) { | ||||||
|  |             const LayerRegion *layerm = layer->regions[region_id]; | ||||||
|  |             if (layerm == nullptr) | ||||||
|  |                 continue; | ||||||
|  |             const PrintRegion ®ion = *object.print()->regions[region_id]; | ||||||
|  |             if (! layerm->perimeters.entities.empty()) | ||||||
|  |                 it_layer->extruders.push_back(region.config.perimeter_extruder.value); | ||||||
|  |             bool has_infill       = false;  | ||||||
|  |             bool has_solid_infill = false; | ||||||
|  |             for (const ExtrusionEntity *ee : layerm->fills.entities) { | ||||||
|  |                 // fill represents infill extrusions of a single island.
 | ||||||
|  |                 const auto *fill = dynamic_cast<const ExtrusionEntityCollection*>(ee); | ||||||
|  |                 ExtrusionRole role = fill->entities.empty() ? erNone : fill->entities.front()->role(); | ||||||
|  |                 if (is_solid_infill(role)) | ||||||
|  |                     has_solid_infill = true; | ||||||
|  |                 else if (role != erNone) | ||||||
|  |                     has_infill = true; | ||||||
|  |             } | ||||||
|  |             if (has_solid_infill) | ||||||
|  |                 it_layer->extruders.push_back(region.config.solid_infill_extruder); | ||||||
|  |             if (has_infill) | ||||||
|  |                 it_layer->extruders.push_back(region.config.infill_extruder); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Sort and remove duplicates
 | ||||||
|  |     for (LayerTools < : layers) | ||||||
|  |         sort_remove_duplicates(lt.extruders); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Reorder extruders to minimize layer changes.
 | ||||||
|  | static void reorder_extruders(std::vector<LayerTools> &layers) | ||||||
|  | { | ||||||
|  |     if (layers.empty()) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     // Initialize the last_extruder_id with the first non-zero extruder id used for the print.
 | ||||||
|  |     unsigned int last_extruder_id = 0; | ||||||
|  |     for (size_t i = 0; i < layers.size() && last_extruder_id == 0; ++ i) { | ||||||
|  |         const LayerTools < = layers[i]; | ||||||
|  |         for (unsigned int extruder_id : lt.extruders) | ||||||
|  |             if (extruder_id > 0) { | ||||||
|  |                 last_extruder_id = extruder_id; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |     } | ||||||
|  |     if (last_extruder_id == 0) | ||||||
|  |         last_extruder_id = 1; | ||||||
|  | 
 | ||||||
|  |     for (LayerTools < : layers) { | ||||||
|  |         if (lt.extruders.empty()) | ||||||
|  |             continue; | ||||||
|  |         if (lt.extruders.size() == 1 && lt.extruders.front() == 0) | ||||||
|  |             lt.extruders.front() = last_extruder_id; | ||||||
|  |         else { | ||||||
|  |             if (lt.extruders.front() == 0) | ||||||
|  |                 // Pop the "don't care" extruder, the "don't care" region will be merged with the next one.
 | ||||||
|  |                 lt.extruders.erase(lt.extruders.begin()); | ||||||
|  |             // Reorder the extruders to start with the last one.
 | ||||||
|  |             for (size_t i = 1; i < lt.extruders.size(); ++ i) | ||||||
|  |                 if (lt.extruders[i] == last_extruder_id) { | ||||||
|  |                     // Move the last extruder to the front.
 | ||||||
|  |                     memmove(lt.extruders.data() + 1, lt.extruders.data(), i * sizeof(unsigned int)); | ||||||
|  |                     lt.extruders.front() = last_extruder_id; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |         last_extruder_id = lt.extruders.back(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Reindex the extruders, so they are zero based, not 1 based.
 | ||||||
|  |     for (LayerTools < : layers) | ||||||
|  |         for (unsigned int &extruder_id : lt.extruders) { | ||||||
|  |             assert(extruder_id > 0); | ||||||
|  |             -- extruder_id; | ||||||
|  |         } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void fill_wipe_tower_partitions(std::vector<LayerTools> &layers) | ||||||
|  | { | ||||||
|  |     if (layers.empty()) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     // Count the minimum number of tool changes per layer.
 | ||||||
|  |     for (LayerTools < : layers) | ||||||
|  |         lt.wipe_tower_partitions = std::max<int>(0, int(layers.front().extruders.size()) - 1); | ||||||
|  | 
 | ||||||
|  |     // In case a distinct set of tools are used between two layers, there will be an additional tool change at the start of a layer.
 | ||||||
|  |     //FIXME this does not minimize the number of tool changes in worst case.
 | ||||||
|  |     for (size_t i = 1; i < layers.size(); ++ i) | ||||||
|  |         if (layers[i-1].extruders.back() != layers[i].extruders.front()) | ||||||
|  |             ++ layers[i].wipe_tower_partitions; | ||||||
|  | 
 | ||||||
|  |     // Propagate the wipe tower partitions down to support the upper partitions by the lower partitions.
 | ||||||
|  |     for (int i = int(layers.size()) - 2; i >= 0; -- i) | ||||||
|  |         layers[i].wipe_tower_partitions = std::max(layers[i + 1].wipe_tower_partitions, layers[i].wipe_tower_partitions); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // For the use case when each object is printed separately
 | ||||||
|  | // (print.config.complete_objects is true).
 | ||||||
|  | std::vector<LayerTools> tool_ordering(PrintObject &object) | ||||||
|  | { | ||||||
|  |     // Initialize the print layers for just a single object.
 | ||||||
|  |     std::vector<LayerTools> layers; | ||||||
|  |     { | ||||||
|  |         std::vector<coordf_t> zs; | ||||||
|  |         zs.reserve(zs.size() + object.layers.size() + object.support_layers.size()); | ||||||
|  |         for (auto layer : object.layers) | ||||||
|  |             zs.emplace_back(layer->print_z); | ||||||
|  |         for (auto layer : object.support_layers) | ||||||
|  |             zs.emplace_back(layer->print_z); | ||||||
|  |         sort_remove_duplicates(zs); | ||||||
|  |         for (coordf_t z : zs) | ||||||
|  |             layers.emplace_back(LayerTools(z)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Collect extruders reuqired to print the layers.
 | ||||||
|  |     collect_extruders(object, layers); | ||||||
|  | 
 | ||||||
|  |     // Reorder the extruders to minimize tool switches.
 | ||||||
|  |     reorder_extruders(layers); | ||||||
|  | 
 | ||||||
|  |     fill_wipe_tower_partitions(layers); | ||||||
|  |     return layers; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // For the use case when all objects are printed at once.
 | ||||||
|  | // (print.config.complete_objects is false).
 | ||||||
|  | std::vector<LayerTools> tool_ordering(const Print &print) | ||||||
|  | { | ||||||
|  |     // Initialize the print layers for all objects and all layers. 
 | ||||||
|  |     std::vector<LayerTools> layers; | ||||||
|  |     { | ||||||
|  |         std::vector<coordf_t> zs; | ||||||
|  |         for (auto object : print.objects) { | ||||||
|  |             zs.reserve(zs.size() + object->layers.size() + object->support_layers.size()); | ||||||
|  |             for (auto layer : object->layers) | ||||||
|  |                 zs.emplace_back(layer->print_z); | ||||||
|  |             for (auto layer : object->support_layers) | ||||||
|  |                 zs.emplace_back(layer->print_z); | ||||||
|  |         } | ||||||
|  |         sort_remove_duplicates(zs); | ||||||
|  |         for (coordf_t z : zs) | ||||||
|  |             layers.emplace_back(LayerTools(z)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Collect extruders reuqired to print the layers.
 | ||||||
|  |     for (auto object : print.objects) | ||||||
|  |         collect_extruders(*object, layers); | ||||||
|  | 
 | ||||||
|  |     // Reorder the extruders to minimize tool switches.
 | ||||||
|  |     reorder_extruders(layers); | ||||||
|  | 
 | ||||||
|  |     fill_wipe_tower_partitions(layers); | ||||||
|  |     return layers; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace ToolOrdering
 | ||||||
|  | } // namespace Slic3r
 | ||||||
							
								
								
									
										38
									
								
								xs/src/libslic3r/GCode/ToolOrdering.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								xs/src/libslic3r/GCode/ToolOrdering.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,38 @@ | ||||||
|  | // Ordering of the tools to minimize tool switches.
 | ||||||
|  | 
 | ||||||
|  | #ifndef slic3r_ToolOrdering_hpp_ | ||||||
|  | #define slic3r_ToolOrdering_hpp_ | ||||||
|  | 
 | ||||||
|  | #include "libslic3r.h" | ||||||
|  | #include "Print.hpp" | ||||||
|  | 
 | ||||||
|  | namespace Slic3r { | ||||||
|  | namespace ToolOrdering { | ||||||
|  | 
 | ||||||
|  | struct LayerTools | ||||||
|  | { | ||||||
|  |     LayerTools(const coordf_t z) : print_z(z), wipe_tower_partitions(0) {} | ||||||
|  | 
 | ||||||
|  |     bool operator< (const LayerTools &rhs) const { return print_z <  rhs.print_z; } | ||||||
|  |     bool operator==(const LayerTools &rhs) const { return print_z == rhs.print_z; } | ||||||
|  | 
 | ||||||
|  | 	coordf_t 					print_z; | ||||||
|  | 	// Zero based extruder IDs, ordered to minimize tool switches.
 | ||||||
|  | 	std::vector<unsigned int> 	extruders; | ||||||
|  | 	// Number of wipe tower partitions to support the required number of tool switches
 | ||||||
|  | 	// and to support the wipe tower partitions above this one.
 | ||||||
|  |     size_t                      wipe_tower_partitions; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // For the use case when each object is printed separately
 | ||||||
|  | // (print.config.complete_objects is true).
 | ||||||
|  | extern std::vector<LayerTools> tool_ordering(PrintObject &object); | ||||||
|  | 
 | ||||||
|  | // For the use case when all objects are printed at once.
 | ||||||
|  | // (print.config.complete_objects is false).
 | ||||||
|  | extern std::vector<LayerTools> tool_ordering(const Print &print); | ||||||
|  | 
 | ||||||
|  | } // namespace ToolOrdering
 | ||||||
|  | } // namespace SLic3r
 | ||||||
|  | 
 | ||||||
|  | #endif /* slic3r_ToolOrdering_hpp_ */ | ||||||
							
								
								
									
										59
									
								
								xs/src/libslic3r/GCode/WipeTower.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								xs/src/libslic3r/GCode/WipeTower.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,59 @@ | ||||||
|  | #ifndef slic3r_WipeTower_hpp_ | ||||||
|  | #define slic3r_WipeTower_hpp_ | ||||||
|  | 
 | ||||||
|  | #include <utility> | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
|  | namespace Slic3r | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | // A pure virtual WipeTower definition.
 | ||||||
|  | class WipeTower | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	// Internal point class, to make the wipe tower independent from other slic3r modules.
 | ||||||
|  | 	// This is important for Prusa Research as we want to build the wipe tower post-processor independently from slic3r.
 | ||||||
|  | 	struct xy | ||||||
|  | 	{ | ||||||
|  | 		xy(float x = 0.f, float y = 0.f) : x(x), y(y) {} | ||||||
|  | 		xy  operator+(const xy &rhs) const { xy out(*this); out.x += rhs.x; out.y += rhs.y; return out; } | ||||||
|  | 		xy  operator-(const xy &rhs) const { xy out(*this); out.x -= rhs.x; out.y -= rhs.y; return out; } | ||||||
|  | 		xy& operator+=(const xy &rhs) { x += rhs.x; y += rhs.y; return *this; } | ||||||
|  | 		xy& operator-=(const xy &rhs) { x -= rhs.x; y -= rhs.y; return *this; } | ||||||
|  | 		float x; | ||||||
|  | 		float y; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	WipeTower() {} | ||||||
|  | 	virtual ~WipeTower() {} | ||||||
|  | 
 | ||||||
|  | 	// Return the wipe tower position.
 | ||||||
|  | 	virtual const xy& position() const = 0; | ||||||
|  | 
 | ||||||
|  | 	// The wipe tower is finished, there should be no more tool changes or wipe tower prints.
 | ||||||
|  | 	virtual bool 	  finished() const = 0; | ||||||
|  | 
 | ||||||
|  | 	// Switch to a next layer.
 | ||||||
|  | 	virtual void 	  set_layer( | ||||||
|  | 		// Print height of this layer.
 | ||||||
|  | 		float  print_z, | ||||||
|  | 		// Layer height, used to calculate extrusion the rate. 
 | ||||||
|  | 		float  layer_height,  | ||||||
|  | 		// Maximum number of tool changes on this layer or the layers below.
 | ||||||
|  | 		size_t max_tool_changes,  | ||||||
|  | 		// Is this the first layer of the print? In that case print the brim first.
 | ||||||
|  | 		bool   is_first_layer, | ||||||
|  | 		// Is this the last layer of the wipe tower?
 | ||||||
|  | 		bool   is_last_layer) = 0; | ||||||
|  | 
 | ||||||
|  | 	// Returns gcode for toolchange and the end position.
 | ||||||
|  | 	// if new_tool == -1, just unload the current filament over the wipe tower.
 | ||||||
|  | 	virtual std::pair<std::string, xy> tool_change(int new_tool) = 0; | ||||||
|  | 
 | ||||||
|  | 	// Close the current wipe tower layer with a perimeter and possibly fill the unfilled space with a zig-zag.
 | ||||||
|  | 	virtual std::pair<std::string, xy> close_layer() = 0; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | }; // namespace Slic3r
 | ||||||
|  | 
 | ||||||
|  | #endif /* slic3r_WipeTower_hpp_ */ | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| #include "WipeTower.hpp" | #include "WipeTowerPrusaMM.hpp" | ||||||
| 
 | 
 | ||||||
| #include <assert.h> | #include <assert.h> | ||||||
| #include <math.h> | #include <math.h> | ||||||
|  | @ -13,9 +13,11 @@ | ||||||
| #define strcasecmp _stricmp | #define strcasecmp _stricmp | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| namespace PrusaSingleExtruderMM | namespace Slic3r | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
|  | namespace PrusaMultiMaterial { | ||||||
|  | 
 | ||||||
| class Writer | class Writer | ||||||
| { | { | ||||||
| public: | public: | ||||||
|  | @ -171,18 +173,18 @@ public: | ||||||
| 		return *this; | 		return *this; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	Writer& comment_material(WipeTower::material_type material) | 	Writer& comment_material(WipeTowerPrusaMM::material_type material) | ||||||
| 	{ | 	{ | ||||||
| 		m_gcode += "; material : "; | 		m_gcode += "; material : "; | ||||||
| 		switch (material) | 		switch (material) | ||||||
| 		{ | 		{ | ||||||
| 		case WipeTower::PVA: | 		case WipeTowerPrusaMM::PVA: | ||||||
| 			m_gcode += "#8 (PVA)"; | 			m_gcode += "#8 (PVA)"; | ||||||
| 			break; | 			break; | ||||||
| 		case WipeTower::SCAFF: | 		case WipeTowerPrusaMM::SCAFF: | ||||||
| 			m_gcode += "#5 (Scaffold)"; | 			m_gcode += "#5 (Scaffold)"; | ||||||
| 			break; | 			break; | ||||||
| 		case WipeTower::FLEX: | 		case WipeTowerPrusaMM::FLEX: | ||||||
| 			m_gcode += "#4 (Flex)"; | 			m_gcode += "#4 (Flex)"; | ||||||
| 			break; | 			break; | ||||||
| 		default: | 		default: | ||||||
|  | @ -236,6 +238,8 @@ private: | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | } // namespace PrusaMultiMaterial
 | ||||||
|  | 
 | ||||||
| static inline int randi(int lo, int hi) | static inline int randi(int lo, int hi) | ||||||
| { | { | ||||||
| 	int n = hi - lo + 1; | 	int n = hi - lo + 1; | ||||||
|  | @ -244,7 +248,7 @@ static inline int randi(int lo, int hi) | ||||||
| 	return lo + i; | 	return lo + i; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| WipeTower::material_type WipeTower::parse_material(const char *name) | WipeTowerPrusaMM::material_type WipeTowerPrusaMM::parse_material(const char *name) | ||||||
| { | { | ||||||
| 	if (strcasecmp(name, "PLA") == 0) | 	if (strcasecmp(name, "PLA") == 0) | ||||||
| 		return PLA; | 		return PLA; | ||||||
|  | @ -267,116 +271,58 @@ WipeTower::material_type WipeTower::parse_material(const char *name) | ||||||
| 	return INVALID; | 	return INVALID; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::string WipeTower::FirstLayer(bool sideOnly, float y_offset) | std::pair<std::string, WipeTower::xy> WipeTowerPrusaMM::tool_change(int tool) | ||||||
| { | { | ||||||
| 	const box_coordinates wipeTower_box( | 	// Either it is the last tool unload,
 | ||||||
| 		m_wipe_tower_pos,  | 	// or there must be a nonzero wipe tower partitions available.
 | ||||||
| 		m_wipe_tower_width,  | 	assert(tool < 0 || it_layer_tools->wipe_tower_partitions > 0); | ||||||
| 		m_wipe_area * float(m_color_changes) - perimeterWidth / 2); |  | ||||||
| 
 | 
 | ||||||
| 	Writer writer; | 	if (m_layer_change_in_layer == size_t(-1)) | ||||||
| 	writer.set_extrusion_flow(extrusion_flow * 1.1f) | 		// First layer, prime the extruder.
 | ||||||
| 		  // Let the writer know the current Z position as a base for Z-hop.
 | 		return toolchange_Brim(tool); | ||||||
| 		  .set_z(m_z_pos) |  | ||||||
| 		  .append( |  | ||||||
| 			";-------------------------------------\n" |  | ||||||
| 			"; CP WIPE TOWER FIRST LAYER BRIM START\n"); |  | ||||||
| 
 | 
 | ||||||
| 	// Move with Z hop and prime the extruder 10*perimeterWidth left along the vertical edge of the wipe tower.
 |  | ||||||
| 	writer.z_hop(zHop, 7200) |  | ||||||
| 		  .travel(wipeTower_box.lu - xy(perimeterWidth * 10.f, 0), 6000) |  | ||||||
| 		  .z_hop(0, 7200) |  | ||||||
| 		  .extrude_explicit(wipeTower_box.ld - xy(perimeterWidth * 10.f, 0), retract, 2400) |  | ||||||
| 		  .feedrate(2100); |  | ||||||
| 
 |  | ||||||
| 	if (sideOnly) { |  | ||||||
| 		float x_offset = 0.f; |  | ||||||
| 		for (size_t i = 0; i < 4; ++ i, x_offset += perimeterWidth) |  | ||||||
| 			writer.travel (wipeTower_box.ld + xy(- x_offset,   y_offset)) |  | ||||||
| 				  .extrude(wipeTower_box.lu + xy(- x_offset, - y_offset)); |  | ||||||
| 		writer.travel(wipeTower_box.rd + xy(x_offset, y_offset), 7000) |  | ||||||
| 			  .feedrate(2100); |  | ||||||
| 		x_offset = 0.f; |  | ||||||
| 		for (size_t i = 0; i < 4; ++ i, x_offset += perimeterWidth) |  | ||||||
| 			writer.travel (wipeTower_box.rd + xy(x_offset,   y_offset)) |  | ||||||
| 				  .extrude(wipeTower_box.ru + xy(x_offset, - y_offset)); |  | ||||||
| 	} else { |  | ||||||
| 		// Extrude 4 rounds of a brim around the future wipe tower.
 |  | ||||||
| 		box_coordinates box(wipeTower_box); |  | ||||||
| 		box.ld += xy(- perimeterWidth / 2, 0); |  | ||||||
| 		box.lu += xy(- perimeterWidth / 2, perimeterWidth); |  | ||||||
| 		box.rd += xy(  perimeterWidth / 2, 0); |  | ||||||
| 		box.ru += xy(  perimeterWidth / 2, perimeterWidth); |  | ||||||
| 		for (size_t i = 0; i < 4; ++ i) { |  | ||||||
| 			writer.travel(box.ld) |  | ||||||
| 				  .extrude(box.lu) .extrude(box.ru) |  | ||||||
| 				  .extrude(box.rd) .extrude(box.ld); |  | ||||||
| 			box.expand(perimeterWidth); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Move to the front left corner and wipe along the front edge.
 |  | ||||||
| 	writer.travel(wipeTower_box.ld, 7000) |  | ||||||
| 		  .travel(wipeTower_box.rd) |  | ||||||
| 		  .travel(wipeTower_box.ld) |  | ||||||
| 		  .append("; CP WIPE TOWER FIRST LAYER BRIM END\n" |  | ||||||
| 			      ";-----------------------------------\n"); |  | ||||||
| 
 |  | ||||||
| 	return writer.gcode(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| std::pair<std::string, WipeTower::xy> WipeTower::Toolchange( |  | ||||||
| 	const int 			tool,  |  | ||||||
| 	const material_type current_material,  |  | ||||||
| 	const material_type new_material,  |  | ||||||
| 	const int 			temperature,  |  | ||||||
| 	const wipe_shape 	shape,  |  | ||||||
| 	const int 			count,  |  | ||||||
| 	const float 		spaceAvailable,  |  | ||||||
| 	const float 		wipeStartY,  |  | ||||||
| 	const bool  		lastInFile,  |  | ||||||
| 	const bool 			colorInit) |  | ||||||
| { |  | ||||||
| 	box_coordinates cleaning_box( | 	box_coordinates cleaning_box( | ||||||
| 		m_wipe_tower_pos.x, | 		m_wipe_tower_pos.x, | ||||||
| 		m_wipe_tower_pos.y + wipeStartY, | 		m_wipe_tower_pos.y + m_current_wipe_start_y, | ||||||
| 		m_wipe_tower_width,  | 		m_wipe_tower_width,  | ||||||
| 		spaceAvailable - perimeterWidth / 2); | 		m_wipe_area - m_perimeter_width / 2); | ||||||
| 
 | 
 | ||||||
| 	Writer writer; | 	PrusaMultiMaterial::Writer writer; | ||||||
| 	writer.set_extrusion_flow(extrusion_flow) | 	writer.set_extrusion_flow(m_extrusion_flow) | ||||||
| 		  .set_z(m_z_pos) | 		  .set_z(m_z_pos) | ||||||
| 		  .append(";--------------------\n" | 		  .append(";--------------------\n" | ||||||
| 			 	  "; CP TOOLCHANGE START\n") | 			 	  "; CP TOOLCHANGE START\n") | ||||||
| 		  .comment_with_value(" toolchange #", count) | 		  .comment_with_value(" toolchange #", m_layer_change_total) | ||||||
| 		  .comment_material(current_material) | 		  .comment_material(m_current_material) | ||||||
| 		  .append(";--------------------\n") | 		  .append(";--------------------\n") | ||||||
| 		  .speed_override(100) | 		  .speed_override(100) | ||||||
| 		  // Lift for a Z hop.
 | 		  // Lift for a Z hop.
 | ||||||
| 		  .z_hop(zHop, 7200) | 		  .z_hop(m_zhop, 7200) | ||||||
| 		  // additional retract on move to tower
 | 		  // additional retract on move to tower
 | ||||||
| 		  .retract(retract/2, 3600) | 		  .retract(m_retract/2, 3600) | ||||||
| 		  .travel(((shape == SHAPE_NORMAL) ? cleaning_box.ld : cleaning_box.rd) + xy(perimeterWidth, shape * perimeterWidth), 7200) | 		  .travel(((m_current_shape == SHAPE_NORMAL) ? cleaning_box.ld : cleaning_box.rd) + xy(m_perimeter_width, m_current_shape * m_perimeter_width), 7200) | ||||||
| 		  // Unlift for a Z hop.
 | 		  // Unlift for a Z hop.
 | ||||||
| 		  .z_hop(0, 7200) | 		  .z_hop(0, 7200) | ||||||
| 		  // Additional retract on move to tower.
 | 		  // Additional retract on move to tower.
 | ||||||
| 		  .deretract(retract/2, 3600) | 		  .deretract(m_retract/2, 3600) | ||||||
| 		  .deretract(retract, 1500) | 		  .deretract(m_retract, 1500) | ||||||
| 		  // Increase extruder current for ramming.
 | 		  // Increase extruder current for ramming.
 | ||||||
| 		  .set_extruder_trimpot(750) | 		  .set_extruder_trimpot(750) | ||||||
| 		  .flush_planner_queue(); | 		  .flush_planner_queue(); | ||||||
| 
 | 
 | ||||||
| 	// Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
 | 	// Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
 | ||||||
| 	toolchange_Unload(writer, cleaning_box, current_material, shape, temperature); | 	toolchange_Unload(writer, cleaning_box, m_current_material, m_current_shape,  | ||||||
|  | 		m_is_first_layer ? m_first_layer_temperature[tool]  : m_temperature[tool]); | ||||||
| 
 | 
 | ||||||
| 	if (! lastInFile) { | 	if (tool >= 0) { | ||||||
|  | 		// This is not the last change.
 | ||||||
| 		// Change the tool, set a speed override for solube and flex materials.
 | 		// Change the tool, set a speed override for solube and flex materials.
 | ||||||
| 		toolchange_Change(writer, tool, current_material, new_material); | 		toolchange_Change(writer, tool, m_current_material, m_material[tool]); | ||||||
| 		toolchange_Load(writer, cleaning_box, current_material, shape, colorInit); | 		toolchange_Load(writer, cleaning_box); | ||||||
| 		// Wipe the newly loaded filament until the end of the assigned wipe area.
 | 		// Wipe the newly loaded filament until the end of the assigned wipe area.
 | ||||||
| 		toolchange_Wipe(writer, cleaning_box, current_material, shape); | 		toolchange_Wipe(writer, cleaning_box, m_current_material); | ||||||
| 		// Draw a perimeter around cleaning_box and wipe.
 | 		// Draw a perimeter around cleaning_box and wipe.
 | ||||||
| 		toolchange_Done(writer, cleaning_box, current_material, shape); | 		toolchange_Done(writer, cleaning_box); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Reset the extruder current to a normal value.
 | 	// Reset the extruder current to a normal value.
 | ||||||
|  | @ -387,20 +333,83 @@ std::pair<std::string, WipeTower::xy> WipeTower::Toolchange( | ||||||
| 	 		      ";------------------\n" | 	 		      ";------------------\n" | ||||||
| 				  "\n\n"); | 				  "\n\n"); | ||||||
| 
 | 
 | ||||||
|  |     ++ m_layer_change_in_layer; | ||||||
|  |     m_current_wipe_start_y += m_wipe_area; | ||||||
|  |   	m_current_material = m_material[tool]; | ||||||
|  | 	return std::pair<std::string, xy>(writer.gcode(), writer.pos()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::pair<std::string, WipeTower::xy> WipeTowerPrusaMM::toolchange_Brim(size_t tool, bool sideOnly, float y_offset) | ||||||
|  | { | ||||||
|  | 	const box_coordinates wipeTower_box( | ||||||
|  | 		m_wipe_tower_pos, | ||||||
|  | 		m_wipe_tower_width, | ||||||
|  | 		m_wipe_area * float(m_max_color_changes) - m_perimeter_width / 2); | ||||||
|  | 
 | ||||||
|  | 	PrusaMultiMaterial::Writer writer; | ||||||
|  | 	writer.set_extrusion_flow(m_extrusion_flow * 1.1f) | ||||||
|  | 		  // Let the writer know the current Z position as a base for Z-hop.
 | ||||||
|  | 		  .set_z(m_z_pos) | ||||||
|  | 		  .append( | ||||||
|  | 			";-------------------------------------\n" | ||||||
|  | 			"; CP WIPE TOWER FIRST LAYER BRIM START\n"); | ||||||
|  | 
 | ||||||
|  | 	// Move with Z hop and prime the extruder 10*m_perimeter_width left along the vertical edge of the wipe tower.
 | ||||||
|  | 	writer.z_hop(m_zhop, 7200) | ||||||
|  | 		  .travel(wipeTower_box.lu - xy(m_perimeter_width * 10.f, 0), 6000) | ||||||
|  | 		  .z_hop(0, 7200) | ||||||
|  | 		  .extrude_explicit(wipeTower_box.ld - xy(m_perimeter_width * 10.f, 0), m_retract, 2400) | ||||||
|  | 		  .feedrate(2100); | ||||||
|  | 
 | ||||||
|  | 	toolchange_Change(writer, tool, m_current_material, m_material[tool]); | ||||||
|  | 
 | ||||||
|  | 	if (sideOnly) { | ||||||
|  | 		float x_offset = 0.f; | ||||||
|  | 		for (size_t i = 0; i < 4; ++ i, x_offset += m_perimeter_width) | ||||||
|  | 			writer.travel (wipeTower_box.ld + xy(- x_offset,   y_offset)) | ||||||
|  | 				  .extrude(wipeTower_box.lu + xy(- x_offset, - y_offset)); | ||||||
|  | 		writer.travel(wipeTower_box.rd + xy(x_offset, y_offset), 7000) | ||||||
|  | 			  .feedrate(2100); | ||||||
|  | 		x_offset = 0.f; | ||||||
|  | 		for (size_t i = 0; i < 4; ++ i, x_offset += m_perimeter_width) | ||||||
|  | 			writer.travel (wipeTower_box.rd + xy(x_offset,   y_offset)) | ||||||
|  | 				  .extrude(wipeTower_box.ru + xy(x_offset, - y_offset)); | ||||||
|  | 	} else { | ||||||
|  | 		// Extrude 4 rounds of a brim around the future wipe tower.
 | ||||||
|  | 		box_coordinates box(wipeTower_box); | ||||||
|  | 		box.ld += xy(- m_perimeter_width / 2, 0); | ||||||
|  | 		box.lu += xy(- m_perimeter_width / 2, m_perimeter_width); | ||||||
|  | 		box.rd += xy(  m_perimeter_width / 2, 0); | ||||||
|  | 		box.ru += xy(  m_perimeter_width / 2, m_perimeter_width); | ||||||
|  | 		for (size_t i = 0; i < 4; ++ i) { | ||||||
|  | 			writer.travel(box.ld) | ||||||
|  | 				  .extrude(box.lu) .extrude(box.ru) | ||||||
|  | 				  .extrude(box.rd) .extrude(box.ld); | ||||||
|  | 			box.expand(m_perimeter_width); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Move to the front left corner and wipe along the front edge.
 | ||||||
|  | 	writer.travel(wipeTower_box.ld, 7000) | ||||||
|  | 		  .travel(wipeTower_box.rd) | ||||||
|  | 		  .travel(wipeTower_box.ld) | ||||||
|  | 		  .append("; CP WIPE TOWER FIRST LAYER BRIM END\n" | ||||||
|  | 			      ";-----------------------------------\n"); | ||||||
|  | 
 | ||||||
| 	return std::pair<std::string, xy>(writer.gcode(), writer.pos()); | 	return std::pair<std::string, xy>(writer.gcode(), writer.pos()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
 | // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
 | ||||||
| void WipeTower::toolchange_Unload( | void WipeTowerPrusaMM::toolchange_Unload( | ||||||
| 	Writer 				    &writer, | 	PrusaMultiMaterial::Writer &writer, | ||||||
| 	const box_coordinates 	&cleaning_box, | 	const box_coordinates 	&cleaning_box, | ||||||
| 	const material_type		 material, | 	const material_type		 material, | ||||||
| 	const wipe_shape 	     shape, | 	const wipe_shape 	     shape, | ||||||
| 	const int 				 temperature) | 	const int 				 temperature) | ||||||
| { | { | ||||||
| 	float xl = cleaning_box.ld.x + (perimeterWidth / 2); | 	float xl = cleaning_box.ld.x + (m_perimeter_width / 2); | ||||||
| 	float xr = cleaning_box.rd.x - (perimeterWidth / 2); | 	float xr = cleaning_box.rd.x - (m_perimeter_width / 2); | ||||||
| 	float y_step = shape * perimeterWidth; | 	float y_step = shape * m_perimeter_width; | ||||||
| 
 | 
 | ||||||
| 	writer.append("; CP TOOLCHANGE UNLOAD"); | 	writer.append("; CP TOOLCHANGE UNLOAD"); | ||||||
| 
 | 
 | ||||||
|  | @ -409,20 +418,20 @@ void WipeTower::toolchange_Unload( | ||||||
| 	{ | 	{ | ||||||
| 	case PVA: | 	case PVA: | ||||||
|    		// ramming          start                    end                  y increment     amount feedrate
 |    		// ramming          start                    end                  y increment     amount feedrate
 | ||||||
| 		writer.ram(xl + perimeterWidth * 2, xr - perimeterWidth,     y_step * 1.2f, 3,     4000) | 		writer.ram(xl + m_perimeter_width * 2, xr - m_perimeter_width,     y_step * 1.2f, 3,     4000) | ||||||
| 			  .ram(xr - perimeterWidth,     xl + perimeterWidth,     y_step * 1.5f, 3,     4500) | 			  .ram(xr - m_perimeter_width,     xl + m_perimeter_width,     y_step * 1.5f, 3,     4500) | ||||||
| 			  .ram(xl + perimeterWidth * 2, xr - perimeterWidth * 2, y_step * 1.5f, 3,     4800) | 			  .ram(xl + m_perimeter_width * 2, xr - m_perimeter_width * 2, y_step * 1.5f, 3,     4800) | ||||||
| 			  .ram(xr - perimeterWidth,     xl + perimeterWidth,     y_step * 1.5f, 3,     5000); | 			  .ram(xr - m_perimeter_width,     xl + m_perimeter_width,     y_step * 1.5f, 3,     5000); | ||||||
| 		break; | 		break; | ||||||
| 	case SCAFF: | 	case SCAFF: | ||||||
| 		writer.ram(xl + perimeterWidth * 2, xr - perimeterWidth,     y_step * 3.f,  3,     4000) | 		writer.ram(xl + m_perimeter_width * 2, xr - m_perimeter_width,     y_step * 3.f,  3,     4000) | ||||||
| 			  .ram(xr - perimeterWidth,     xl + perimeterWidth,     y_step * 3.f,  4,     4600) | 			  .ram(xr - m_perimeter_width,     xl + m_perimeter_width,     y_step * 3.f,  4,     4600) | ||||||
| 			  .ram(xl + perimeterWidth * 2, xr - perimeterWidth * 2, y_step * 3.f,  4.5,   5200); | 			  .ram(xl + m_perimeter_width * 2, xr - m_perimeter_width * 2, y_step * 3.f,  4.5,   5200); | ||||||
| 		break; | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		writer.ram(xl + perimeterWidth * 2, xr - perimeterWidth,     y_step * 1.2f, 1.6f,  4000) | 		writer.ram(xl + m_perimeter_width * 2, xr - m_perimeter_width,     y_step * 1.2f, 1.6f,  4000) | ||||||
| 			  .ram(xr - perimeterWidth,     xl + perimeterWidth,     y_step * 1.2f, 1.65f, 4600) | 			  .ram(xr - m_perimeter_width,     xl + m_perimeter_width,     y_step * 1.2f, 1.65f, 4600) | ||||||
| 			  .ram(xl + perimeterWidth * 2, xr - perimeterWidth * 2, y_step * 1.2f, 1.74f, 5200); | 			  .ram(xl + m_perimeter_width * 2, xr - m_perimeter_width * 2, y_step * 1.2f, 1.74f, 5200); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Pull the filament end into a cooling tube.
 | 	// Pull the filament end into a cooling tube.
 | ||||||
|  | @ -462,8 +471,8 @@ void WipeTower::toolchange_Unload( | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Change the tool, set a speed override for solube and flex materials.
 | // Change the tool, set a speed override for solube and flex materials.
 | ||||||
| void WipeTower::toolchange_Change( | void WipeTowerPrusaMM::toolchange_Change( | ||||||
| 	Writer 		   &writer, | 	PrusaMultiMaterial::Writer &writer, | ||||||
| 	const int 		tool,  | 	const int 		tool,  | ||||||
| 	material_type  /* current_material */,  | 	material_type  /* current_material */,  | ||||||
| 	material_type 	new_material) | 	material_type 	new_material) | ||||||
|  | @ -481,15 +490,12 @@ void WipeTower::toolchange_Change( | ||||||
| 	      .flush_planner_queue(); | 	      .flush_planner_queue(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WipeTower::toolchange_Load( | void WipeTowerPrusaMM::toolchange_Load( | ||||||
| 	Writer                 &writer, | 	PrusaMultiMaterial::Writer &writer, | ||||||
| 	const box_coordinates  &cleaning_box,  | 	const box_coordinates  &cleaning_box) | ||||||
| 	const material_type 	/* material */, |  | ||||||
| 	const wipe_shape 		shape, |  | ||||||
| 	const bool 				colorInit) |  | ||||||
| { | { | ||||||
| 	float xl = cleaning_box.ld.x + perimeterWidth; | 	float xl = cleaning_box.ld.x + m_perimeter_width; | ||||||
| 	float xr = cleaning_box.rd.x - perimeterWidth; | 	float xr = cleaning_box.rd.x - m_perimeter_width; | ||||||
| 
 | 
 | ||||||
| 	writer.append("; CP TOOLCHANGE LOAD\n") | 	writer.append("; CP TOOLCHANGE LOAD\n") | ||||||
| 	// Load the filament while moving left / right,
 | 	// Load the filament while moving left / right,
 | ||||||
|  | @ -501,11 +507,12 @@ void WipeTower::toolchange_Load( | ||||||
| 
 | 
 | ||||||
| 	// Extrude first five lines (just three lines if colorInit is set).
 | 	// Extrude first five lines (just three lines if colorInit is set).
 | ||||||
| 	writer.extrude(xr, writer.y(), 1600); | 	writer.extrude(xr, writer.y(), 1600); | ||||||
|  | 	bool colorInit = false; | ||||||
| 	size_t pass = colorInit ? 1 : 2; | 	size_t pass = colorInit ? 1 : 2; | ||||||
| 	for (int i = 0; i < pass; ++ i) | 	for (int i = 0; i < pass; ++ i) | ||||||
| 		writer.travel (xr, writer.y() + shape * perimeterWidth * 0.85f, 2200) | 		writer.travel (xr, writer.y() + m_current_shape * m_perimeter_width * 0.85f, 2200) | ||||||
| 			  .extrude(xl, writer.y()) | 			  .extrude(xl, writer.y()) | ||||||
| 			  .travel (xl, writer.y() + shape * perimeterWidth * 0.85f) | 			  .travel (xl, writer.y() + m_current_shape * m_perimeter_width * 0.85f) | ||||||
| 			  .extrude(xr, writer.y()); | 			  .extrude(xr, writer.y()); | ||||||
| 
 | 
 | ||||||
| 	// Reset the extruder current to the normal value.
 | 	// Reset the extruder current to the normal value.
 | ||||||
|  | @ -513,52 +520,49 @@ void WipeTower::toolchange_Load( | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Wipe the newly loaded filament until the end of the assigned wipe area.
 | // Wipe the newly loaded filament until the end of the assigned wipe area.
 | ||||||
| void WipeTower::toolchange_Wipe( | void WipeTowerPrusaMM::toolchange_Wipe( | ||||||
| 	Writer                 &writer, | 	PrusaMultiMaterial::Writer &writer, | ||||||
| 	const box_coordinates  &cleaning_box, | 	const box_coordinates  &cleaning_box, | ||||||
| 	const material_type 	material, | 	const material_type 	material) | ||||||
| 	const wipe_shape 	    shape) |  | ||||||
| { | { | ||||||
| 	// Increase flow on first layer, slow down print.
 | 	// Increase flow on first layer, slow down print.
 | ||||||
| 	writer.set_extrusion_flow(extrusion_flow * (is_first_layer() ? 1.18f : 1.f)) | 	writer.set_extrusion_flow(m_extrusion_flow * (m_is_first_layer ? 1.18f : 1.f)) | ||||||
| 		  .append("; CP TOOLCHANGE WIPE\n"); | 		  .append("; CP TOOLCHANGE WIPE\n"); | ||||||
| 	float wipe_coeff = is_first_layer() ? 0.5f : 1.f; | 	float wipe_coeff = m_is_first_layer ? 0.5f : 1.f; | ||||||
| 	float xl = cleaning_box.ld.x + 2.f * perimeterWidth; | 	float xl = cleaning_box.ld.x + 2.f * m_perimeter_width; | ||||||
| 	float xr = cleaning_box.rd.x - 2.f * perimeterWidth; | 	float xr = cleaning_box.rd.x - 2.f * m_perimeter_width; | ||||||
| 	// Wipe speed will increase up to 4800.
 | 	// Wipe speed will increase up to 4800.
 | ||||||
| 	float wipe_speed = 4200; | 	float wipe_speed = 4200; | ||||||
| 	// Y increment per wipe line.
 | 	// Y increment per wipe line.
 | ||||||
| 	float dy = shape * perimeterWidth * 0.7f; | 	float dy = m_current_shape * m_perimeter_width * 0.7f; | ||||||
| 	for (bool p = true; ; p = ! p) { | 	for (bool p = true; ; p = ! p) { | ||||||
| 		writer.feedrate((wipe_speed = std::min(4800.f, wipe_speed + 50.f)) * wipe_coeff); | 		writer.feedrate((wipe_speed = std::min(4800.f, wipe_speed + 50.f)) * wipe_coeff); | ||||||
| 		if (p) | 		if (p) | ||||||
| 			writer.extrude(xl - perimeterWidth/2, writer.y() + dy) | 			writer.extrude(xl - m_perimeter_width/2, writer.y() + dy) | ||||||
| 			      .extrude(xr + perimeterWidth,   writer.y()); | 			      .extrude(xr + m_perimeter_width,   writer.y()); | ||||||
| 		else | 		else | ||||||
| 			writer.extrude(xl - perimeterWidth,   writer.y() + dy) | 			writer.extrude(xl - m_perimeter_width,   writer.y() + dy) | ||||||
| 				  .extrude(xr + perimeterWidth*2, writer.y()); | 				  .extrude(xr + m_perimeter_width*2, writer.y()); | ||||||
| 		writer.feedrate((wipe_speed = std::min(4800.f, wipe_speed + 50.f)) * wipe_coeff) | 		writer.feedrate((wipe_speed = std::min(4800.f, wipe_speed + 50.f)) * wipe_coeff) | ||||||
| 			  .extrude(xr + perimeterWidth, writer.y() + dy) | 			  .extrude(xr + m_perimeter_width, writer.y() + dy) | ||||||
| 			  .extrude(xl - perimeterWidth, writer.y()); | 			  .extrude(xl - m_perimeter_width, writer.y()); | ||||||
| 		if ((shape == SHAPE_NORMAL) ? | 		if ((m_current_shape == SHAPE_NORMAL) ? | ||||||
| 			(writer.y() > cleaning_box.lu.y - perimeterWidth) : | 			(writer.y() > cleaning_box.lu.y - m_perimeter_width) : | ||||||
| 			(writer.y() < cleaning_box.ld.y + perimeterWidth)) | 			(writer.y() < cleaning_box.ld.y + m_perimeter_width)) | ||||||
| 			// Next wipe line does not fit the cleaning box.
 | 			// Next wipe line does not fit the cleaning box.
 | ||||||
| 			break; | 			break; | ||||||
| 	} | 	} | ||||||
| 	// Reset the extrusion flow.
 | 	// Reset the extrusion flow.
 | ||||||
| 	writer.set_extrusion_flow(extrusion_flow); | 	writer.set_extrusion_flow(m_extrusion_flow); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Draw a perimeter around cleaning_box and wipe.
 | // Draw a perimeter around cleaning_box and wipe.
 | ||||||
| void WipeTower::toolchange_Done( | void WipeTowerPrusaMM::toolchange_Done( | ||||||
| 	Writer 					&writer, | 	PrusaMultiMaterial::Writer &writer, | ||||||
| 	const box_coordinates 	&cleaning_box, | 	const box_coordinates 	&cleaning_box) | ||||||
| 	const material_type 	/* material */,  |  | ||||||
| 	const wipe_shape 		 shape) |  | ||||||
| { | { | ||||||
| 	box_coordinates box = cleaning_box; | 	box_coordinates box = cleaning_box; | ||||||
| 	if (shape == SHAPE_REVERSED) { | 	if (m_current_shape == SHAPE_REVERSED) { | ||||||
| 		std::swap(box.lu, box.ld); | 		std::swap(box.lu, box.ld); | ||||||
| 		std::swap(box.ru, box.rd); | 		std::swap(box.ru, box.rd); | ||||||
| 	} | 	} | ||||||
|  | @ -572,82 +576,86 @@ void WipeTower::toolchange_Done( | ||||||
| 		  .feedrate(6000); | 		  .feedrate(6000); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::string WipeTower::Perimeter(int order, int total, int Layer, bool afterToolchange, int firstLayerOffset) | std::pair<std::string, WipeTower::xy> WipeTowerPrusaMM::close_layer() | ||||||
| { | { | ||||||
| 	Writer writer; | 	PrusaMultiMaterial::Writer writer; | ||||||
| 	writer.set_extrusion_flow(extrusion_flow) | 	writer.set_extrusion_flow(m_extrusion_flow) | ||||||
| 		  .set_z(m_z_pos) | 		  .set_z(m_z_pos) | ||||||
| 		  .append(";--------------------\n" | 		  .append(";--------------------\n" | ||||||
| 				  "; CP EMPTY GRID START\n") | 				  "; CP EMPTY GRID START\n") | ||||||
| 		  .comment_with_value(" layer #", Layer); | 		  .comment_with_value(" layer #", m_layer_change_total ++); | ||||||
| 
 | 
 | ||||||
| 	// Slow down on the 1st layer.
 | 	// Slow down on the 1st layer.
 | ||||||
| 	float speed_factor = is_first_layer() ? 0.5f : 1.f; | 	float speed_factor = m_is_first_layer ? 0.5f : 1.f; | ||||||
| 
 | 
 | ||||||
| 	box_coordinates _p  = _boxForColor(order); | 	box_coordinates _p  = _boxForColor(m_layer_change_in_layer); | ||||||
| 	{ | 	{ | ||||||
| 		box_coordinates _to = _boxForColor(total); | 		box_coordinates _to = _boxForColor(m_max_color_changes); | ||||||
|  | 		float firstLayerOffset = 0.f; | ||||||
| 		_p.ld.y += firstLayerOffset; | 		_p.ld.y += firstLayerOffset; | ||||||
| 		_p.rd.y += firstLayerOffset; | 		_p.rd.y += firstLayerOffset; | ||||||
| 		_p.lu = _to.lu; _p.ru = _to.ru; | 		_p.lu = _to.lu; _p.ru = _to.ru; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (! afterToolchange) | 	if (m_layer_change_in_layer == 0) | ||||||
|  | 		// There were no tool changes at all in this layer.
 | ||||||
| 		// Jump with retract to _p.ld + a random shift in +x.
 | 		// Jump with retract to _p.ld + a random shift in +x.
 | ||||||
| 		writer.retract(retract * 1.5f, 3600) | 		writer.retract(m_retract * 1.5f, 3600) | ||||||
| 			  .z_hop(zHop, 7200) | 			  .z_hop(m_zhop, 7200) | ||||||
| 			  .travel(_p.ld.x + randi(5, 20), _p.ld.y, 7000) | 			  .travel(_p.ld.x + randi(5, 20), _p.ld.y, 7000) | ||||||
| 			  .z_hop(0, 7200) | 			  .z_hop(0, 7200) | ||||||
| 			  .extrude_explicit(_p.ld, retract * 1.5f, 3600); | 			  .extrude_explicit(_p.ld, m_retract * 1.5f, 3600); | ||||||
| 
 | 
 | ||||||
| 	box_coordinates box = _p; | 	box_coordinates box = _p; | ||||||
| 	writer.extrude(box.lu, 2400 * speed_factor) | 	writer.extrude(box.lu, 2400 * speed_factor) | ||||||
| 		  .extrude(box.ru) | 		  .extrude(box.ru) | ||||||
| 		  .extrude(box.rd) | 		  .extrude(box.rd) | ||||||
| 		  .extrude(box.ld + xy(perimeterWidth / 2, 0)); | 		  .extrude(box.ld + xy(m_perimeter_width / 2, 0)); | ||||||
| 
 | 
 | ||||||
| 	box.expand(- perimeterWidth / 2); | 	box.expand(- m_perimeter_width / 2); | ||||||
| 	writer.extrude(box.lu, 3200 * speed_factor) | 	writer.extrude(box.lu, 3200 * speed_factor) | ||||||
| 		  .extrude(box.ru) | 		  .extrude(box.ru) | ||||||
| 		  .extrude(box.rd) | 		  .extrude(box.rd) | ||||||
| 		  .extrude(box.ld + xy(perimeterWidth / 2, 0)) | 		  .extrude(box.ld + xy(m_perimeter_width / 2, 0)) | ||||||
| 		  .extrude(box.ld + xy(perimeterWidth / 2, perimeterWidth / 2)); | 		  .extrude(box.ld + xy(m_perimeter_width / 2, m_perimeter_width / 2)); | ||||||
| 
 | 
 | ||||||
| 	writer.extrude(_p.ld + xy(perimeterWidth * 3,   perimeterWidth), 2900 * speed_factor) | 	writer.extrude(_p.ld + xy(m_perimeter_width * 3,   m_perimeter_width), 2900 * speed_factor) | ||||||
| 	      .extrude(_p.lu + xy(perimeterWidth * 3, - perimeterWidth)) | 	      .extrude(_p.lu + xy(m_perimeter_width * 3, - m_perimeter_width)) | ||||||
| 		  .extrude(_p.lu + xy(perimeterWidth * 6, - perimeterWidth)) | 		  .extrude(_p.lu + xy(m_perimeter_width * 6, - m_perimeter_width)) | ||||||
| 		  .extrude(_p.ld + xy(perimeterWidth * 6,   perimeterWidth)); | 		  .extrude(_p.ld + xy(m_perimeter_width * 6,   m_perimeter_width)); | ||||||
| 
 | 
 | ||||||
| 	if (_p.lu.y - _p.ld.y > 4) { | 	if (_p.lu.y - _p.ld.y > 4) { | ||||||
| 		// Extrude three zig-zags.
 | 		// Extrude three zig-zags.
 | ||||||
| 		writer.feedrate(3200 * speed_factor); | 		writer.feedrate(3200 * speed_factor); | ||||||
| 		float step = (m_wipe_tower_width - perimeterWidth * 12.f) / 12.f; | 		float step = (m_wipe_tower_width - m_perimeter_width * 12.f) / 12.f; | ||||||
| 		for (size_t i = 0; i < 3; ++ i) { | 		for (size_t i = 0; i < 3; ++ i) { | ||||||
| 			writer.extrude(writer.x() + step, _p.ld.y + perimeterWidth * 8); | 			writer.extrude(writer.x() + step, _p.ld.y + m_perimeter_width * 8); | ||||||
| 			writer.extrude(writer.x()       , _p.lu.y - perimeterWidth * 8); | 			writer.extrude(writer.x()       , _p.lu.y - m_perimeter_width * 8); | ||||||
| 			writer.extrude(writer.x() + step, _p.lu.y - perimeterWidth    ); | 			writer.extrude(writer.x() + step, _p.lu.y - m_perimeter_width    ); | ||||||
| 			writer.extrude(writer.x() + step, _p.lu.y - perimeterWidth * 8); | 			writer.extrude(writer.x() + step, _p.lu.y - m_perimeter_width * 8); | ||||||
| 			writer.extrude(writer.x()       , _p.ld.y + perimeterWidth * 8); | 			writer.extrude(writer.x()       , _p.ld.y + m_perimeter_width * 8); | ||||||
| 			writer.extrude(writer.x() + step, _p.ld.y + perimeterWidth    ); | 			writer.extrude(writer.x() + step, _p.ld.y + m_perimeter_width    ); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	writer.extrude(_p.ru + xy(- perimeterWidth * 6, - perimeterWidth), 2900 * speed_factor) | 	// Extrude the perimeter.
 | ||||||
| 		  .extrude(_p.ru + xy(- perimeterWidth * 3, - perimeterWidth)) | 	writer.extrude(_p.ru + xy(- m_perimeter_width * 6, - m_perimeter_width), 2900 * speed_factor) | ||||||
| 		  .extrude(_p.rd + xy(- perimeterWidth * 3,   perimeterWidth)) | 		  .extrude(_p.ru + xy(- m_perimeter_width * 3, - m_perimeter_width)) | ||||||
| 		  .extrude(_p.rd + xy(- perimeterWidth,       perimeterWidth)) | 		  .extrude(_p.rd + xy(- m_perimeter_width * 3,   m_perimeter_width)) | ||||||
|  | 		  .extrude(_p.rd + xy(- m_perimeter_width,       m_perimeter_width)) | ||||||
|        	  // Wipe along the front side of the current wiping box.
 |        	  // Wipe along the front side of the current wiping box.
 | ||||||
| 		  .travel(_p.ld + xy(  perimeterWidth, perimeterWidth / 2), 7200) | 		  .travel(_p.ld + xy(  m_perimeter_width, m_perimeter_width / 2), 7200) | ||||||
| 		  .travel(_p.rd + xy(- perimeterWidth, perimeterWidth / 2)) | 		  .travel(_p.rd + xy(- m_perimeter_width, m_perimeter_width / 2)) | ||||||
| 		  .append("; CP EMPTY GRID END\n" | 		  .append("; CP EMPTY GRID END\n" | ||||||
| 			      ";------------------\n\n\n\n\n\n\n"); | 			      ";------------------\n\n\n\n\n\n\n"); | ||||||
| 
 | 
 | ||||||
| 	return writer.gcode(); | 	m_current_shape = wipe_shape(- m_current_shape); | ||||||
|  | 	return std::pair<std::string, xy>(writer.gcode(), writer.pos()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| WipeTower::box_coordinates WipeTower::_boxForColor(int order) const | WipeTowerPrusaMM::box_coordinates WipeTowerPrusaMM::_boxForColor(int order) const | ||||||
| { | { | ||||||
| 	return box_coordinates(m_wipe_tower_pos.x, m_wipe_tower_pos.y + m_wipe_area * order - perimeterWidth / 2, m_wipe_tower_width, perimeterWidth); | 	return box_coordinates(m_wipe_tower_pos.x, m_wipe_tower_pos.y + m_wipe_area * order - m_perimeter_width / 2, m_wipe_tower_width, m_perimeter_width); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| }; // namespace PrusaSingleExtruderMM
 | }; // namespace Slic3r
 | ||||||
							
								
								
									
										217
									
								
								xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,217 @@ | ||||||
|  | #ifndef WipeTowerPrusaMM_hpp_ | ||||||
|  | #define WipeTowerPrusaMM_hpp_ | ||||||
|  | 
 | ||||||
|  | #include <algorithm> | ||||||
|  | #include <string> | ||||||
|  | #include <utility> | ||||||
|  | 
 | ||||||
|  | #include "WipeTower.hpp" | ||||||
|  | 
 | ||||||
|  | namespace Slic3r | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | namespace PrusaMultiMaterial { | ||||||
|  | 	class Writer; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | class WipeTowerPrusaMM : public WipeTower | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	enum material_type | ||||||
|  | 	{ | ||||||
|  | 		INVALID = -1, | ||||||
|  | 		PLA   = 0,		// E:210C	B:55C
 | ||||||
|  | 		ABS   = 1,		// E:255C	B:100C
 | ||||||
|  | 		PET   = 2,		// E:240C	B:90C
 | ||||||
|  | 		HIPS  = 3,		// E:220C	B:100C
 | ||||||
|  | 		FLEX  = 4,		// E:245C	B:80C
 | ||||||
|  | 		SCAFF = 5,		// E:215C	B:55C
 | ||||||
|  | 		EDGE  = 6,		// E:240C	B:80C
 | ||||||
|  | 		NGEN  = 7,		// E:230C	B:80C
 | ||||||
|  | 		PVA   = 8	    // E:210C	B:80C
 | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	// Parse material name into material_type.
 | ||||||
|  | 	static material_type parse_material(const char *name); | ||||||
|  | 
 | ||||||
|  | 	// x			-- x coordinates of wipe tower in mm ( left bottom corner )
 | ||||||
|  | 	// y			-- y coordinates of wipe tower in mm ( left bottom corner )
 | ||||||
|  | 	// width		-- width of wipe tower in mm ( default 60 mm - leave as it is )
 | ||||||
|  | 	// wipe_area	-- space available for one toolchange in mm
 | ||||||
|  | 	WipeTowerPrusaMM(float x, float y, float width, float wipe_area) : | ||||||
|  | 		m_wipe_tower_pos(x, y), | ||||||
|  | 		m_wipe_tower_width(width), | ||||||
|  | 		m_wipe_area(wipe_area), | ||||||
|  | 		m_z_pos(0.f) { | ||||||
|  | 		for (size_t i = 0; i < 4; ++ i) { | ||||||
|  | 			// Extruder specific parameters.
 | ||||||
|  | 			m_material[i] = PLA; | ||||||
|  | 			m_temperature[i] = 0; | ||||||
|  | 			m_first_layer_temperature[i] = 0; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	virtual ~WipeTowerPrusaMM() {} | ||||||
|  | 
 | ||||||
|  | 	// _retract - retract value in mm
 | ||||||
|  | 	void set_retract(float retract) { m_retract = retract; } | ||||||
|  | 	 | ||||||
|  | 	// _zHop - z hop value in mm
 | ||||||
|  | 	void set_zhop(float zhop) { m_zhop = zhop; } | ||||||
|  | 
 | ||||||
|  | 	// Set the extruder properties.
 | ||||||
|  | 	void set_extruder(size_t idx, material_type material, int temp, int first_layer_temp) | ||||||
|  | 	{ | ||||||
|  | 		m_material[idx] = material; | ||||||
|  | 		m_temperature[idx] = temp; | ||||||
|  | 		m_first_layer_temperature[idx] = first_layer_temp; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Switch to a next layer.
 | ||||||
|  | 	virtual void set_layer( | ||||||
|  | 		// Print height of this layer.
 | ||||||
|  | 		float  print_z, | ||||||
|  | 		// Layer height, used to calculate extrusion the rate. 
 | ||||||
|  | 		float  layer_height,  | ||||||
|  | 		// Maximum number of tool changes on this layer or the layers below.
 | ||||||
|  | 		size_t max_tool_changes,  | ||||||
|  | 		// Is this the first layer of the print? In that case print the brim first.
 | ||||||
|  | 		bool   is_first_layer, | ||||||
|  | 		// Is this the last layer of the waste tower?
 | ||||||
|  | 		bool   is_last_layer) | ||||||
|  | 	{ | ||||||
|  | 		m_z_pos 				= print_z; | ||||||
|  | 		m_max_color_changes 	= max_tool_changes; | ||||||
|  | 		m_is_first_layer 		= is_first_layer; | ||||||
|  | 		m_is_last_layer			= is_last_layer; | ||||||
|  | 		// Start counting the color changes from zero.
 | ||||||
|  | 		m_layer_change_in_layer = is_first_layer ? size_t(-1) : 0; | ||||||
|  | 		m_current_wipe_start_y  = 0.f; | ||||||
|  | 
 | ||||||
|  | 		int layer_idx = int(floor(layer_height * 100) + 0.5f); | ||||||
|  | 		switch (layer_idx) | ||||||
|  | 		{ | ||||||
|  | 		case 15: | ||||||
|  | 			m_extrusion_flow = (float)0.024; | ||||||
|  | 			break; | ||||||
|  | 		case 20: | ||||||
|  | 		default: | ||||||
|  | 			m_extrusion_flow = (float)0.029; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Return the wipe tower position.
 | ||||||
|  | 	virtual const xy& position() const { return m_wipe_tower_pos; } | ||||||
|  | 	// The wipe tower is finished, there should be no more tool changes or wipe tower prints.
 | ||||||
|  | 	virtual bool 	  finished() const { return m_max_color_changes == 0; } | ||||||
|  | 
 | ||||||
|  | 	// Returns gcode for toolchange 
 | ||||||
|  | 	virtual std::pair<std::string, xy> tool_change(int new_tool); | ||||||
|  | 
 | ||||||
|  | 	// Close the current wipe tower layer with a perimeter and possibly fill the unfilled space with a zig-zag.
 | ||||||
|  | 	virtual std::pair<std::string, xy> close_layer(); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  | 	WipeTowerPrusaMM(); | ||||||
|  | 
 | ||||||
|  | 	enum wipe_shape | ||||||
|  | 	{ | ||||||
|  | 		SHAPE_NORMAL   = 1, | ||||||
|  | 		SHAPE_REVERSED = -1 | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	// Left front corner of the wipe tower in mm.
 | ||||||
|  | 	xy     m_wipe_tower_pos; | ||||||
|  | 	// Width of the wipe tower.
 | ||||||
|  | 	float  m_wipe_tower_width; | ||||||
|  | 	// Per color Y span.
 | ||||||
|  | 	float  m_wipe_area; | ||||||
|  | 	// Current Z position.
 | ||||||
|  | 	float  m_z_pos 			= 0.f; | ||||||
|  | 	// Maximum number of color changes per layer.
 | ||||||
|  | 	size_t m_max_color_changes = 0; | ||||||
|  | 	// Is this the 1st layer of the print? If so, print the brim around the waste tower.
 | ||||||
|  | 	bool   m_is_first_layer = false; | ||||||
|  | 	// Is this the last layer of this waste tower?
 | ||||||
|  | 	bool   m_is_last_layer  = false; | ||||||
|  | 
 | ||||||
|  | 	// G-code generator parameters.
 | ||||||
|  | 	float  m_zhop 			 = 0.5f; | ||||||
|  | 	float  m_retract		 = 4.f; | ||||||
|  | 	float  m_perimeter_width = 0.5f; | ||||||
|  | 	float  m_extrusion_flow  = 0.029f; | ||||||
|  | 
 | ||||||
|  | 	// Extruder specific parameters.
 | ||||||
|  | 	material_type 	m_material[4]; | ||||||
|  | 	int  			m_temperature[4]; | ||||||
|  | 	int  			m_first_layer_temperature[4]; | ||||||
|  | 
 | ||||||
|  | 	// State of the wiper tower generator.
 | ||||||
|  | 	// Layer change counter for the output statistics.
 | ||||||
|  | 	unsigned int 	m_layer_change_total = 0; | ||||||
|  | 	// Layer change counter in this layer. Counting up to m_max_color_changes.
 | ||||||
|  | 	unsigned int 	m_layer_change_in_layer = 0; | ||||||
|  | 	wipe_shape   	m_current_shape = SHAPE_NORMAL; | ||||||
|  | 	material_type 	m_current_material = PLA; | ||||||
|  | 	// Current y position at the wipe tower.
 | ||||||
|  | 	float 		 	m_current_wipe_start_y = 0.f; | ||||||
|  | 
 | ||||||
|  | 	struct box_coordinates | ||||||
|  | 	{ | ||||||
|  | 		box_coordinates(float left, float bottom, float width, float height) : | ||||||
|  | 			ld(left        , bottom         ), | ||||||
|  | 			lu(left        , bottom + height), | ||||||
|  | 			rd(left + width, bottom         ), | ||||||
|  | 			ru(left + width, bottom + height) {} | ||||||
|  | 		box_coordinates(const xy &pos, float width, float height) : box_coordinates(pos.x, pos.y, width, height) {} | ||||||
|  | 		void expand(const float offset) { | ||||||
|  | 			ld += xy(- offset, - offset); | ||||||
|  | 			lu += xy(- offset,   offset); | ||||||
|  | 			rd += xy(  offset, - offset); | ||||||
|  | 			ru += xy(  offset,   offset); | ||||||
|  | 		} | ||||||
|  | 		xy ld;  // left down
 | ||||||
|  | 		xy lu;	// left upper 
 | ||||||
|  | 		xy ru;	// right upper
 | ||||||
|  | 		xy rd;	// right lower
 | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	// Returns gcode for wipe tower brim
 | ||||||
|  | 	// sideOnly			-- set to false -- experimental, draw brim on sides of wipe tower 
 | ||||||
|  | 	// offset			-- set to 0		-- experimental, offset to replace brim in front / rear of wipe tower
 | ||||||
|  | 	std::pair<std::string, WipeTower::xy> toolchange_Brim(size_t tool, bool sideOnly = false, float y_offset = 0.f); | ||||||
|  | 
 | ||||||
|  | 	void toolchange_Unload( | ||||||
|  | 		PrusaMultiMaterial::Writer &writer, | ||||||
|  | 		const box_coordinates  &cleaning_box,  | ||||||
|  | 		const material_type	 	material, | ||||||
|  | 		const wipe_shape 	    shape, | ||||||
|  | 		const int 				temperature); | ||||||
|  | 
 | ||||||
|  | 	void toolchange_Change( | ||||||
|  | 		PrusaMultiMaterial::Writer &writer, | ||||||
|  | 		int 					tool, | ||||||
|  | 		material_type 			current_material, | ||||||
|  | 		material_type 			new_material); | ||||||
|  | 	 | ||||||
|  | 	void toolchange_Load( | ||||||
|  | 		PrusaMultiMaterial::Writer &writer, | ||||||
|  | 		const box_coordinates  &cleaning_box); | ||||||
|  | 	 | ||||||
|  | 	void toolchange_Wipe( | ||||||
|  | 		PrusaMultiMaterial::Writer &writer, | ||||||
|  | 		const box_coordinates  &cleaning_box,  | ||||||
|  | 		const material_type 	material); | ||||||
|  | 	 | ||||||
|  | 	void toolchange_Done( | ||||||
|  | 		PrusaMultiMaterial::Writer &writer, | ||||||
|  | 		const box_coordinates  &cleaning_box); | ||||||
|  | 
 | ||||||
|  | 	void toolchange_Perimeter(); | ||||||
|  | 
 | ||||||
|  | 	box_coordinates _boxForColor(int order) const; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | }; // namespace Slic3r
 | ||||||
|  | 
 | ||||||
|  | #endif /* WipeTowerPrusaMM_hpp_ */ | ||||||
|  | @ -354,6 +354,37 @@ PrintConfigDef::PrintConfigDef() | ||||||
|         def->default_value = opt; |         def->default_value = opt; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     def = this->add("filament_type", coStrings); | ||||||
|  |     def->label = "Filament type"; | ||||||
|  |     def->tooltip = "If you want to process the output G-code through custom scripts, just list their absolute paths here. Separate multiple scripts with a semicolon. Scripts will be passed the absolute path to the G-code file as the first argument, and they can access the Slic3r config settings by reading environment variables."; | ||||||
|  |     def->cli = "filament_type=s@"; | ||||||
|  |     def->gui_type = "f_enum_open"; | ||||||
|  |     def->gui_flags = "show_value"; | ||||||
|  |     def->enum_values.push_back("PLA"); | ||||||
|  |     def->enum_values.push_back("ABS"); | ||||||
|  |     def->enum_values.push_back("PET"); | ||||||
|  |     def->enum_values.push_back("HIPS"); | ||||||
|  |     def->enum_values.push_back("FLEX"); | ||||||
|  |     def->enum_values.push_back("SCAFF"); | ||||||
|  |     def->enum_values.push_back("EDGE"); | ||||||
|  |     def->enum_values.push_back("NGEN"); | ||||||
|  |     def->enum_values.push_back("PVA"); | ||||||
|  |     { | ||||||
|  |         ConfigOptionStrings* opt = new ConfigOptionStrings(); | ||||||
|  |         opt->values.push_back("PLA"); | ||||||
|  |         def->default_value = opt; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     def = this->add("filament_soluble", coBools); | ||||||
|  |     def->label = "Soluble material"; | ||||||
|  |     def->tooltip = "Soluble material is most likely used for a soluble support."; | ||||||
|  |     def->cli = "filament-soluble!"; | ||||||
|  |     { | ||||||
|  |         ConfigOptionBools* opt = new ConfigOptionBools(); | ||||||
|  |         opt->values.push_back(false); | ||||||
|  |         def->default_value = opt; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     def = this->add("filament_cost", coFloats); |     def = this->add("filament_cost", coFloats); | ||||||
|     def->label = "Cost"; |     def->label = "Cost"; | ||||||
|     def->tooltip = "Enter your filament cost per kg here. This is only for statistical information."; |     def->tooltip = "Enter your filament cost per kg here. This is only for statistical information."; | ||||||
|  | @ -1168,6 +1199,12 @@ PrintConfigDef::PrintConfigDef() | ||||||
|     def->height = 120; |     def->height = 120; | ||||||
|     def->default_value = new ConfigOptionString("G28 ; home all axes\nG1 Z5 F5000 ; lift nozzle\n"); |     def->default_value = new ConfigOptionString("G28 ; home all axes\nG1 Z5 F5000 ; lift nozzle\n"); | ||||||
| 
 | 
 | ||||||
|  |     def = this->add("single_extruder_multi_material", coBool); | ||||||
|  |     def->label = "Single Extruder Multi Material"; | ||||||
|  |     def->tooltip = "The printer multiplexes filaments into a single hot end."; | ||||||
|  |     def->cli = "single-extruder-multi-material!"; | ||||||
|  |     def->default_value = new ConfigOptionBool(false); | ||||||
|  | 
 | ||||||
|     def = this->add("support_material", coBool); |     def = this->add("support_material", coBool); | ||||||
|     def->label = "Generate support material"; |     def->label = "Generate support material"; | ||||||
|     def->category = "Support material"; |     def->category = "Support material"; | ||||||
|  | @ -1454,6 +1491,40 @@ PrintConfigDef::PrintConfigDef() | ||||||
|         def->default_value = opt; |         def->default_value = opt; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     def = this->add("wipe_tower", coBool); | ||||||
|  |     def->label = "Enable"; | ||||||
|  |     def->tooltip = "Multi material printers may need to prime or purge extruders on tool changes. Extrude the excess material into the wipe tower."; | ||||||
|  |     def->cli = "wipe-tower!"; | ||||||
|  |     def->default_value = new ConfigOptionBool(false); | ||||||
|  | 
 | ||||||
|  |     def = this->add("wipe_tower_x", coFloat); | ||||||
|  |     def->label = "Position X"; | ||||||
|  |     def->tooltip = "X coordinate of the left front corner of a wipe tower"; | ||||||
|  |     def->sidetext = "mm"; | ||||||
|  |     def->cli = "wipe-tower-x=f"; | ||||||
|  |     def->default_value = new ConfigOptionFloat(180.); | ||||||
|  | 
 | ||||||
|  |     def = this->add("wipe_tower_y", coFloat); | ||||||
|  |     def->label = "Position Y"; | ||||||
|  |     def->tooltip = "Y coordinate of the left front corner of a wipe tower"; | ||||||
|  |     def->sidetext = "mm"; | ||||||
|  |     def->cli = "wipe-tower-y=f"; | ||||||
|  |     def->default_value = new ConfigOptionFloat(140.); | ||||||
|  | 
 | ||||||
|  |     def = this->add("wipe_tower_width", coFloat); | ||||||
|  |     def->label = "Width"; | ||||||
|  |     def->tooltip = "Width of a wipe tower"; | ||||||
|  |     def->sidetext = "mm"; | ||||||
|  |     def->cli = "wipe-tower-width=f"; | ||||||
|  |     def->default_value = new ConfigOptionFloat(60.); | ||||||
|  | 
 | ||||||
|  |     def = this->add("wipe_tower_per_color_wipe", coFloat); | ||||||
|  |     def->label = "Per color change depth"; | ||||||
|  |     def->tooltip = "Depth of a wipe color per color change. For N colors, there will be maximum (N-1) tool switches performed, therefore the total depth of the wipe tower will be (N-1) times this value."; | ||||||
|  |     def->sidetext = "mm"; | ||||||
|  |     def->cli = "wipe-tower-per-color-wipe=f"; | ||||||
|  |     def->default_value = new ConfigOptionFloat(15.); | ||||||
|  | 
 | ||||||
|     def = this->add("xy_size_compensation", coFloat); |     def = this->add("xy_size_compensation", coFloat); | ||||||
|     def->label = "XY Size Compensation"; |     def->label = "XY Size Compensation"; | ||||||
|     def->category = "Advanced"; |     def->category = "Advanced"; | ||||||
|  |  | ||||||
|  | @ -42,6 +42,10 @@ enum SeamPosition { | ||||||
|     spRandom, spNearest, spAligned, spRear |     spRandom, spNearest, spAligned, spRear | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | enum FilamentType { | ||||||
|  |     ftPLA, ftABS, ftPET, ftHIPS, ftFLEX, ftSCAFF, ftEDGE, ftNGEN, ftPVA | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| template<> inline t_config_enum_values ConfigOptionEnum<GCodeFlavor>::get_enum_values() { | template<> inline t_config_enum_values ConfigOptionEnum<GCodeFlavor>::get_enum_values() { | ||||||
|     t_config_enum_values keys_map; |     t_config_enum_values keys_map; | ||||||
|     keys_map["reprap"]          = gcfRepRap; |     keys_map["reprap"]          = gcfRepRap; | ||||||
|  | @ -91,6 +95,20 @@ template<> inline t_config_enum_values ConfigOptionEnum<SeamPosition>::get_enum_ | ||||||
|     return keys_map; |     return keys_map; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | template<> inline t_config_enum_values ConfigOptionEnum<FilamentType>::get_enum_values() { | ||||||
|  |     t_config_enum_values keys_map; | ||||||
|  |     keys_map["PLA"]             = ftPLA; | ||||||
|  |     keys_map["ABS"]             = ftABS; | ||||||
|  |     keys_map["PET"]             = ftPET; | ||||||
|  |     keys_map["HIPS"]            = ftHIPS; | ||||||
|  |     keys_map["FLEX"]            = ftFLEX; | ||||||
|  |     keys_map["SCAFF"]           = ftSCAFF; | ||||||
|  |     keys_map["EDGE"]            = ftEDGE; | ||||||
|  |     keys_map["NGEN"]            = ftNGEN; | ||||||
|  |     keys_map["PVA"]             = ftPVA; | ||||||
|  |     return keys_map; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // Defines each and every confiuration option of Slic3r, including the properties of the GUI dialogs.
 | // Defines each and every confiuration option of Slic3r, including the properties of the GUI dialogs.
 | ||||||
| // Does not store the actual values, but defines default values.
 | // Does not store the actual values, but defines default values.
 | ||||||
| class PrintConfigDef : public ConfigDef | class PrintConfigDef : public ConfigDef | ||||||
|  | @ -297,13 +315,15 @@ class PrintRegionConfig : public virtual StaticPrintConfig | ||||||
| // This object is mapped to Perl as Slic3r::Config::GCode.
 | // This object is mapped to Perl as Slic3r::Config::GCode.
 | ||||||
| class GCodeConfig : public virtual StaticPrintConfig | class GCodeConfig : public virtual StaticPrintConfig | ||||||
| { | { | ||||||
|     public: | public: | ||||||
|     ConfigOptionString              before_layer_gcode; |     ConfigOptionString              before_layer_gcode; | ||||||
|     ConfigOptionString              end_gcode; |     ConfigOptionString              end_gcode; | ||||||
|     ConfigOptionString              extrusion_axis; |     ConfigOptionString              extrusion_axis; | ||||||
|     ConfigOptionFloats              extrusion_multiplier; |     ConfigOptionFloats              extrusion_multiplier; | ||||||
|     ConfigOptionFloats              filament_diameter; |     ConfigOptionFloats              filament_diameter; | ||||||
|     ConfigOptionFloats              filament_density; |     ConfigOptionFloats              filament_density; | ||||||
|  |     ConfigOptionStrings             filament_type; | ||||||
|  |     ConfigOptionBools               filament_soluble; | ||||||
|     ConfigOptionFloats              filament_cost; |     ConfigOptionFloats              filament_cost; | ||||||
|     ConfigOptionFloats              filament_max_volumetric_speed; |     ConfigOptionFloats              filament_max_volumetric_speed; | ||||||
|     ConfigOptionBool                gcode_comments; |     ConfigOptionBool                gcode_comments; | ||||||
|  | @ -322,6 +342,7 @@ class GCodeConfig : public virtual StaticPrintConfig | ||||||
|     ConfigOptionFloats              retract_restart_extra_toolchange; |     ConfigOptionFloats              retract_restart_extra_toolchange; | ||||||
|     ConfigOptionFloats              retract_speed; |     ConfigOptionFloats              retract_speed; | ||||||
|     ConfigOptionString              start_gcode; |     ConfigOptionString              start_gcode; | ||||||
|  |     ConfigOptionBool                single_extruder_multi_material; | ||||||
|     ConfigOptionString              toolchange_gcode; |     ConfigOptionString              toolchange_gcode; | ||||||
|     ConfigOptionFloat               travel_speed; |     ConfigOptionFloat               travel_speed; | ||||||
|     ConfigOptionBool                use_firmware_retraction; |     ConfigOptionBool                use_firmware_retraction; | ||||||
|  | @ -341,6 +362,8 @@ class GCodeConfig : public virtual StaticPrintConfig | ||||||
|         OPT_PTR(extrusion_multiplier); |         OPT_PTR(extrusion_multiplier); | ||||||
|         OPT_PTR(filament_diameter); |         OPT_PTR(filament_diameter); | ||||||
|         OPT_PTR(filament_density); |         OPT_PTR(filament_density); | ||||||
|  |         OPT_PTR(filament_type); | ||||||
|  |         OPT_PTR(filament_soluble); | ||||||
|         OPT_PTR(filament_cost); |         OPT_PTR(filament_cost); | ||||||
|         OPT_PTR(filament_max_volumetric_speed); |         OPT_PTR(filament_max_volumetric_speed); | ||||||
|         OPT_PTR(gcode_comments); |         OPT_PTR(gcode_comments); | ||||||
|  | @ -358,6 +381,7 @@ class GCodeConfig : public virtual StaticPrintConfig | ||||||
|         OPT_PTR(retract_restart_extra); |         OPT_PTR(retract_restart_extra); | ||||||
|         OPT_PTR(retract_restart_extra_toolchange); |         OPT_PTR(retract_restart_extra_toolchange); | ||||||
|         OPT_PTR(retract_speed); |         OPT_PTR(retract_speed); | ||||||
|  |         OPT_PTR(single_extruder_multi_material); | ||||||
|         OPT_PTR(start_gcode); |         OPT_PTR(start_gcode); | ||||||
|         OPT_PTR(toolchange_gcode); |         OPT_PTR(toolchange_gcode); | ||||||
|         OPT_PTR(travel_speed); |         OPT_PTR(travel_speed); | ||||||
|  | @ -435,6 +459,11 @@ class PrintConfig : public GCodeConfig | ||||||
|     ConfigOptionInts                temperature; |     ConfigOptionInts                temperature; | ||||||
|     ConfigOptionInt                 threads; |     ConfigOptionInt                 threads; | ||||||
|     ConfigOptionBools               wipe; |     ConfigOptionBools               wipe; | ||||||
|  |     ConfigOptionBool                wipe_tower; | ||||||
|  |     ConfigOptionFloat               wipe_tower_x; | ||||||
|  |     ConfigOptionFloat               wipe_tower_y; | ||||||
|  |     ConfigOptionFloat               wipe_tower_width; | ||||||
|  |     ConfigOptionFloat               wipe_tower_per_color_wipe; | ||||||
|     ConfigOptionFloat               z_offset; |     ConfigOptionFloat               z_offset; | ||||||
|      |      | ||||||
|     PrintConfig(bool initialize = true) : GCodeConfig(false) { |     PrintConfig(bool initialize = true) : GCodeConfig(false) { | ||||||
|  | @ -494,6 +523,11 @@ class PrintConfig : public GCodeConfig | ||||||
|         OPT_PTR(temperature); |         OPT_PTR(temperature); | ||||||
|         OPT_PTR(threads); |         OPT_PTR(threads); | ||||||
|         OPT_PTR(wipe); |         OPT_PTR(wipe); | ||||||
|  |         OPT_PTR(wipe_tower); | ||||||
|  |         OPT_PTR(wipe_tower_x); | ||||||
|  |         OPT_PTR(wipe_tower_y); | ||||||
|  |         OPT_PTR(wipe_tower_width); | ||||||
|  |         OPT_PTR(wipe_tower_per_color_wipe); | ||||||
|         OPT_PTR(z_offset); |         OPT_PTR(z_offset); | ||||||
|          |          | ||||||
|         // look in parent class
 |         // look in parent class
 | ||||||
|  |  | ||||||
|  | @ -1,210 +0,0 @@ | ||||||
| #ifndef PrusaSingleExtruderMM_WipeTower_hpp_ |  | ||||||
| #define PrusaSingleExtruderMM_WipeTower_hpp_ |  | ||||||
| 
 |  | ||||||
| #include <algorithm> |  | ||||||
| #include <string> |  | ||||||
| #include <utility> |  | ||||||
| 
 |  | ||||||
| namespace PrusaSingleExtruderMM |  | ||||||
| { |  | ||||||
| 
 |  | ||||||
| class Writer; |  | ||||||
| 
 |  | ||||||
| class WipeTower |  | ||||||
| { |  | ||||||
| public: |  | ||||||
| 	enum material_type |  | ||||||
| 	{ |  | ||||||
| 		INVALID = -1, |  | ||||||
| 		PLA   = 0,		// E:210C	B:55C
 |  | ||||||
| 		ABS   = 1,		// E:255C	B:100C
 |  | ||||||
| 		PET   = 2,		// E:240C	B:90C
 |  | ||||||
| 		HIPS  = 3,		// E:220C	B:100C
 |  | ||||||
| 		FLEX  = 4,		// E:245C	B:80C
 |  | ||||||
| 		SCAFF = 5,		// E:215C	B:55C
 |  | ||||||
| 		EDGE  = 6,		// E:240C	B:80C
 |  | ||||||
| 		NGEN  = 7,		// E:230C	B:80C
 |  | ||||||
| 		PVA   = 8	    // E:210C	B:80C
 |  | ||||||
| 	}; |  | ||||||
| 
 |  | ||||||
| 	enum wipe_shape |  | ||||||
| 	{ |  | ||||||
| 		SHAPE_NORMAL   = 1, |  | ||||||
| 		SHAPE_REVERSED = -1 |  | ||||||
| 	}; |  | ||||||
| 
 |  | ||||||
| 	struct xy |  | ||||||
| 	{ |  | ||||||
| 		xy(float x = 0.f, float y = 0.f) : x(x), y(y) {} |  | ||||||
| 		xy  operator+(const xy &rhs) const { xy out(*this); out.x += rhs.x; out.y += rhs.y; return out; } |  | ||||||
| 		xy  operator-(const xy &rhs) const { xy out(*this); out.x -= rhs.x; out.y -= rhs.y; return out; } |  | ||||||
| 		xy& operator+=(const xy &rhs) { x += rhs.x; y += rhs.y; return *this; } |  | ||||||
| 		xy& operator-=(const xy &rhs) { x -= rhs.x; y -= rhs.y; return *this; } |  | ||||||
| 		float x; |  | ||||||
| 		float y; |  | ||||||
| 	}; |  | ||||||
| 
 |  | ||||||
| 	// Parse material name into material_type.
 |  | ||||||
| 	static material_type parse_material(const char *name); |  | ||||||
| 
 |  | ||||||
| 	// x			-- x coordinates of wipe tower in mm ( left bottom corner )
 |  | ||||||
| 	// y			-- y coordinates of wipe tower in mm ( left bottom corner )
 |  | ||||||
| 	// width		-- width of wipe tower in mm ( default 60 mm - leave as it is )
 |  | ||||||
| 	// wipe_area	-- space available for one toolchange in mm
 |  | ||||||
| 	// colors		-- maximum colors for object
 |  | ||||||
| 	WipeTower(float x, float y, float width, float wipe_area, int color_changes) : |  | ||||||
| 		m_wipe_tower_pos(x, y), |  | ||||||
| 		m_wipe_tower_width(width), |  | ||||||
| 		m_wipe_area(wipe_area), |  | ||||||
| 		m_color_changes(color_changes), |  | ||||||
| 		m_z_pos(0.f) {} |  | ||||||
| 
 |  | ||||||
| 	// colors		-- maximum color changes for layer
 |  | ||||||
| 	void setColors(int colors) { m_color_changes = colors; } |  | ||||||
| 
 |  | ||||||
| 	// Z height		-- mm
 |  | ||||||
| 	void setZ(float z) { m_z_pos = z; } |  | ||||||
| 	bool is_first_layer() const { return m_z_pos < 0.205f; } |  | ||||||
| 
 |  | ||||||
| 	// _retract - retract value in mm
 |  | ||||||
| 	void setRetract(float _retract) { retract = _retract; } |  | ||||||
| 	 |  | ||||||
| 	// _zHop - z hop value in mm
 |  | ||||||
| 	void setZHop(float _zhop) { zHop = _zhop; } |  | ||||||
| 
 |  | ||||||
| 	void setExtrusion(int layerHeight) |  | ||||||
| 	{ |  | ||||||
| 		// set extrusion coefficient for layer height 
 |  | ||||||
| 		// layerHeight		-- mm * 100
 |  | ||||||
| 
 |  | ||||||
| 		switch (layerHeight) |  | ||||||
| 		{ |  | ||||||
| 		case 15: |  | ||||||
| 			extrusion_flow = (float)0.024; |  | ||||||
| 			break; |  | ||||||
| 		case 20: |  | ||||||
| 			extrusion_flow = (float)0.029; |  | ||||||
| 			break; |  | ||||||
| 		default: |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 		Returns gcode for wipe tower brim |  | ||||||
| 	 |  | ||||||
| 		sideOnly			-- set to false -- experimental, draw brim on sides of wipe tower  |  | ||||||
| 		offset				-- set to 0		-- experimental, offset to replace brim in front / rear of wipe tower |  | ||||||
| 	*/ |  | ||||||
| 	std::string FirstLayer(bool sideOnly = false, float y_offset = 0.f); |  | ||||||
| 
 |  | ||||||
| 	// Returns gcode for toolchange 
 |  | ||||||
| 	std::pair<std::string, WipeTower::xy> Toolchange( |  | ||||||
| 		// extruder #   0 - 3
 |  | ||||||
| 		const int 			tool,  |  | ||||||
| 		// filament type currently used to print and loaded in nozzle -- see enum material_type
 |  | ||||||
| 		const material_type current_material,  |  | ||||||
| 		// filament type that will be loaded in to the nozzle  -- see enum material_type
 |  | ||||||
| 		const material_type new_material,  |  | ||||||
| 		// temperature in Celsius for new filament that will be loaded into the nozzle	
 |  | ||||||
| 		const int 			temperature,  |  | ||||||
| 		// orientation of purge / wipe shape (NORMAL / REVERSED)
 |  | ||||||
| 		const wipe_shape 	shape,  |  | ||||||
| 		// total toolchanges done counter ( comment in  header of toolchange only )
 |  | ||||||
| 		const int 			count,  |  | ||||||
| 		// space available for toolchange ( purge / load / wipe ) - in mm
 |  | ||||||
| 		const float 		spaceAvailable,  |  | ||||||
| 		// experimental, don't use, set to 0
 |  | ||||||
| 		const float 		wipeStartY,  |  | ||||||
| 		// for last toolchange in object set to true to unload filament into cooling tube, for all other set to false
 |  | ||||||
| 		const bool  		lastInFile,  |  | ||||||
| 		// experimental, set to false
 |  | ||||||
| 		const bool 			colorInit = false); |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 		Returns gcode to draw empty pattern in place of a toolchange -> in case there are less toolchanges atm then what is required later  |  | ||||||
| 
 |  | ||||||
| 		order				-- total toolchanges done for current layer |  | ||||||
| 		total				-- total colors in current z layer including empty ones |  | ||||||
| 		afterToolchange		-- true - ignore some not neccesary moves | false - do whole move from object to wipe tower |  | ||||||
| 		firstLayerOffset	-- experimental , set to 0 |  | ||||||
| 	*/ |  | ||||||
| 	std::string Perimeter(int order, int total, int Layer, bool afterToolchange, int firstLayerOffset = 0); |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
| 	WipeTower(); |  | ||||||
| 
 |  | ||||||
| 	// Left front corner of the wipe tower in mm.
 |  | ||||||
| 	xy    m_wipe_tower_pos; |  | ||||||
| 	// Width of the wipe tower.
 |  | ||||||
| 	float m_wipe_tower_width; |  | ||||||
| 	// Per color Y span.
 |  | ||||||
| 	float m_wipe_area; |  | ||||||
| 	// Current Z position.
 |  | ||||||
| 	float m_z_pos; |  | ||||||
| 	// Maximum number of color changes per layer.
 |  | ||||||
| 	int   m_color_changes; |  | ||||||
| 
 |  | ||||||
| 	float zHop 				= 0.5f; |  | ||||||
| 	float retract 			= 4.f; |  | ||||||
| 	float perimeterWidth 	= 0.5f; |  | ||||||
| 	float extrusion_flow 	= 0.029f; |  | ||||||
| 
 |  | ||||||
| 	struct box_coordinates |  | ||||||
| 	{ |  | ||||||
| 		box_coordinates(float left, float bottom, float width, float height) : |  | ||||||
| 			ld(left        , bottom         ), |  | ||||||
| 			lu(left        , bottom + height), |  | ||||||
| 			rd(left + width, bottom         ), |  | ||||||
| 			ru(left + width, bottom + height) {} |  | ||||||
| 		box_coordinates(const xy &pos, float width, float height) : box_coordinates(pos.x, pos.y, width, height) {} |  | ||||||
| 		void expand(const float offset) { |  | ||||||
| 			ld += xy(- offset, - offset); |  | ||||||
| 			lu += xy(- offset,   offset); |  | ||||||
| 			rd += xy(  offset, - offset); |  | ||||||
| 			ru += xy(  offset,   offset); |  | ||||||
| 		} |  | ||||||
| 		xy ld;  // left down
 |  | ||||||
| 		xy lu;	// left upper 
 |  | ||||||
| 		xy ru;	// right upper
 |  | ||||||
| 		xy rd;	// right lower
 |  | ||||||
| 	}; |  | ||||||
| 	 |  | ||||||
| 	void toolchange_Unload( |  | ||||||
| 		Writer				   &writer, |  | ||||||
| 		const box_coordinates  &cleaning_box,  |  | ||||||
| 		const material_type	 	material, |  | ||||||
| 		const wipe_shape 	    shape, |  | ||||||
| 		const int 				temperature); |  | ||||||
| 
 |  | ||||||
| 	void toolchange_Change( |  | ||||||
| 		Writer				   &writer, |  | ||||||
| 		int 					tool, |  | ||||||
| 		material_type 			current_material, |  | ||||||
| 		material_type 			new_material); |  | ||||||
| 	 |  | ||||||
| 	void toolchange_Load( |  | ||||||
| 		Writer				   &writer, |  | ||||||
| 		const box_coordinates  &cleaning_box, |  | ||||||
| 		const material_type 	material, |  | ||||||
| 		const wipe_shape 		shape, |  | ||||||
| 		const bool 				colorInit); |  | ||||||
| 	 |  | ||||||
| 	void toolchange_Wipe( |  | ||||||
| 		Writer				   &writer, |  | ||||||
| 		const box_coordinates  &cleaning_box,  |  | ||||||
| 		const material_type 	material, |  | ||||||
| 		const wipe_shape 	    shape); |  | ||||||
| 	 |  | ||||||
| 	void toolchange_Done( |  | ||||||
| 		Writer				   &writer, |  | ||||||
| 		const box_coordinates  &cleaning_box,  |  | ||||||
| 		const material_type 	material,  |  | ||||||
| 		const wipe_shape 		shape); |  | ||||||
| 
 |  | ||||||
| 	box_coordinates _boxForColor(int order) const; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| }; // namespace PrusaSingleExtruderMM
 |  | ||||||
| 
 |  | ||||||
| #endif /* PrusaSingleExtruderMM_WipeTower_hpp_ */ |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv