mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	
		
			
				
	
	
		
			196 lines
		
	
	
	
		
			5.6 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			196 lines
		
	
	
	
		
			5.6 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
| package Slic3r::ExtrusionPath;
 | |
| use Moo;
 | |
| 
 | |
| require Exporter;
 | |
| our @ISA = qw(Exporter);
 | |
| our @EXPORT_OK = qw(EXTR_ROLE_PERIMETER EXTR_ROLE_EXTERNAL_PERIMETER 
 | |
|     EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER EXTR_ROLE_OVERHANG_PERIMETER
 | |
|     EXTR_ROLE_FILL EXTR_ROLE_SOLIDFILL EXTR_ROLE_TOPSOLIDFILL EXTR_ROLE_BRIDGE 
 | |
|     EXTR_ROLE_INTERNALBRIDGE EXTR_ROLE_SKIRT EXTR_ROLE_SUPPORTMATERIAL EXTR_ROLE_GAPFILL);
 | |
| our %EXPORT_TAGS = (roles => \@EXPORT_OK);
 | |
| 
 | |
| use Slic3r::Geometry qw(PI X Y epsilon deg2rad rotate_points);
 | |
| 
 | |
| # the underlying Slic3r::Polyline objects holds the geometry
 | |
| has 'polyline' => (
 | |
|     is          => 'rw',
 | |
|     required    => 1,
 | |
|     handles     => [qw(merge_continuous_lines lines length reverse clip_end)],
 | |
| );
 | |
| 
 | |
| # height is the vertical thickness of the extrusion expressed in mm
 | |
| has 'height'       => (is => 'rw');
 | |
| has 'flow_spacing' => (is => 'rw', required => 1);
 | |
| has 'role'         => (is => 'rw', required => 1);
 | |
| 
 | |
| use constant EXTR_ROLE_PERIMETER                    => 0;
 | |
| use constant EXTR_ROLE_EXTERNAL_PERIMETER           => 1;
 | |
| use constant EXTR_ROLE_OVERHANG_PERIMETER           => 2;
 | |
| use constant EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER   => 3;
 | |
| use constant EXTR_ROLE_FILL                         => 4;
 | |
| use constant EXTR_ROLE_SOLIDFILL                    => 5;
 | |
| use constant EXTR_ROLE_TOPSOLIDFILL                 => 6;
 | |
| use constant EXTR_ROLE_BRIDGE                       => 7;
 | |
| use constant EXTR_ROLE_INTERNALBRIDGE               => 8;
 | |
| use constant EXTR_ROLE_SKIRT                        => 9;
 | |
| use constant EXTR_ROLE_SUPPORTMATERIAL              => 10;
 | |
| use constant EXTR_ROLE_GAPFILL                      => 11;
 | |
| 
 | |
| use constant PACK_FMT => 'ffca*';
 | |
| 
 | |
| # class or object method
 | |
| sub pack {
 | |
|     my $self = shift;
 | |
|     my %args = @_;
 | |
|     
 | |
|     if (ref $self) {
 | |
|         %args = map { $_ => $self->$_ } qw(height flow_spacing role polyline);
 | |
|     }
 | |
|     
 | |
|     my $o = \ pack PACK_FMT,
 | |
|         $args{height}       // -1,
 | |
|         $args{flow_spacing} || -1,
 | |
|         $args{role}         // (die "Missing mandatory attribute 'role'"), #/
 | |
|         $args{polyline}->serialize;
 | |
|     
 | |
|     bless $o, 'Slic3r::ExtrusionPath::Packed';
 | |
|     return $o;
 | |
| }
 | |
| 
 | |
| # no-op, this allows to use both packed and non-packed objects in Collections
 | |
| sub unpack { $_[0] }
 | |
| 
 | |
| sub clone {
 | |
|     my $self = shift;
 | |
|     my %p = @_;
 | |
|     
 | |
|     $p{polyline} ||= $self->polyline->clone;
 | |
|     return (ref $self)->new(
 | |
|         (map { $_ => $self->$_ } qw(polyline height flow_spacing role)),
 | |
|         %p,
 | |
|     );
 | |
| }
 | |
| 
 | |
| sub clip_with_polygon {
 | |
|     my $self = shift;
 | |
|     my ($polygon) = @_;
 | |
|     
 | |
|     return $self->clip_with_expolygon(Slic3r::ExPolygon->new($polygon));
 | |
| }
 | |
| 
 | |
| sub clip_with_expolygon {
 | |
|     my $self = shift;
 | |
|     my ($expolygon) = @_;
 | |
|     
 | |
|     return map $self->clone(polyline => $_),
 | |
|         $self->polyline->clip_with_expolygon($expolygon);
 | |
| }
 | |
| 
 | |
| sub intersect_expolygons {
 | |
|     my $self = shift;
 | |
|     my ($expolygons) = @_;
 | |
|     
 | |
|     return map $self->clone(polyline => Slic3r::Polyline->new(@$_)),
 | |
|         @{Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection($expolygons, [$self->polyline])};
 | |
| }
 | |
| 
 | |
| sub subtract_expolygons {
 | |
|     my $self = shift;
 | |
|     my ($expolygons) = @_;
 | |
|     
 | |
|     return map $self->clone(polyline => Slic3r::Polyline->new(@$_)),
 | |
|         @{Boost::Geometry::Utils::multi_linestring_multi_polygon_difference([$self->polyline], $expolygons)};
 | |
| }
 | |
| 
 | |
| sub simplify {
 | |
|     my $self = shift;
 | |
|     $self->polyline($self->polyline->simplify(@_));
 | |
| }
 | |
| 
 | |
| sub points {
 | |
|     my $self = shift;
 | |
|     return $self->polyline;
 | |
| }
 | |
| 
 | |
| sub first_point {
 | |
|     my $self = shift;
 | |
|     return $self->polyline->[0];
 | |
| }
 | |
| 
 | |
| sub last_point {
 | |
|     my $self = shift;
 | |
|     return $self->polyline->[-1];
 | |
| }
 | |
| 
 | |
| sub is_perimeter {
 | |
|     my $self = shift;
 | |
|     return $self->role == EXTR_ROLE_PERIMETER
 | |
|         || $self->role == EXTR_ROLE_EXTERNAL_PERIMETER
 | |
|         || $self->role == EXTR_ROLE_OVERHANG_PERIMETER
 | |
|         || $self->role == EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER;
 | |
| }
 | |
| 
 | |
| sub is_fill {
 | |
|     my $self = shift;
 | |
|     return $self->role == EXTR_ROLE_FILL
 | |
|         || $self->role == EXTR_ROLE_SOLIDFILL
 | |
|         || $self->role == EXTR_ROLE_TOPSOLIDFILL;
 | |
| }
 | |
| 
 | |
| sub is_bridge {
 | |
|     my $self = shift;
 | |
|     return $self->role == EXTR_ROLE_BRIDGE
 | |
|         || $self->role == EXTR_ROLE_INTERNALBRIDGE
 | |
|         || $self->role == EXTR_ROLE_OVERHANG_PERIMETER;
 | |
| }
 | |
| 
 | |
| sub split_at_acute_angles {
 | |
|     my $self = shift;
 | |
|     
 | |
|     # calculate angle limit
 | |
|     my $angle_limit = abs(Slic3r::Geometry::deg2rad(40));
 | |
|     my @points = @{$self->p};
 | |
|     
 | |
|     my @paths = ();
 | |
|     
 | |
|     # take first two points
 | |
|     my @p = splice @points, 0, 2;
 | |
|     
 | |
|     # loop until we have one spare point
 | |
|     while (my $p3 = shift @points) {
 | |
|         my $angle = abs(Slic3r::Geometry::angle3points($p[-1], $p[-2], $p3));
 | |
|         $angle = 2*PI - $angle if $angle > PI;
 | |
|         
 | |
|         if ($angle < $angle_limit) {
 | |
|             # if the angle between $p[-2], $p[-1], $p3 is too acute
 | |
|             # then consider $p3 only as a starting point of a new
 | |
|             # path and stop the current one as it is
 | |
|             push @paths, $self->clone(polyline => Slic3r::Polyline->new(@p));
 | |
|             @p = ($p3);
 | |
|             push @p, grep $_, shift @points or last;
 | |
|         } else {
 | |
|             push @p, $p3;
 | |
|         }
 | |
|     }
 | |
|     push @paths, $self->clone(polyline => Slic3r::Polyline->new(@p))
 | |
|         if @p > 1;
 | |
|     
 | |
|     return @paths;
 | |
| }
 | |
| 
 | |
| package Slic3r::ExtrusionPath::Packed;
 | |
| sub unpack {
 | |
|     my $self = shift;
 | |
|     
 | |
|     my ($height, $flow_spacing, $role, $polyline_s)
 | |
|         = unpack Slic3r::ExtrusionPath::PACK_FMT, $$self;
 | |
|     
 | |
|     return Slic3r::ExtrusionPath->new(
 | |
|         height          => ($height == -1) ? undef : $height,
 | |
|         flow_spacing    => ($flow_spacing == -1) ? undef : $flow_spacing,
 | |
|         role            => $role,
 | |
|         polyline        => Slic3r::Polyline->deserialize($polyline_s),
 | |
|     );
 | |
| }
 | |
| 
 | |
| 1;
 | 
