Add the full source of BambuStudio

using version 1.0.10
This commit is contained in:
lane.wei 2022-07-15 23:37:19 +08:00 committed by Lane.Wei
parent 30bcadab3e
commit 1555904bef
3771 changed files with 1251328 additions and 0 deletions

135
lib/Slic3r.pm Normal file
View file

@ -0,0 +1,135 @@
# This package loads all the non-GUI Slic3r perl packages.
package Slic3r;
# Copyright holder: Alessandro Ranellucci
# This application is licensed under the GNU Affero General Public License, version 3
use strict;
use warnings;
use Config;
require v5.10;
our $VERSION = VERSION();
our $BUILD = BUILD();
our $FORK_NAME = FORK_NAME();
our $debug = 0;
sub debugf {
printf @_ if $debug;
}
our $loglevel = 0;
BEGIN {
$debug = 1 if (defined($ENV{'SLIC3R_DEBUGOUT'}) && $ENV{'SLIC3R_DEBUGOUT'} == 1);
print "Debugging output enabled\n" if $debug;
}
use FindBin;
# Let the XS module know where the GUI resources reside.
set_resources_dir(decode_path($FindBin::Bin) . (($^O eq 'darwin') ? '/../Resources' : '/resources'));
set_var_dir(resources_dir() . "/images");
set_local_dir(resources_dir() . "/i18n/");
use Moo 1.003001;
use Slic3r::XS; # import all symbols (constants etc.) before they get parsed
use Slic3r::Config;
use Slic3r::ExPolygon;
use Slic3r::ExtrusionLoop;
use Slic3r::ExtrusionPath;
use Slic3r::Flow;
use Slic3r::GCode::Reader;
use Slic3r::Geometry::Clipper;
use Slic3r::Layer;
use Slic3r::Line;
use Slic3r::Model;
use Slic3r::Point;
use Slic3r::Polygon;
use Slic3r::Polyline;
use Slic3r::Print::Object;
use Slic3r::Surface;
our $build = eval "use Slic3r::Build; 1";
# Scaling between the float and integer coordinates.
# Floats are in mm.
use constant SCALING_FACTOR => 0.000001;
# Set the logging level at the Slic3r XS module.
$Slic3r::loglevel = (defined($ENV{'SLIC3R_LOGLEVEL'}) && $ENV{'SLIC3R_LOGLEVEL'} =~ /^[1-9]/) ? $ENV{'SLIC3R_LOGLEVEL'} : 0;
set_logging_level($Slic3r::loglevel);
# Let the palceholder parser evaluate one expression to initialize its local static macro_processor
# class instance in a thread safe manner.
Slic3r::GCode::PlaceholderParser->new->evaluate_boolean_expression('1==1');
# Open a file by converting $filename to local file system locales.
sub open {
my ($fh, $mode, $filename) = @_;
return CORE::open $$fh, $mode, encode_path($filename);
}
sub tags {
my ($format) = @_;
$format //= '';
my %tags;
# End of line
$tags{eol} = ($format eq 'html') ? '<br>' : "\n";
# Heading
$tags{h2start} = ($format eq 'html') ? '<b>' : '';
$tags{h2end} = ($format eq 'html') ? '</b>' : '';
# Bold font
$tags{bstart} = ($format eq 'html') ? '<b>' : '';
$tags{bend} = ($format eq 'html') ? '</b>' : '';
# Verbatim
$tags{vstart} = ($format eq 'html') ? '<pre>' : '';
$tags{vend} = ($format eq 'html') ? '</pre>' : '';
return %tags;
}
sub slic3r_info
{
my (%params) = @_;
my %tag = Slic3r::tags($params{format});
my $out = '';
$out .= "$tag{bstart}$Slic3r::FORK_NAME$tag{bend}$tag{eol}";
$out .= "$tag{bstart}Version: $tag{bend}$Slic3r::VERSION$tag{eol}";
$out .= "$tag{bstart}Build: $tag{bend}$Slic3r::BUILD$tag{eol}";
return $out;
}
sub copyright_info
{
my (%params) = @_;
my %tag = Slic3r::tags($params{format});
my $out =
'Copyright &copy; Bambu Studio.';
return $out;
}
sub system_info
{
my (%params) = @_;
my %tag = Slic3r::tags($params{format});
my $out = '';
$out .= "$tag{bstart}Operating System: $tag{bend}$Config{osname}$tag{eol}";
$out .= "$tag{bstart}System Architecture: $tag{bend}$Config{archname}$tag{eol}";
if ($^O eq 'MSWin32') {
$out .= "$tag{bstart}Windows Version: $tag{bend}" . `ver` . $tag{eol};
} else {
# Hopefully some kind of unix / linux.
$out .= "$tag{bstart}System Version: $tag{bend}" . `uname -a` . $tag{eol};
}
$out .= $tag{vstart} . Config::myconfig . $tag{vend};
$out .= " $tag{bstart}\@INC:$tag{bend}$tag{eol}$tag{vstart}";
foreach my $i (@INC) {
$out .= " $i\n";
}
$out .= "$tag{vend}";
return $out;
}
1;

76
lib/Slic3r/Config.pm Normal file
View file

@ -0,0 +1,76 @@
# Extends C++ class Slic3r::DynamicPrintConfig
# This perl class does not keep any perl class variables,
# all the storage is handled by the underlying C++ code.
package Slic3r::Config;
use strict;
use warnings;
use utf8;
use List::Util qw(first max);
# C++ Slic3r::PrintConfigDef exported as a Perl hash of hashes.
# The C++ counterpart is a constant singleton.
our $Options = print_config_def();
# Generate accessors.
{
no strict 'refs';
for my $opt_key (keys %$Options) {
*{$opt_key} = sub {
#print "Slic3r::Config::accessor $opt_key\n";
$_[0]->get($opt_key)
};
}
}
# From command line parameters, used by slic3r.pl
sub new_from_cli {
my $class = shift;
my %args = @_;
# Delete hash keys with undefined value.
delete $args{$_} for grep !defined $args{$_}, keys %args;
# Replace the start_gcode, end_gcode ... hash values
# with the content of the files they reference.
for (qw(start end layer toolchange)) {
my $opt_key = "${_}_gcode";
if ($args{$opt_key}) {
if (-e $args{$opt_key}) {
Slic3r::open(\my $fh, "<", $args{$opt_key})
or die "Failed to open $args{$opt_key}\n";
binmode $fh, ':utf8';
$args{$opt_key} = do { local $/; <$fh> };
close $fh;
}
}
}
my $self = $class->new;
foreach my $opt_key (keys %args) {
my $opt_def = $Options->{$opt_key};
# we use set_deserialize() for bool options since GetOpt::Long doesn't handle
# arrays of boolean values
if ($opt_key =~ /^(?:bed_shape|duplicate_grid|extruder_offset)$/ || $opt_def->{type} eq 'bool') {
$self->set_deserialize($opt_key, $args{$opt_key});
} elsif (my $shortcut = $opt_def->{shortcut}) {
$self->set($_, $args{$opt_key}) for @$shortcut;
} else {
$self->set($opt_key, $args{$opt_key});
}
}
return $self;
}
package Slic3r::Config::Static;
use parent 'Slic3r::Config';
sub Slic3r::Config::GCode::new { Slic3r::Config::Static::new_GCodeConfig }
sub Slic3r::Config::Print::new { Slic3r::Config::Static::new_PrintConfig }
sub Slic3r::Config::PrintObject::new { Slic3r::Config::Static::new_PrintObjectConfig }
sub Slic3r::Config::PrintRegion::new { Slic3r::Config::Static::new_PrintRegionConfig }
sub Slic3r::Config::Full::new { Slic3r::Config::Static::new_FullPrintConfig }
1;

39
lib/Slic3r/ExPolygon.pm Normal file
View file

@ -0,0 +1,39 @@
package Slic3r::ExPolygon;
use strict;
use warnings;
# an ExPolygon is a polygon with holes
use List::Util qw(first);
use Slic3r::Geometry::Clipper qw(union_ex diff_pl);
sub offset {
my $self = shift;
return Slic3r::Geometry::Clipper::offset(\@$self, @_);
}
sub offset_ex {
my $self = shift;
return Slic3r::Geometry::Clipper::offset_ex(\@$self, @_);
}
sub noncollapsing_offset_ex {
my $self = shift;
my ($distance, @params) = @_;
return $self->offset_ex($distance + 1, @params);
}
sub bounding_box {
my $self = shift;
return $self->contour->bounding_box;
}
package Slic3r::ExPolygon::Collection;
sub size {
my $self = shift;
return [ Slic3r::Geometry::size_2D([ map @$_, map @$_, @$self ]) ];
}
1;

View file

@ -0,0 +1,12 @@
package Slic3r::ExtrusionLoop;
use strict;
use warnings;
use parent qw(Exporter);
our @EXPORT_OK = qw(EXTRL_ROLE_DEFAULT
EXTRL_ROLE_CONTOUR_INTERNAL_PERIMETER EXTRL_ROLE_SKIRT);
our %EXPORT_TAGS = (roles => \@EXPORT_OK);
1;

View file

@ -0,0 +1,13 @@
package Slic3r::ExtrusionPath;
use strict;
use warnings;
use parent qw(Exporter);
our @EXPORT_OK = qw(EXTR_ROLE_PERIMETER EXTR_ROLE_EXTERNAL_PERIMETER EXTR_ROLE_OVERHANG_PERIMETER
EXTR_ROLE_FILL EXTR_ROLE_SOLIDFILL EXTR_ROLE_TOPSOLIDFILL EXTR_ROLE_GAPFILL EXTR_ROLE_BRIDGE
EXTR_ROLE_SKIRT EXTR_ROLE_SUPPORTMATERIAL EXTR_ROLE_SUPPORTMATERIAL_INTERFACE
EXTR_ROLE_NONE);
our %EXPORT_TAGS = (roles => \@EXPORT_OK);
1;

13
lib/Slic3r/Flow.pm Normal file
View file

@ -0,0 +1,13 @@
package Slic3r::Flow;
use strict;
use warnings;
use parent qw(Exporter);
our @EXPORT_OK = qw(FLOW_ROLE_EXTERNAL_PERIMETER FLOW_ROLE_PERIMETER FLOW_ROLE_INFILL
FLOW_ROLE_SOLID_INFILL
FLOW_ROLE_TOP_SOLID_INFILL FLOW_ROLE_SUPPORT_MATERIAL
FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE);
our %EXPORT_TAGS = (roles => \@EXPORT_OK);
1;

View file

@ -0,0 +1,90 @@
# Helper module to parse and interpret a G-code file,
# invoking a callback for each move extracted from the G-code.
# Currently used by the automatic tests only.
package Slic3r::GCode::Reader;
use Moo;
has 'config' => (is => 'ro', default => sub { Slic3r::Config::GCode->new });
has 'X' => (is => 'rw', default => sub {0});
has 'Y' => (is => 'rw', default => sub {0});
has 'Z' => (is => 'rw', default => sub {0});
has 'E' => (is => 'rw', default => sub {0});
has 'F' => (is => 'rw', default => sub {0});
has '_extrusion_axis' => (is => 'rw', default => sub {"E"});
our $Verbose = 0;
my @AXES = qw(X Y Z E);
sub apply_print_config {
my ($self, $print_config) = @_;
$self->config->apply_static($print_config);
$self->_extrusion_axis($self->config->get_extrusion_axis);
}
sub clone {
my $self = shift;
return (ref $self)->new(
map { $_ => $self->$_ } (@AXES, 'F', '_extrusion_axis', 'config'),
);
}
sub parse {
my $self = shift;
my ($gcode, $cb) = @_;
foreach my $raw_line (split /\R+/, $gcode) {
print "$raw_line\n" if $Verbose || $ENV{SLIC3R_TESTS_GCODE};
my $line = $raw_line;
$line =~ s/\s*;(.*)//; # strip comment
my %info = (comment => $1, raw => $raw_line);
# parse command
my ($command, @args) = split /\s+/, $line;
$command //= '';
my %args = map { /([A-Z])(.*)/; ($1 => $2) } @args;
# convert extrusion axis
if (exists $args{ $self->_extrusion_axis }) {
$args{E} = $args{ $self->_extrusion_axis };
}
# check motion
if ($command =~ /^G[01]$/) {
foreach my $axis (@AXES) {
if (exists $args{$axis}) {
$self->$axis(0) if $axis eq 'E' && $self->config->use_relative_e_distances;
$info{"dist_$axis"} = $args{$axis} - $self->$axis;
$info{"new_$axis"} = $args{$axis};
} else {
$info{"dist_$axis"} = 0;
$info{"new_$axis"} = $self->$axis;
}
}
$info{dist_XY} = sqrt(($info{dist_X}**2) + ($info{dist_Y}**2));
if (exists $args{E}) {
if ($info{dist_E} > 0) {
$info{extruding} = 1;
} elsif ($info{dist_E} < 0) {
$info{retracting} = 1
}
} else {
$info{travel} = 1;
}
}
# run callback
$cb->($self, $command, \%args, \%info);
# update coordinates
if ($command =~ /^(?:G[01]|G92)$/) {
for my $axis (@AXES, 'F') {
$self->$axis($args{$axis}) if exists $args{$axis};
}
}
# TODO: update temperatures
}
}
1;

271
lib/Slic3r/Geometry.pm Normal file
View file

@ -0,0 +1,271 @@
package Slic3r::Geometry;
use strict;
use warnings;
require Exporter;
our @ISA = qw(Exporter);
# Exported by this module. The last section starting with convex_hull is exported by Geometry.xsp
our @EXPORT_OK = qw(
PI epsilon
angle3points
collinear
dot
line_intersection
normalize
point_in_segment
polyline_lines
polygon_is_convex
polygon_segment_having_point
scale
unscale
scaled_epsilon
size_2D
X Y Z
convex_hull
chained_path_from
deg2rad
rad2deg
rad2deg_dir
);
use constant PI => 4 * atan2(1, 1);
use constant A => 0;
use constant B => 1;
use constant X1 => 0;
use constant Y1 => 1;
use constant X2 => 2;
use constant Y2 => 3;
sub epsilon () { 1E-4 }
sub scaled_epsilon () { epsilon / &Slic3r::SCALING_FACTOR }
sub scale ($) { $_[0] / &Slic3r::SCALING_FACTOR }
sub unscale ($) { $_[0] * &Slic3r::SCALING_FACTOR }
# used by geometry.t, polygon_segment_having_point
sub point_in_segment {
my ($point, $line) = @_;
my ($x, $y) = @$point;
my $line_p = $line->pp;
my @line_x = sort { $a <=> $b } $line_p->[A][X], $line_p->[B][X];
my @line_y = sort { $a <=> $b } $line_p->[A][Y], $line_p->[B][Y];
# check whether the point is in the segment bounding box
return 0 unless $x >= ($line_x[0] - epsilon) && $x <= ($line_x[1] + epsilon)
&& $y >= ($line_y[0] - epsilon) && $y <= ($line_y[1] + epsilon);
# if line is vertical, check whether point's X is the same as the line
if ($line_p->[A][X] == $line_p->[B][X]) {
return abs($x - $line_p->[A][X]) < epsilon ? 1 : 0;
}
# calculate the Y in line at X of the point
my $y3 = $line_p->[A][Y] + ($line_p->[B][Y] - $line_p->[A][Y])
* ($x - $line_p->[A][X]) / ($line_p->[B][X] - $line_p->[A][X]);
return abs($y3 - $y) < epsilon ? 1 : 0;
}
# used by geometry.t
sub polyline_lines {
my ($polyline) = @_;
my @points = @$polyline;
return map Slic3r::Line->new(@points[$_, $_+1]), 0 .. $#points-1;
}
# given a $polygon, return the (first) segment having $point
# used by geometry.t
sub polygon_segment_having_point {
my ($polygon, $point) = @_;
foreach my $line (@{ $polygon->lines }) {
return $line if point_in_segment($point, $line);
}
return undef;
}
# polygon must be simple (non complex) and ccw
sub polygon_is_convex {
my ($points) = @_;
for (my $i = 0; $i <= $#$points; $i++) {
my $angle = angle3points($points->[$i-1], $points->[$i-2], $points->[$i]);
return 0 if $angle < PI;
}
return 1;
}
sub normalize {
my ($line) = @_;
my $len = sqrt( ($line->[X]**2) + ($line->[Y]**2) + ($line->[Z]**2) )
or return [0, 0, 0]; # to avoid illegal division by zero
return [ map $_ / $len, @$line ];
}
# 2D dot product
# used by 3DScene.pm
sub dot {
my ($u, $v) = @_;
return $u->[X] * $v->[X] + $u->[Y] * $v->[Y];
}
sub line_intersection {
my ($line1, $line2, $require_crossing) = @_;
$require_crossing ||= 0;
my $intersection = _line_intersection(map @$_, @$line1, @$line2);
return (ref $intersection && $intersection->[1] == $require_crossing)
? $intersection->[0]
: undef;
}
# Used by test cases.
sub collinear {
my ($line1, $line2, $require_overlapping) = @_;
my $intersection = _line_intersection(map @$_, @$line1, @$line2);
return 0 unless !ref($intersection)
&& ($intersection eq 'parallel collinear'
|| ($intersection eq 'parallel vertical' && abs($line1->[A][X] - $line2->[A][X]) < epsilon));
if ($require_overlapping) {
my @box_a = bounding_box([ $line1->[0], $line1->[1] ]);
my @box_b = bounding_box([ $line2->[0], $line2->[1] ]);
return 0 unless bounding_box_intersect( 2, @box_a, @box_b );
}
return 1;
}
sub _line_intersection {
my ( $x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3 ) = @_;
my ($x, $y); # The as-yet-undetermined intersection point.
my $dy10 = $y1 - $y0; # dyPQ, dxPQ are the coordinate differences
my $dx10 = $x1 - $x0; # between the points P and Q.
my $dy32 = $y3 - $y2;
my $dx32 = $x3 - $x2;
my $dy10z = abs( $dy10 ) < epsilon; # Is the difference $dy10 "zero"?
my $dx10z = abs( $dx10 ) < epsilon;
my $dy32z = abs( $dy32 ) < epsilon;
my $dx32z = abs( $dx32 ) < epsilon;
my $dyx10; # The slopes.
my $dyx32;
$dyx10 = $dy10 / $dx10 unless $dx10z;
$dyx32 = $dy32 / $dx32 unless $dx32z;
# Now we know all differences and the slopes;
# we can detect horizontal/vertical special cases.
# E.g., slope = 0 means a horizontal line.
unless ( defined $dyx10 or defined $dyx32 ) {
return "parallel vertical";
}
elsif ( $dy10z and not $dy32z ) { # First line horizontal.
$y = $y0;
$x = $x2 + ( $y - $y2 ) * $dx32 / $dy32;
}
elsif ( not $dy10z and $dy32z ) { # Second line horizontal.
$y = $y2;
$x = $x0 + ( $y - $y0 ) * $dx10 / $dy10;
}
elsif ( $dx10z and not $dx32z ) { # First line vertical.
$x = $x0;
$y = $y2 + $dyx32 * ( $x - $x2 );
}
elsif ( not $dx10z and $dx32z ) { # Second line vertical.
$x = $x2;
$y = $y0 + $dyx10 * ( $x - $x0 );
}
elsif ( abs( $dyx10 - $dyx32 ) < epsilon ) {
# The slopes are suspiciously close to each other.
# Either we have parallel collinear or just parallel lines.
# The bounding box checks have already weeded the cases
# "parallel horizontal" and "parallel vertical" away.
my $ya = $y0 - $dyx10 * $x0;
my $yb = $y2 - $dyx32 * $x2;
return "parallel collinear" if abs( $ya - $yb ) < epsilon;
return "parallel";
}
else {
# None of the special cases matched.
# We have a "honest" line intersection.
$x = ($y2 - $y0 + $dyx10*$x0 - $dyx32*$x2)/($dyx10 - $dyx32);
$y = $y0 + $dyx10 * ($x - $x0);
}
my $h10 = $dx10 ? ($x - $x0) / $dx10 : ($dy10 ? ($y - $y0) / $dy10 : 1);
my $h32 = $dx32 ? ($x - $x2) / $dx32 : ($dy32 ? ($y - $y2) / $dy32 : 1);
return [Slic3r::Point->new($x, $y), $h10 >= 0 && $h10 <= 1 && $h32 >= 0 && $h32 <= 1];
}
# 2D
sub bounding_box {
my ($points) = @_;
my @x = map $_->x, @$points;
my @y = map $_->y, @$points; #,,
my @bb = (undef, undef, undef, undef);
for (0..$#x) {
$bb[X1] = $x[$_] if !defined $bb[X1] || $x[$_] < $bb[X1];
$bb[X2] = $x[$_] if !defined $bb[X2] || $x[$_] > $bb[X2];
$bb[Y1] = $y[$_] if !defined $bb[Y1] || $y[$_] < $bb[Y1];
$bb[Y2] = $y[$_] if !defined $bb[Y2] || $y[$_] > $bb[Y2];
}
return @bb[X1,Y1,X2,Y2];
}
# used by ExPolygon::size
sub size_2D {
my @bounding_box = bounding_box(@_);
return (
($bounding_box[X2] - $bounding_box[X1]),
($bounding_box[Y2] - $bounding_box[Y1]),
);
}
# Used by sub collinear, which is used by test cases.
# bounding_box_intersect($d, @a, @b)
# Return true if the given bounding boxes @a and @b intersect
# in $d dimensions. Used by sub collinear.
sub bounding_box_intersect {
my ( $d, @bb ) = @_; # Number of dimensions and box coordinates.
my @aa = splice( @bb, 0, 2 * $d ); # The first box.
# (@bb is the second one.)
# Must intersect in all dimensions.
for ( my $i_min = 0; $i_min < $d; $i_min++ ) {
my $i_max = $i_min + $d; # The index for the maximum.
return 0 if ( $aa[ $i_max ] + epsilon ) < $bb[ $i_min ];
return 0 if ( $bb[ $i_max ] + epsilon ) < $aa[ $i_min ];
}
return 1;
}
# Used by test cases.
# this assumes a CCW rotation from $p2 to $p3 around $p1
sub angle3points {
my ($p1, $p2, $p3) = @_;
# p1 is the center
my $angle = atan2($p2->[X] - $p1->[X], $p2->[Y] - $p1->[Y])
- atan2($p3->[X] - $p1->[X], $p3->[Y] - $p1->[Y]);
# we only want to return only positive angles
return $angle <= 0 ? $angle + 2*PI() : $angle;
}
1;

View file

@ -0,0 +1,14 @@
package Slic3r::Geometry::Clipper;
use strict;
use warnings;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(
offset
offset_ex offset2_ex
diff_ex diff union_ex intersection_ex
JT_ROUND JT_MITER JT_SQUARE
intersection intersection_pl diff_pl union);
1;

37
lib/Slic3r/Layer.pm Normal file
View file

@ -0,0 +1,37 @@
# Extends the C++ class Slic3r::Layer.
package Slic3r::Layer;
use strict;
use warnings;
# the following two were previously generated by Moo
sub print {
my $self = shift;
return $self->object->print;
}
sub config {
my $self = shift;
return $self->object->config;
}
sub region {
my $self = shift;
my ($region_id) = @_;
while ($self->region_count <= $region_id) {
$self->add_region($self->object->print->get_region($self->region_count));
}
return $self->get_region($region_id);
}
sub regions {
my ($self) = @_;
return [ map $self->get_region($_), 0..($self->region_count-1) ];
}
package Slic3r::Layer::Support;
our @ISA = qw(Slic3r::Layer);
1;

19
lib/Slic3r/Line.pm Normal file
View file

@ -0,0 +1,19 @@
package Slic3r::Line;
use strict;
use warnings;
# a line is a two-points line
use parent 'Slic3r::Polyline';
sub intersection {
my $self = shift;
my ($line, $require_crossing) = @_;
return Slic3r::Geometry::line_intersection($self, $line, $require_crossing);
}
sub grow {
my $self = shift;
return Slic3r::Polyline->new(@$self)->grow(@_);
}
1;

143
lib/Slic3r/Model.pm Normal file
View file

@ -0,0 +1,143 @@
# extends C++ class Slic3r::Model
package Slic3r::Model;
use List::Util qw(first max any);
sub merge {
my $class = shift;
my @models = @_;
my $new_model = ref($class)
? $class
: $class->new;
$new_model->add_object($_) for map @{$_->objects}, @models;
return $new_model;
}
sub add_object {
my $self = shift;
if (@_ == 1) {
# we have a Model::Object
my ($object) = @_;
return $self->_add_object_clone($object);
} else {
my (%args) = @_;
my $new_object = $self->_add_object;
$new_object->set_name($args{name})
if defined $args{name};
$new_object->set_input_file($args{input_file})
if defined $args{input_file};
$new_object->config->apply($args{config})
if defined $args{config};
$new_object->set_layer_height_ranges($args{layer_height_ranges})
if defined $args{layer_height_ranges};
$new_object->set_origin_translation($args{origin_translation})
if defined $args{origin_translation};
return $new_object;
}
}
sub set_material {
my $self = shift;
my ($material_id, $attributes) = @_;
my $material = $self->add_material($material_id);
$material->apply($attributes // {});
return $material;
}
# Extends C++ class Slic3r::ModelMaterial
package Slic3r::Model::Material;
sub apply {
my ($self, $attributes) = @_;
$self->set_attribute($_, $attributes{$_}) for keys %$attributes;
}
# Extends C++ class Slic3r::ModelObject
package Slic3r::Model::Object;
use List::Util qw(first sum);
sub add_volume {
my $self = shift;
my $new_volume;
if (@_ == 1) {
# we have a Model::Volume
my ($volume) = @_;
$new_volume = $self->_add_volume_clone($volume);
if ($volume->material_id ne '') {
# merge material attributes and config (should we rename materials in case of duplicates?)
if (my $material = $volume->object->model->get_material($volume->material_id)) {
my %attributes = %{ $material->attributes };
if ($self->model->has_material($volume->material_id)) {
%attributes = (%attributes, %{ $self->model->get_material($volume->material_id)->attributes })
}
my $new_material = $self->model->set_material($volume->material_id, {%attributes});
$new_material->config->apply($material->config);
}
}
} else {
my %args = @_;
$new_volume = $self->_add_volume($args{mesh});
$new_volume->set_name($args{name})
if defined $args{name};
$new_volume->set_material_id($args{material_id})
if defined $args{material_id};
$new_volume->set_modifier($args{modifier})
if defined $args{modifier};
$new_volume->config->apply($args{config})
if defined $args{config};
}
if ($new_volume->material_id ne '' && !defined $self->model->get_material($new_volume->material_id)) {
# TODO: this should be a trigger on Volume::material_id
$self->model->set_material($new_volume->material_id);
}
$self->invalidate_bounding_box;
return $new_volume;
}
sub add_instance {
my $self = shift;
if (@_ == 1) {
# we have a Model::Instance
my ($instance) = @_;
return $self->_add_instance_clone($instance);
} else {
my (%args) = @_;
my $new_instance = $self->_add_instance;
$new_instance->set_rotations($args{rotation})
if defined $args{rotation};
$new_instance->set_scaling_factors($args{scaling_factor})
if defined $args{scaling_factor};
$new_instance->set_offset($args{offset})
if defined $args{offset};
return $new_instance;
}
}
sub mesh_stats {
my $self = shift;
# TODO: sum values from all volumes
return $self->volumes->[0]->mesh->stats;
}
1;

28
lib/Slic3r/Point.pm Normal file
View file

@ -0,0 +1,28 @@
package Slic3r::Point;
use strict;
use warnings;
sub new_scale {
my $class = shift;
return $class->new(map Slic3r::Geometry::scale($_), @_);
}
package Slic3r::Pointf;
use strict;
use warnings;
sub new_unscale {
my $class = shift;
return $class->new(map Slic3r::Geometry::unscale($_), @_);
}
package Slic3r::Pointf3;
use strict;
use warnings;
sub new_unscale {
my $class = shift;
return $class->new(map Slic3r::Geometry::unscale($_), @_);
}
1;

13
lib/Slic3r/Polygon.pm Normal file
View file

@ -0,0 +1,13 @@
package Slic3r::Polygon;
use strict;
use warnings;
# a polygon is a closed polyline.
use parent 'Slic3r::Polyline';
sub grow {
my $self = shift;
return $self->split_at_first_point->grow(@_);
}
1;

13
lib/Slic3r/Polyline.pm Normal file
View file

@ -0,0 +1,13 @@
package Slic3r::Polyline;
use strict;
use warnings;
use Slic3r::Geometry qw(X Y);
sub new_scale {
my $class = shift;
my @points = map { ref($_) eq 'Slic3r::Point' ? $_->pp : $_ } @_;
return $class->new(map [ Slic3r::Geometry::scale($_->[X]), Slic3r::Geometry::scale($_->[Y]) ], @points);
}
1;

View file

@ -0,0 +1,24 @@
package Slic3r::Print::Object;
# extends c++ class Slic3r::PrintObject (Print.xsp)
use strict;
use warnings;
use List::Util qw(min max sum first);
use Slic3r::Flow ':roles';
use Slic3r::Geometry qw(scale epsilon);
use Slic3r::Geometry::Clipper qw(diff diff_ex intersection intersection_ex union union_ex
offset offset_ex offset2_ex JT_MITER);
use Slic3r::Print::State ':steps';
use Slic3r::Surface ':types';
sub layers {
my $self = shift;
return [ map $self->get_layer($_), 0..($self->layer_count - 1) ];
}
sub support_layers {
my $self = shift;
return [ map $self->get_support_layer($_), 0..($self->support_layer_count - 1) ];
}
1;

12
lib/Slic3r/Print/State.pm Normal file
View file

@ -0,0 +1,12 @@
# Wraps C++ enums Slic3r::PrintStep and Slic3r::PrintObjectStep
package Slic3r::Print::State;
use strict;
use warnings;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(STEP_SLICE STEP_PERIMETERS STEP_PREPARE_INFILL
STEP_INFILL STEP_SUPPORTMATERIAL STEP_SKIRT STEP_BRIM STEP_WIPE_TOWER);
our %EXPORT_TAGS = (steps => \@EXPORT_OK);
1;

15
lib/Slic3r/Surface.pm Normal file
View file

@ -0,0 +1,15 @@
package Slic3r::Surface;
use strict;
use warnings;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(S_TYPE_TOP S_TYPE_BOTTOM S_TYPE_BOTTOMBRIDGE S_TYPE_INTERNAL S_TYPE_INTERNALSOLID S_TYPE_INTERNALBRIDGE S_TYPE_INTERNALVOID);
our %EXPORT_TAGS = (types => \@EXPORT_OK);
sub p {
my $self = shift;
return @{$self->polygons};
}
1;

261
lib/Slic3r/Test.pm Normal file

File diff suppressed because one or more lines are too long