mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Merge branch 'master' into boost-optimizations
This commit is contained in:
		
						commit
						c46bfc71b4
					
				
					 19 changed files with 224 additions and 148 deletions
				
			
		|  | @ -161,11 +161,6 @@ sub bounding_box_polygon { | |||
|     ]); | ||||
| } | ||||
| 
 | ||||
| sub bounding_box_center { | ||||
|     my $self = shift; | ||||
|     return Slic3r::Geometry::bounding_box_center($self->contour); | ||||
| } | ||||
| 
 | ||||
| sub clip_line { | ||||
|     my $self = shift; | ||||
|     my ($line) = @_;  # line must be a Slic3r::Line object | ||||
|  |  | |||
|  | @ -39,10 +39,9 @@ sub filler { | |||
|         return $FillTypes{$filler}->new; | ||||
|     } | ||||
|      | ||||
|     if (!$self->fillers->{$filler}) { | ||||
|         my $f = $self->fillers->{$filler} = $FillTypes{$filler}->new; | ||||
|         $f->bounding_box([ $self->print->bounding_box ]) if $f->can('bounding_box'); | ||||
|     } | ||||
|     $self->fillers->{$filler} ||= $FillTypes{$filler}->new( | ||||
|         bounding_box => [ $self->print->bounding_box ], | ||||
|     ); | ||||
|     return $self->fillers->{$filler}; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ use Slic3r::Geometry qw(PI); | |||
| 
 | ||||
| has 'layer_id'            => (is => 'rw'); | ||||
| has 'angle'               => (is => 'rw', default => sub { $Slic3r::Config->fill_angle }); | ||||
| has 'bounding_box'        => (is => 'ro', required => 1); | ||||
| 
 | ||||
| sub angles () { [0, PI/2] } | ||||
| 
 | ||||
|  | @ -15,7 +16,7 @@ sub infill_direction { | |||
|     # set infill angle | ||||
|     my (@rotate, @shift); | ||||
|     $rotate[0] = Slic3r::Geometry::deg2rad($self->angle); | ||||
|     $rotate[1] = $surface->expolygon->bounding_box_center; | ||||
|     $rotate[1] = Slic3r::Geometry::bounding_box_center($self->bounding_box); | ||||
|     @shift = @{$rotate[1]}; | ||||
|      | ||||
|     if (defined $self->layer_id) { | ||||
|  | @ -38,26 +39,20 @@ sub infill_direction { | |||
| sub rotate_points { | ||||
|     my $self = shift; | ||||
|     my ($expolygon, $rotate_vector) = @_; | ||||
|     my @rotate = @{$rotate_vector->[0]}; | ||||
|     my @shift  = @{$rotate_vector->[1]}; | ||||
|      | ||||
|     # rotate points as needed | ||||
|     if ($rotate[0]) { | ||||
|         $expolygon->rotate(@rotate); | ||||
|         $expolygon->translate(@shift); | ||||
|     } | ||||
|     # rotate points | ||||
|     $expolygon->rotate(@{$rotate_vector->[0]}); | ||||
|     $expolygon->translate(@{$rotate_vector->[1]}); | ||||
| } | ||||
| 
 | ||||
| sub rotate_points_back { | ||||
|     my $self = shift; | ||||
|     my ($paths, $rotate_vector) = @_; | ||||
|     my @rotate = @{$rotate_vector->[0]}; | ||||
|     my @shift  = @{$rotate_vector->[1]}; | ||||
|     my @rotate = (-$rotate_vector->[0][0], $rotate_vector->[0][1]); | ||||
|     my $shift  = [ map -$_, @{$rotate_vector->[1]} ]; | ||||
|      | ||||
|     if ($rotate[0]) { | ||||
|         @$paths = map [ Slic3r::Geometry::rotate_points(-$rotate[0], $rotate[1], @$_) ],  | ||||
|             map [ Slic3r::Geometry::move_points([map -$_, @shift], @$_) ], @$paths; | ||||
|     } | ||||
|     @$paths = map [ Slic3r::Geometry::rotate_points(@rotate, @$_) ],  | ||||
|         map [ Slic3r::Geometry::move_points($shift, @$_) ], @$paths; | ||||
| } | ||||
| 
 | ||||
| sub adjust_solid_spacing { | ||||
|  |  | |||
|  | @ -3,7 +3,6 @@ use Moo; | |||
| 
 | ||||
| extends 'Slic3r::Fill::Base'; | ||||
| 
 | ||||
| has 'bounding_box'  => (is => 'rw'); | ||||
| has 'cache'         => (is => 'rw', default => sub {{}}); | ||||
| 
 | ||||
| use Slic3r::Geometry qw(PI X1 Y1 X2 Y2 X Y scale); | ||||
|  | @ -25,7 +24,7 @@ sub fill_surface { | |||
|      | ||||
|     my $cache_id = sprintf "d%s_s%s_a%s", | ||||
|         $params{density}, $params{flow_spacing}, $rotate_vector->[0][0]; | ||||
|     if (!$self->cache->{$cache_id} || !defined $self->bounding_box) { | ||||
|     if (!$self->cache->{$cache_id}) { | ||||
|          | ||||
|         # hexagons math | ||||
|         my $hex_side = $distance / (sqrt(3)/2); | ||||
|  | @ -39,7 +38,7 @@ sub fill_surface { | |||
|          | ||||
|         # adjust actual bounding box to the nearest multiple of our hex pattern | ||||
|         # and align it so that it matches across layers | ||||
|         my $bounding_box = [ $self->bounding_box ? @{$self->bounding_box} : $expolygon->bounding_box ]; | ||||
|         my $bounding_box = [ @{$self->bounding_box} ];  # clone | ||||
|         $bounding_box->[$_] = 0 for X1, Y1; | ||||
|         { | ||||
|             my $bb_polygon = Slic3r::Polygon->new_from_bounding_box($bounding_box); | ||||
|  |  | |||
|  | @ -3,6 +3,8 @@ use Moo; | |||
| 
 | ||||
| extends 'Slic3r::Fill::Base'; | ||||
| 
 | ||||
| has 'cache'         => (is => 'rw', default => sub {{}}); | ||||
| 
 | ||||
| use Slic3r::Geometry qw(X1 Y1 X2 Y2 A B X Y scale unscale scaled_epsilon); | ||||
| 
 | ||||
| sub fill_surface { | ||||
|  | @ -16,39 +18,55 @@ sub fill_surface { | |||
|      | ||||
|     my ($expolygon_off) = $expolygon->offset_ex(scale $params{flow_spacing}/2); | ||||
|     return {} if !$expolygon_off;  # skip some very small polygons (which shouldn't arrive here) | ||||
|     my $bounding_box = [ $expolygon->bounding_box ]; | ||||
|      | ||||
|     my $flow_spacing = $params{flow_spacing}; | ||||
|     my $min_spacing = scale $params{flow_spacing}; | ||||
|     my $distance_between_lines = $min_spacing / $params{density}; | ||||
|     my $line_oscillation = $distance_between_lines - $min_spacing; | ||||
|      | ||||
|     my $flow_spacing = $params{flow_spacing}; | ||||
|     if ($params{density} == 1 && !$params{dont_adjust}) { | ||||
|         $distance_between_lines = $self->adjust_solid_spacing( | ||||
|             width       => $bounding_box->[X2] - $bounding_box->[X1], | ||||
|             distance    => $distance_between_lines, | ||||
|         ); | ||||
|         $flow_spacing = unscale $distance_between_lines; | ||||
|     } | ||||
|      | ||||
|     my $x = $bounding_box->[X1]; | ||||
|     my $is_line_pattern = $self->isa('Slic3r::Fill::Line'); | ||||
|     my @vertical_lines = (); | ||||
|     for (my $i = 0; $x <= $bounding_box->[X2] + scaled_epsilon; $i++) { | ||||
|         my $vertical_line = Slic3r::Line->new([$x, $bounding_box->[Y2]], [$x, $bounding_box->[Y1]]); | ||||
|         if ($is_line_pattern && $i % 2) { | ||||
|             $vertical_line->[A][X] += $line_oscillation; | ||||
|             $vertical_line->[B][X] -= $line_oscillation; | ||||
|      | ||||
|     my $cache_id = sprintf "d%s_s%s_a%s", | ||||
|         $params{density}, $params{flow_spacing}, $rotate_vector->[0][0]; | ||||
|      | ||||
|     if (!$self->cache->{$cache_id}) { | ||||
|         # compute bounding box | ||||
|         my $bounding_box = $self->bounding_box; | ||||
|         { | ||||
|             my $bb_expolygon = Slic3r::ExPolygon->new(Slic3r::Polygon->new_from_bounding_box($bounding_box)); | ||||
|             $self->rotate_points($bb_expolygon, $rotate_vector); | ||||
|             $bounding_box = [ $bb_expolygon->bounding_box ]; | ||||
|         } | ||||
|         push @vertical_lines, $vertical_line; | ||||
|         $x += $distance_between_lines; | ||||
|          | ||||
|         # define flow spacing according to requested density | ||||
|         if ($params{density} == 1 && !$params{dont_adjust}) { | ||||
|             $distance_between_lines = $self->adjust_solid_spacing( | ||||
|                 width       => $bounding_box->[X2] - $bounding_box->[X1], | ||||
|                 distance    => $distance_between_lines, | ||||
|             ); | ||||
|             $flow_spacing = unscale $distance_between_lines; | ||||
|         } | ||||
|          | ||||
|         # generate the basic pattern | ||||
|         my $x = $bounding_box->[X1]; | ||||
|         my @vertical_lines = (); | ||||
|         for (my $i = 0; $x <= $bounding_box->[X2] + scaled_epsilon; $i++) { | ||||
|             my $vertical_line = Slic3r::Line->new([$x, $bounding_box->[Y2]], [$x, $bounding_box->[Y1]]); | ||||
|             if ($is_line_pattern && $i % 2) { | ||||
|                 $vertical_line->[A][X] += $line_oscillation; | ||||
|                 $vertical_line->[B][X] -= $line_oscillation; | ||||
|             } | ||||
|             push @vertical_lines, $vertical_line; | ||||
|             $x += $distance_between_lines; | ||||
|         } | ||||
|          | ||||
|         $self->cache->{$cache_id} = [@vertical_lines]; | ||||
|     } | ||||
|      | ||||
|     # clip paths against a slightly offsetted expolygon, so that the first and last paths | ||||
|     # are kept even if the expolygon has vertical sides | ||||
|     my @paths = @{ Boost::Geometry::Utils::polygon_multi_linestring_intersection( | ||||
|         +($expolygon->offset_ex(scaled_epsilon))[0],  # TODO: we should use all the resulting expolygons and clip the linestrings to a multipolygon object | ||||
|         [ @vertical_lines ], | ||||
|         [ @{ $self->cache->{$cache_id} } ], | ||||
|     ) }; | ||||
|      | ||||
|     # connect lines | ||||
|  |  | |||
|  | @ -248,7 +248,7 @@ sub extrude_path { | |||
|             $gcode .= $self->G1($line->[B], undef, $e * $line_length, $description); | ||||
|         } | ||||
|         $self->wipe_path(Slic3r::Polyline->new([ reverse @{$path->points} ])) | ||||
|             if $Slic3r::Config->wipe; | ||||
|             if $self->extruder->wipe; | ||||
|     } | ||||
|      | ||||
|     if ($Slic3r::Config->cooling) { | ||||
|  | @ -358,19 +358,19 @@ sub retract { | |||
|      | ||||
|     # wipe | ||||
|     my $wipe_path; | ||||
|     if ($Slic3r::Config->wipe && $self->wipe_path) { | ||||
|     if ($self->extruder->wipe && $self->wipe_path) { | ||||
|         $wipe_path = Slic3r::Polyline->new([ $self->last_pos, @{$self->wipe_path}[1..$#{$self->wipe_path}] ]) | ||||
|             ->clip_start($self->extruder->scaled_wipe_distance); | ||||
|     } | ||||
|      | ||||
|     # prepare moves | ||||
|     $self->speed('retract'); | ||||
|     my $retract = [undef, undef, -$length, $comment]; | ||||
|     my $lift    = ($self->extruder->retract_lift == 0 || defined $params{move_z}) && !$self->lifted | ||||
|         ? undef | ||||
|         : [undef, $self->z + $self->extruder->retract_lift, 0, 'lift plate during travel']; | ||||
|      | ||||
|     if (($Slic3r::Config->g0 || $Slic3r::Config->gcode_flavor eq 'mach3') && $params{travel_to}) { | ||||
|         $self->speed('travel'); | ||||
|         if ($lift) { | ||||
|             # combine lift and retract | ||||
|             $lift->[2] = $retract->[2]; | ||||
|  | @ -382,22 +382,25 @@ sub retract { | |||
|         } | ||||
|     } elsif (($Slic3r::Config->g0 || $Slic3r::Config->gcode_flavor eq 'mach3') && defined $params{move_z}) { | ||||
|         # combine Z change and retraction | ||||
|         $self->speed('travel'); | ||||
|         my $travel = [undef, $params{move_z}, $retract->[2], "change layer and $comment"]; | ||||
|         $gcode .= $self->G0(@$travel); | ||||
|     } else { | ||||
|         if ($wipe_path) { | ||||
|         # check that we have a positive wipe length | ||||
|         if ($wipe_path && (my $total_wipe_length = $wipe_path->length)) { | ||||
|             $self->speed('travel'); | ||||
|             # subdivide the retraction | ||||
|             my $total_wipe_length = $wipe_path->length; | ||||
|              | ||||
|             # subdivide the retraction | ||||
|             for (1 .. $#$wipe_path) { | ||||
|                 my $segment_length = $wipe_path->[$_-1]->distance_to($wipe_path->[$_]); | ||||
|                 $gcode .= $self->G1($wipe_path->[$_], undef, $retract->[2] * ($segment_length / $total_wipe_length), $retract->[3] . ";_WIPE"); | ||||
|             } | ||||
|         } else { | ||||
|             $self->speed('retract'); | ||||
|             $gcode .= $self->G1(@$retract); | ||||
|         } | ||||
|         if (!$self->lifted) { | ||||
|             $self->speed('travel'); | ||||
|             if (defined $params{move_z} && $self->extruder->retract_lift > 0) { | ||||
|                 my $travel = [undef, $params{move_z} + $self->extruder->retract_lift, 0, 'move to next layer (' . $self->layer->id . ') and lift']; | ||||
|                 $gcode .= $self->G0(@$travel); | ||||
|  |  | |||
							
								
								
									
										77
									
								
								lib/Slic3r/GCode/CoolingBuffer.pm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								lib/Slic3r/GCode/CoolingBuffer.pm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,77 @@ | |||
| package Slic3r::GCode::CoolingBuffer; | ||||
| use Moo; | ||||
| 
 | ||||
| has 'config'    => (is => 'ro', required => 1); | ||||
| has 'gcodegen'  => (is => 'ro', required => 1); | ||||
| has 'gcode'     => (is => 'rw', default => sub {""}); | ||||
| has 'layer_id'  => (is => 'rw'); | ||||
| has 'last_z'    => (is => 'rw'); | ||||
| has 'min_print_speed' => (is => 'lazy'); | ||||
| 
 | ||||
| sub _build_min_print_speed { | ||||
|     my $self = shift; | ||||
|     return 60 * $self->config->min_print_speed; | ||||
| } | ||||
| 
 | ||||
| sub append { | ||||
|     my $self = shift; | ||||
|     my ($gcode, $layer) = @_; | ||||
|      | ||||
|     my $return = ""; | ||||
|     if (defined $self->last_z && $self->last_z != $layer->print_z) { | ||||
|         $return = $self->flush; | ||||
|         $self->gcodegen->elapsed_time(0); | ||||
|     } | ||||
|      | ||||
|     $self->layer_id($layer->id); | ||||
|     $self->last_z($layer->print_z); | ||||
|     $self->gcode($self->gcode . $gcode); | ||||
|      | ||||
|     return $return; | ||||
| } | ||||
| 
 | ||||
| sub flush { | ||||
|     my $self = shift; | ||||
|      | ||||
|     my $gcode = $self->gcode; | ||||
|     $self->gcode(""); | ||||
|      | ||||
|     my $fan_speed = $self->config->fan_always_on ? $self->config->min_fan_speed : 0; | ||||
|     my $speed_factor = 1; | ||||
|     if ($self->config->cooling) { | ||||
|         my $layer_time = $self->gcodegen->elapsed_time; | ||||
|         Slic3r::debugf "Layer %d estimated printing time: %d seconds\n", $self->layer_id, $layer_time; | ||||
|         if ($layer_time < $self->config->slowdown_below_layer_time) { | ||||
|             $fan_speed = $self->config->max_fan_speed; | ||||
|             $speed_factor = $layer_time / $self->config->slowdown_below_layer_time; | ||||
|         } elsif ($layer_time < $self->config->fan_below_layer_time) { | ||||
|             $fan_speed = $self->config->max_fan_speed - ($self->config->max_fan_speed - $self->config->min_fan_speed) | ||||
|                 * ($layer_time - $self->config->slowdown_below_layer_time) | ||||
|                 / ($self->config->fan_below_layer_time - $self->config->slowdown_below_layer_time); #/ | ||||
|         } | ||||
|         Slic3r::debugf "  fan = %d%%, speed = %d%%\n", $fan_speed, $speed_factor * 100; | ||||
|          | ||||
|         if ($speed_factor < 1) { | ||||
|             my $dec = $self->gcodegen->dec; | ||||
|             $gcode =~ s/^(?=.*? [XY])(?=.*? E)(?!;_WIPE)(?<!;_BRIDGE_FAN_START\n)(G1 .*?F)(\d+(?:\.\d+)?)/ | ||||
|                 my $new_speed = $2 * $speed_factor; | ||||
|                 $1 . sprintf("%.${dec}f", $new_speed < $self->min_print_speed ? $self->min_print_speed : $new_speed) | ||||
|                 /gexm; | ||||
|         } | ||||
|         $fan_speed = 0 if $self->layer_id < $self->config->disable_fan_first_layers; | ||||
|     } | ||||
|     $gcode = $self->gcodegen->set_fan($fan_speed) . $gcode; | ||||
|      | ||||
|     # bridge fan speed | ||||
|     if (!$self->config->cooling || $self->config->bridge_fan_speed == 0 || $self->layer_id < $self->config->disable_fan_first_layers) { | ||||
|         $gcode =~ s/^;_BRIDGE_FAN_(?:START|END)\n//gm; | ||||
|     } else { | ||||
|         $gcode =~ s/^;_BRIDGE_FAN_START\n/ $self->gcodegen->set_fan($self->config->bridge_fan_speed, 1) /gmex; | ||||
|         $gcode =~ s/^;_BRIDGE_FAN_END\n/ $self->gcodegen->set_fan($fan_speed, 1) /gmex; | ||||
|     } | ||||
|     $gcode =~ s/;_WIPE//g; | ||||
|      | ||||
|     return $gcode; | ||||
| } | ||||
| 
 | ||||
| 1; | ||||
|  | @ -5,9 +5,9 @@ use utf8; | |||
| 
 | ||||
| use File::Basename qw(basename dirname); | ||||
| use List::Util qw(max sum first); | ||||
| use Math::Clipper qw(offset JT_ROUND); | ||||
| use Math::ConvexHull::MonotoneChain qw(convex_hull); | ||||
| use Slic3r::Geometry qw(X Y Z X1 Y1 X2 Y2 MIN MAX); | ||||
| use Slic3r::Geometry::Clipper qw(offset JT_ROUND); | ||||
| use threads::shared qw(shared_clone); | ||||
| use Wx qw(:bitmap :brush :button :cursor :dialog :filedialog :font :keycode :icon :id :listctrl :misc :panel :pen :sizer :toolbar :window); | ||||
| use Wx::Event qw(EVT_BUTTON EVT_COMMAND EVT_KEY_DOWN EVT_LIST_ITEM_ACTIVATED EVT_LIST_ITEM_DESELECTED EVT_LIST_ITEM_SELECTED EVT_MOUSE_EVENTS EVT_PAINT EVT_TOOL EVT_CHOICE); | ||||
|  |  | |||
|  | @ -243,7 +243,9 @@ sub config_wizard { | |||
| 
 | ||||
|     return unless $self->check_unsaved_changes; | ||||
|     if (my $config = Slic3r::GUI::ConfigWizard->new($self)->run) { | ||||
|         $_->select_default_preset for values %{$self->{options_tabs}}; | ||||
|         if ($self->{mode} eq 'expert') { | ||||
|             $_->select_default_preset for values %{$self->{options_tabs}}; | ||||
|         } | ||||
|         $self->load_config($config); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ our @ISA = qw(Exporter); | |||
| our @EXPORT_OK = qw( | ||||
|     PI X Y Z A B X1 Y1 X2 Y2 MIN MAX epsilon slope line_atan lines_parallel  | ||||
|     line_point_belongs_to_segment points_coincide distance_between_points  | ||||
|     comparable_distance_between_points chained_path_items chained_path_points | ||||
|     chained_path_items chained_path_points | ||||
|     line_length midpoint point_in_polygon point_in_segment segment_in_segment | ||||
|     point_is_on_left_of_segment polyline_lines polygon_lines nearest_point | ||||
|     point_along_segment polygon_segment_having_point polygon_has_subsegment | ||||
|  | @ -115,11 +115,6 @@ sub distance_between_points { | |||
|     return sqrt((($p1->[X] - $p2->[X])**2) + ($p1->[Y] - $p2->[Y])**2); | ||||
| } | ||||
| 
 | ||||
| sub comparable_distance_between_points { | ||||
|     my ($p1, $p2) = @_; | ||||
|     return (($p1->[X] - $p2->[X])**2) + (($p1->[Y] - $p2->[Y])**2); | ||||
| } | ||||
| 
 | ||||
| sub point_line_distance { | ||||
|     my ($point, $line) = @_; | ||||
|     return distance_between_points($point, $line->[A]) | ||||
|  | @ -248,14 +243,27 @@ sub nearest_point_index { | |||
|     my ($point, $points) = @_; | ||||
|      | ||||
|     my ($nearest_point_index, $distance) = (); | ||||
| 
 | ||||
|     my $point_x = $point->[X]; | ||||
|     my $point_y = $point->[Y]; | ||||
| 
 | ||||
|     for my $i (0..$#$points) { | ||||
|         my $d = comparable_distance_between_points($point, $points->[$i]); | ||||
|         if (!defined $distance || $d < $distance) { | ||||
|             $nearest_point_index = $i; | ||||
|             $distance = $d; | ||||
|             return $i if $distance < epsilon; | ||||
|         } | ||||
|         my $d = ($point_x - $points->[$i]->[X])**2; | ||||
|         # If the X distance of the candidate is > than the total distance of the | ||||
|         # best previous candidate, we know we don't want it | ||||
|         next if (defined $distance && $d > $distance); | ||||
|     | ||||
|         # If the total distance of the candidate is > than the total distance of the | ||||
|         # best previous candidate, we know we don't want it | ||||
|         $d += ($point_y - $points->[$i]->[Y])**2; | ||||
|         next if (defined $distance && $d > $distance); | ||||
| 
 | ||||
|         $nearest_point_index = $i; | ||||
|         $distance = $d; | ||||
|          | ||||
|         last if $distance < epsilon; | ||||
|     } | ||||
| 
 | ||||
|     return $nearest_point_index; | ||||
| } | ||||
| 
 | ||||
|  | @ -671,10 +679,10 @@ sub bounding_box { | |||
| } | ||||
| 
 | ||||
| sub bounding_box_center { | ||||
|     my @bounding_box = bounding_box(@_); | ||||
|     my ($bounding_box) = @_; | ||||
|     return Slic3r::Point->new( | ||||
|         ($bounding_box[X2] + $bounding_box[X1]) / 2, | ||||
|         ($bounding_box[Y2] + $bounding_box[Y1]) / 2, | ||||
|         ($bounding_box->[X2] + $bounding_box->[X1]) / 2, | ||||
|         ($bounding_box->[Y2] + $bounding_box->[Y1]) / 2, | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -14,12 +14,13 @@ our $clipper = Math::Clipper->new; | |||
| 
 | ||||
| sub safety_offset { | ||||
|     my ($polygons, $factor) = @_; | ||||
|     return Math::Clipper::offset($polygons, $factor // (scale 1e-05), 100000, JT_MITER, 2); | ||||
|     return Math::Clipper::int_offset($polygons, $factor // (scale 1e-05), 100000, JT_MITER, 2); | ||||
| } | ||||
| 
 | ||||
| sub safety_offset_ex { | ||||
|     # offset polygons and then apply holes to the right contours | ||||
|     return @{ union_ex([ safety_offset(@_) ]) }; | ||||
|     my ($polygons, $factor) = @_; | ||||
|     return map Slic3r::ExPolygon->new($_), | ||||
|         @{Math::Clipper::ex_int_offset($polygons, $factor // (scale 1e-05), 100000, JT_MITER, 2)}; | ||||
| } | ||||
| 
 | ||||
| sub offset { | ||||
|  | @ -28,13 +29,18 @@ sub offset { | |||
|     $joinType   //= JT_MITER; | ||||
|     $miterLimit //= 3; | ||||
|      | ||||
|     my $offsets = Math::Clipper::offset($polygons, $distance, $scale, $joinType, $miterLimit); | ||||
|     my $offsets = Math::Clipper::int_offset($polygons, $distance, $scale, $joinType, $miterLimit); | ||||
|     return @$offsets; | ||||
| } | ||||
| 
 | ||||
| sub offset_ex { | ||||
|     # offset polygons and then apply holes to the right contours | ||||
|     return @{ union_ex([ offset(@_) ]) }; | ||||
|     my ($polygons, $distance, $scale, $joinType, $miterLimit) = @_; | ||||
|     $scale      ||= 100000; | ||||
|     $joinType   //= JT_MITER; | ||||
|     $miterLimit //= 3; | ||||
|      | ||||
|     my $offsets = Math::Clipper::ex_int_offset($polygons, $distance, $scale, $joinType, $miterLimit); | ||||
|     return map Slic3r::ExPolygon->new($_), @$offsets; | ||||
| } | ||||
| 
 | ||||
| sub diff_ex { | ||||
|  | @ -96,13 +102,19 @@ sub xor_ex { | |||
|     ]; | ||||
| } | ||||
| 
 | ||||
| sub ex_int_offset2 { | ||||
|     my ($polygons, $delta1, $delta2, $scale, $joinType, $miterLimit) = @_; | ||||
|     $scale      ||= 100000; | ||||
|     $joinType   //= JT_MITER; | ||||
|     $miterLimit //= 3; | ||||
|      | ||||
|     my $offsets = Math::Clipper::ex_int_offset2($polygons, $delta1, $delta2, $scale, $joinType, $miterLimit); | ||||
|     return map Slic3r::ExPolygon->new($_), @$offsets; | ||||
| } | ||||
| 
 | ||||
| sub collapse_ex { | ||||
|     my ($polygons, $width) = @_; | ||||
|     my @result = offset( | ||||
|         [ offset($polygons, -$width/2,) ], | ||||
|         +$width/2, | ||||
|     ); | ||||
|     return union_ex([@result]); | ||||
|     my ($polygons, $width) = @_;use XXX; YYY  | ||||
|     return [ ex_int_offset2($polygons, -$width/2, +$width/2) ]; | ||||
| } | ||||
| 
 | ||||
| sub simplify_polygon { | ||||
|  |  | |||
|  | @ -96,12 +96,9 @@ sub make_surfaces { | |||
|     # detect thin walls by offsetting slices by half extrusion inwards | ||||
|     { | ||||
|         my $width = $self->perimeter_flow->scaled_width; | ||||
|         my $outgrown = union_ex([ | ||||
|             Slic3r::Geometry::Clipper::offset( | ||||
|                 [Slic3r::Geometry::Clipper::offset([ map @$_, map $_->expolygon, @{$self->slices} ], -$width)],  | ||||
|                 +$width, | ||||
|             ), | ||||
|         ]); | ||||
|         my $outgrown = [ | ||||
|             Slic3r::Geometry::Clipper::ex_int_offset2([ map @$_, map $_->expolygon, @{$self->slices} ], -$width, +$width), | ||||
|         ]; | ||||
|         my $diff = diff_ex( | ||||
|             [ map $_->p, @{$self->slices} ], | ||||
|             [ map @$_, @$outgrown ], | ||||
|  | @ -139,7 +136,7 @@ sub _merge_loops { | |||
|     # winding order. | ||||
|     # TODO: find a faster algorithm for this. | ||||
|     my @loops = sort { $a->encloses_point($b->[0]) ? 0 : 1 } @$loops;  # outer first | ||||
|     $safety_offset //= scale 0.1; | ||||
|     $safety_offset //= scale 0.0499; | ||||
|     @loops = @{ safety_offset(\@loops, $safety_offset) }; | ||||
|     my $expolygons = []; | ||||
|     while (my $loop = shift @loops) { | ||||
|  | @ -230,12 +227,7 @@ sub make_perimeters { | |||
|             # offsetting a polygon can result in one or many offset polygons | ||||
|             my @new_offsets = (); | ||||
|             foreach my $expolygon (@last_offsets) { | ||||
|                 my @offsets = @{union_ex([ | ||||
|                     Slic3r::Geometry::Clipper::offset( | ||||
|                         [Slic3r::Geometry::Clipper::offset($expolygon, -1.5*$spacing)],  | ||||
|                         +0.5*$spacing, | ||||
|                     ), | ||||
|                 ])}; | ||||
|                 my @offsets = Slic3r::Geometry::Clipper::ex_int_offset2($expolygon, -1.5*$spacing,  +0.5*$spacing); | ||||
|                 push @new_offsets, @offsets; | ||||
|                  | ||||
|                 # where the above check collapses the expolygon, then there's no room for an inner loop | ||||
|  |  | |||
|  | @ -151,7 +151,9 @@ sub validate { | |||
|                 { | ||||
|                     my @points = map [ @$_[X,Y] ], map @{$_->vertices}, @{$self->objects->[$obj_idx]->meshes}; | ||||
|                     my $convex_hull = Slic3r::Polygon->new(convex_hull(\@points)); | ||||
|                     ($clearance) = offset([$convex_hull], scale $Slic3r::Config->extruder_clearance_radius / 2, 1, JT_ROUND); | ||||
|                     ($clearance) = map Slic3r::Polygon->new($_),  | ||||
|                                         Slic3r::Geometry::Clipper::offset( | ||||
|                                             [$convex_hull], scale $Slic3r::Config->extruder_clearance_radius / 2, 1, JT_ROUND); | ||||
|                 } | ||||
|                 for my $copy (@{$self->objects->[$obj_idx]->copies}) { | ||||
|                     my $copy_clearance = $clearance->clone; | ||||
|  | @ -714,8 +716,6 @@ sub write_gcode { | |||
|         multiple_extruders  => (@{$self->extruders} > 1), | ||||
|         layer_count         => $self->layer_count, | ||||
|     ); | ||||
|     my $min_print_speed = 60 * $Slic3r::Config->min_print_speed; | ||||
|     my $dec = $gcodegen->dec; | ||||
|     print $fh "G21 ; set units to millimeters\n"; | ||||
|     print $fh $gcodegen->set_fan(0, 1) if $Slic3r::Config->cooling && $Slic3r::Config->disable_fan_first_layers; | ||||
|      | ||||
|  | @ -794,11 +794,11 @@ sub write_gcode { | |||
|             } | ||||
|             $gcode .= $gcodegen->set_bed_temperature($Slic3r::Config->bed_temperature) | ||||
|                 if $Slic3r::Config->bed_temperature && $Slic3r::Config->bed_temperature != $Slic3r::Config->first_layer_bed_temperature; | ||||
|             $second_layer_things_done = 1; | ||||
|         } | ||||
|          | ||||
|         # set new layer, but don't move Z as support material contact areas may need an intermediate one | ||||
|         $gcode .= $gcodegen->change_layer($layer); | ||||
|         $gcodegen->elapsed_time(0); | ||||
|          | ||||
|         # prepare callback to call as soon as a Z command is generated | ||||
|         $gcodegen->move_z_callback(sub { | ||||
|  | @ -940,42 +940,6 @@ sub write_gcode { | |||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return if !$gcode; | ||||
|          | ||||
|         my $fan_speed = $Slic3r::Config->fan_always_on ? $Slic3r::Config->min_fan_speed : 0; | ||||
|         my $speed_factor = 1; | ||||
|         if ($Slic3r::Config->cooling) { | ||||
|             my $layer_time = $gcodegen->elapsed_time; | ||||
|             Slic3r::debugf "Layer %d estimated printing time: %d seconds\n", $layer->id, $layer_time; | ||||
|             if ($layer_time < $Slic3r::Config->slowdown_below_layer_time) { | ||||
|                 $fan_speed = $Slic3r::Config->max_fan_speed; | ||||
|                 $speed_factor = $layer_time / $Slic3r::Config->slowdown_below_layer_time; | ||||
|             } elsif ($layer_time < $Slic3r::Config->fan_below_layer_time) { | ||||
|                 $fan_speed = $Slic3r::Config->max_fan_speed - ($Slic3r::Config->max_fan_speed - $Slic3r::Config->min_fan_speed) | ||||
|                     * ($layer_time - $Slic3r::Config->slowdown_below_layer_time) | ||||
|                     / ($Slic3r::Config->fan_below_layer_time - $Slic3r::Config->slowdown_below_layer_time); #/ | ||||
|             } | ||||
|             Slic3r::debugf "  fan = %d%%, speed = %d%%\n", $fan_speed, $speed_factor * 100; | ||||
|              | ||||
|             if ($speed_factor < 1) { | ||||
|                 $gcode =~ s/^(?=.*? [XY])(?=.*? E)(?!;_WIPE)(?<!;_BRIDGE_FAN_START\n)(G1 .*?F)(\d+(?:\.\d+)?)/ | ||||
|                     my $new_speed = $2 * $speed_factor; | ||||
|                     $1 . sprintf("%.${dec}f", $new_speed < $min_print_speed ? $min_print_speed : $new_speed) | ||||
|                     /gexm; | ||||
|             } | ||||
|             $fan_speed = 0 if $layer->id < $Slic3r::Config->disable_fan_first_layers; | ||||
|         } | ||||
|         $gcode = $gcodegen->set_fan($fan_speed) . $gcode; | ||||
|          | ||||
|         # bridge fan speed | ||||
|         if (!$Slic3r::Config->cooling || $Slic3r::Config->bridge_fan_speed == 0 || $layer->id < $Slic3r::Config->disable_fan_first_layers) { | ||||
|             $gcode =~ s/^;_BRIDGE_FAN_(?:START|END)\n//gm; | ||||
|         } else { | ||||
|             $gcode =~ s/^;_BRIDGE_FAN_START\n/ $gcodegen->set_fan($Slic3r::Config->bridge_fan_speed, 1) /gmex; | ||||
|             $gcode =~ s/^;_BRIDGE_FAN_END\n/ $gcodegen->set_fan($fan_speed, 1) /gmex; | ||||
|         } | ||||
|         $gcode =~ s/;_WIPE//g; | ||||
|          | ||||
|         return $gcode; | ||||
|     }; | ||||
|      | ||||
|  | @ -998,6 +962,11 @@ sub write_gcode { | |||
|                     print $fh $gcodegen->G0(Slic3r::Point->new(0,0), undef, 0, 'move to origin position for next object'); | ||||
|                 } | ||||
|                  | ||||
|                 my $buffer = Slic3r::GCode::CoolingBuffer->new( | ||||
|                     config      => $Slic3r::Config, | ||||
|                     gcodegen    => $gcodegen, | ||||
|                 ); | ||||
|                  | ||||
|                 for my $layer (@{$self->objects->[$obj_idx]->layers}) { | ||||
|                     # if we are printing the bottom layer of an object, and we have already finished | ||||
|                     # another one, set first layer temperatures. this happens before the Z move | ||||
|  | @ -1007,15 +976,20 @@ sub write_gcode { | |||
|                             if $Slic3r::Config->first_layer_bed_temperature; | ||||
|                         $print_first_layer_temperature->(); | ||||
|                     } | ||||
|                     print $fh $extrude_layer->($layer, [$copy]); | ||||
|                     print $fh $buffer->append($extrude_layer->($layer, [$copy]), $layer); | ||||
|                 } | ||||
|                 print $fh $buffer->flush; | ||||
|                 $finished_objects++; | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         print $fh $extrude_layer->($_, $_->object->copies) | ||||
|             for sort { $a->print_z <=> $b->print_z } | ||||
|                 map @{$_->layers}, @{$self->objects}; | ||||
|         my $buffer = Slic3r::GCode::CoolingBuffer->new( | ||||
|             config      => $Slic3r::Config, | ||||
|             gcodegen    => $gcodegen, | ||||
|         ); | ||||
|         print $fh $buffer->append($extrude_layer->($_, $_->object->copies), $_) | ||||
|             for sort { $a->print_z <=> $b->print_z } map @{$_->layers}, @{$self->objects}; | ||||
|         print $fh $buffer->flush; | ||||
|     } | ||||
|      | ||||
|     # save statistic data | ||||
|  |  | |||
|  | @ -894,6 +894,7 @@ sub generate_support_material { | |||
|      | ||||
|     # generate paths for the pattern that we're going to use | ||||
|     Slic3r::debugf "Generating patterns\n"; | ||||
|     my $fill = Slic3r::Fill->new(print => $self->print); | ||||
|     my $support_patterns = []; | ||||
|     my $support_interface_patterns = []; | ||||
|     { | ||||
|  | @ -908,10 +909,7 @@ sub generate_support_material { | |||
|             push @angles, $angles[0] + 90; | ||||
|         } | ||||
|          | ||||
|         my $filler = Slic3r::Fill->filler($pattern); | ||||
|         $filler->bounding_box([ Slic3r::Geometry::bounding_box([ map @$_, map @$_, @areas ]) ]) | ||||
|             if $filler->can('bounding_box'); | ||||
|          | ||||
|         my $filler = $fill->filler($pattern); | ||||
|         my $make_pattern = sub { | ||||
|             my ($expolygon, $density) = @_; | ||||
|              | ||||
|  | @ -996,7 +994,7 @@ sub generate_support_material { | |||
|              | ||||
|             # make a solid base on bottom layer | ||||
|             if ($layer_id == 0) { | ||||
|                 my $filler = Slic3r::Fill->filler('rectilinear'); | ||||
|                 my $filler = $fill->filler('rectilinear'); | ||||
|                 $filler->angle($Slic3r::Config->support_material_angle + 90); | ||||
|                 foreach my $expolygon (@$islands) { | ||||
|                     my @paths = $filler->fill_surface( | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci