mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-11-02 20:51:23 -07:00
Add the full source of BambuStudio
using version 1.0.10
This commit is contained in:
parent
30bcadab3e
commit
1555904bef
3771 changed files with 1251328 additions and 0 deletions
135
lib/Slic3r.pm
Normal file
135
lib/Slic3r.pm
Normal 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 © 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
76
lib/Slic3r/Config.pm
Normal 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
39
lib/Slic3r/ExPolygon.pm
Normal 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;
|
||||
12
lib/Slic3r/ExtrusionLoop.pm
Normal file
12
lib/Slic3r/ExtrusionLoop.pm
Normal 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;
|
||||
13
lib/Slic3r/ExtrusionPath.pm
Normal file
13
lib/Slic3r/ExtrusionPath.pm
Normal 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
13
lib/Slic3r/Flow.pm
Normal 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;
|
||||
90
lib/Slic3r/GCode/Reader.pm
Normal file
90
lib/Slic3r/GCode/Reader.pm
Normal 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
271
lib/Slic3r/Geometry.pm
Normal 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;
|
||||
14
lib/Slic3r/Geometry/Clipper.pm
Normal file
14
lib/Slic3r/Geometry/Clipper.pm
Normal 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
37
lib/Slic3r/Layer.pm
Normal 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
19
lib/Slic3r/Line.pm
Normal 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
143
lib/Slic3r/Model.pm
Normal 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
28
lib/Slic3r/Point.pm
Normal 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
13
lib/Slic3r/Polygon.pm
Normal 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
13
lib/Slic3r/Polyline.pm
Normal 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;
|
||||
24
lib/Slic3r/Print/Object.pm
Normal file
24
lib/Slic3r/Print/Object.pm
Normal 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
12
lib/Slic3r/Print/State.pm
Normal 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
15
lib/Slic3r/Surface.pm
Normal 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
261
lib/Slic3r/Test.pm
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue