Defined the +-* operators on Pointf.
Removed the deprecated VibrationLimit feature. Added triangle infill. The Prusa3D fork of Slic3r has been marked as "Slic3r Prusa Edition" with menus pointing to the prusa3d/slic3r github release page and Prusa3D drivers downloads page.
This commit is contained in:
parent
15d3e94a66
commit
1fb57e439e
@ -140,8 +140,6 @@ The author of the Silk icon set is Mark James.
|
|||||||
--gcode-arcs Use G2/G3 commands for native arcs (experimental, not supported
|
--gcode-arcs Use G2/G3 commands for native arcs (experimental, not supported
|
||||||
by all firmwares)
|
by all firmwares)
|
||||||
--gcode-comments Make G-code verbose by adding comments (default: no)
|
--gcode-comments Make G-code verbose by adding comments (default: no)
|
||||||
--vibration-limit Limit the frequency of moves on X and Y axes (Hz, set zero to disable;
|
|
||||||
default: 0)
|
|
||||||
--pressure-advance Adjust pressure using the experimental advance algorithm (K constant,
|
--pressure-advance Adjust pressure using the experimental advance algorithm (K constant,
|
||||||
set zero to disable; default: 0)
|
set zero to disable; default: 0)
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ use warnings;
|
|||||||
require v5.10;
|
require v5.10;
|
||||||
|
|
||||||
our $VERSION = VERSION();
|
our $VERSION = VERSION();
|
||||||
|
our $FORK_NAME = FORK_NAME();
|
||||||
|
|
||||||
our $debug = 0;
|
our $debug = 0;
|
||||||
sub debugf {
|
sub debugf {
|
||||||
@ -67,7 +68,6 @@ use Slic3r::GCode::MotionPlanner;
|
|||||||
use Slic3r::GCode::PressureRegulator;
|
use Slic3r::GCode::PressureRegulator;
|
||||||
use Slic3r::GCode::Reader;
|
use Slic3r::GCode::Reader;
|
||||||
use Slic3r::GCode::SpiralVase;
|
use Slic3r::GCode::SpiralVase;
|
||||||
use Slic3r::GCode::VibrationLimit;
|
|
||||||
use Slic3r::Geometry qw(PI);
|
use Slic3r::Geometry qw(PI);
|
||||||
use Slic3r::Geometry::Clipper;
|
use Slic3r::Geometry::Clipper;
|
||||||
use Slic3r::Layer;
|
use Slic3r::Layer;
|
||||||
|
@ -12,7 +12,7 @@ use List::Util qw(first max);
|
|||||||
our @Ignore = qw(duplicate_x duplicate_y multiply_x multiply_y support_material_tool acceleration
|
our @Ignore = qw(duplicate_x duplicate_y multiply_x multiply_y support_material_tool acceleration
|
||||||
adjust_overhang_flow standby_temperature scale rotate duplicate duplicate_grid
|
adjust_overhang_flow standby_temperature scale rotate duplicate duplicate_grid
|
||||||
rotate scale duplicate_grid start_perimeters_at_concave_points start_perimeters_at_non_overhang
|
rotate scale duplicate_grid start_perimeters_at_concave_points start_perimeters_at_non_overhang
|
||||||
randomize_start seal_position bed_size print_center g0);
|
randomize_start seal_position bed_size print_center g0 vibration_limit);
|
||||||
|
|
||||||
# C++ Slic3r::PrintConfigDef exported as a Perl hash of hashes.
|
# C++ Slic3r::PrintConfigDef exported as a Perl hash of hashes.
|
||||||
# The C++ counterpart is a constant singleton.
|
# The C++ counterpart is a constant singleton.
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
package Slic3r::GCode::VibrationLimit;
|
|
||||||
use Moo;
|
|
||||||
|
|
||||||
extends 'Slic3r::GCode::Reader';
|
|
||||||
|
|
||||||
has '_min_time' => (is => 'lazy');
|
|
||||||
has '_last_dir' => (is => 'ro', default => sub { [0,0] });
|
|
||||||
has '_dir_time' => (is => 'ro', default => sub { [0,0] });
|
|
||||||
|
|
||||||
# inspired by http://hydraraptor.blogspot.it/2010/12/frequency-limit.html
|
|
||||||
|
|
||||||
use List::Util qw(max);
|
|
||||||
|
|
||||||
sub _build__min_time {
|
|
||||||
my ($self) = @_;
|
|
||||||
return 1 / ($self->config->vibration_limit * 60); # in minutes
|
|
||||||
}
|
|
||||||
|
|
||||||
sub process {
|
|
||||||
my $self = shift;
|
|
||||||
my ($gcode) = @_;
|
|
||||||
|
|
||||||
my $new_gcode = "";
|
|
||||||
$self->parse($gcode, sub {
|
|
||||||
my ($reader, $cmd, $args, $info) = @_;
|
|
||||||
|
|
||||||
if ($cmd eq 'G1' && $info->{dist_XY} > 0) {
|
|
||||||
my $point = Slic3r::Pointf->new($args->{X} // $reader->X, $args->{Y} // $reader->Y);
|
|
||||||
my @dir = (
|
|
||||||
($point->x <=> $reader->X),
|
|
||||||
($point->y <=> $reader->Y), #$
|
|
||||||
);
|
|
||||||
my $time = $info->{dist_XY} / ($args->{F} // $reader->F); # in minutes
|
|
||||||
|
|
||||||
if ($time > 0) {
|
|
||||||
my @pause = ();
|
|
||||||
foreach my $axis (0..$#dir) {
|
|
||||||
if ($dir[$axis] != 0 && $self->_last_dir->[$axis] != $dir[$axis]) {
|
|
||||||
if ($self->_last_dir->[$axis] != 0) {
|
|
||||||
# this axis is changing direction: check whether we need to pause
|
|
||||||
if ($self->_dir_time->[$axis] < $self->_min_time) {
|
|
||||||
push @pause, ($self->_min_time - $self->_dir_time->[$axis]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$self->_last_dir->[$axis] = $dir[$axis];
|
|
||||||
$self->_dir_time->[$axis] = 0;
|
|
||||||
}
|
|
||||||
$self->_dir_time->[$axis] += $time;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (@pause) {
|
|
||||||
$new_gcode .= sprintf "G4 P%d\n", max(@pause) * 60 * 1000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$new_gcode .= $info->{raw} . "\n";
|
|
||||||
});
|
|
||||||
|
|
||||||
return $new_gcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -90,6 +90,7 @@ sub OnInit {
|
|||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
$self->SetAppName('Slic3r');
|
$self->SetAppName('Slic3r');
|
||||||
|
$self->SetAppDisplayName('Slic3r Prusa Edition');
|
||||||
Slic3r::debugf "wxWidgets version %s, Wx version %s\n", &Wx::wxVERSION_STRING, $Wx::VERSION;
|
Slic3r::debugf "wxWidgets version %s, Wx version %s\n", &Wx::wxVERSION_STRING, $Wx::VERSION;
|
||||||
|
|
||||||
$self->{notifier} = Slic3r::GUI::Notifier->new;
|
$self->{notifier} = Slic3r::GUI::Notifier->new;
|
||||||
|
@ -27,7 +27,7 @@ sub new {
|
|||||||
$hsizer->Add($vsizer, 1, wxEXPAND, 0);
|
$hsizer->Add($vsizer, 1, wxEXPAND, 0);
|
||||||
|
|
||||||
# title
|
# title
|
||||||
my $title = Wx::StaticText->new($self, -1, 'Slic3r', wxDefaultPosition, wxDefaultSize);
|
my $title = Wx::StaticText->new($self, -1, $Slic3r::FORK_NAME, wxDefaultPosition, wxDefaultSize);
|
||||||
my $title_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
my $title_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
||||||
$title_font->SetWeight(wxFONTWEIGHT_BOLD);
|
$title_font->SetWeight(wxFONTWEIGHT_BOLD);
|
||||||
$title_font->SetFamily(wxFONTFAMILY_ROMAN);
|
$title_font->SetFamily(wxFONTFAMILY_ROMAN);
|
||||||
@ -47,6 +47,7 @@ sub new {
|
|||||||
'<html>' .
|
'<html>' .
|
||||||
'<body bgcolor="#ffffff" link="#808080">' .
|
'<body bgcolor="#ffffff" link="#808080">' .
|
||||||
'<font color="#808080">' .
|
'<font color="#808080">' .
|
||||||
|
'Copyright © 2016 Vojtech Bubnik, Prusa Research. <br />' .
|
||||||
'Copyright © 2011-2016 Alessandro Ranellucci. <br />' .
|
'Copyright © 2011-2016 Alessandro Ranellucci. <br />' .
|
||||||
'<a href="http://slic3r.org/">Slic3r</a> is licensed under the ' .
|
'<a href="http://slic3r.org/">Slic3r</a> is licensed under the ' .
|
||||||
'<a href="http://www.gnu.org/licenses/agpl-3.0.html">GNU Affero General Public License, version 3</a>.' .
|
'<a href="http://www.gnu.org/licenses/agpl-3.0.html">GNU Affero General Public License, version 3</a>.' .
|
||||||
|
@ -20,7 +20,7 @@ our $last_config;
|
|||||||
sub new {
|
sub new {
|
||||||
my ($class, %params) = @_;
|
my ($class, %params) = @_;
|
||||||
|
|
||||||
my $self = $class->SUPER::new(undef, -1, 'Slic3r', wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE);
|
my $self = $class->SUPER::new(undef, -1, $Slic3r::FORK_NAME . ' - ' . $Slic3r::VERSION, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE);
|
||||||
$self->SetIcon(Wx::Icon->new($Slic3r::var->("Slic3r_128px.png"), wxBITMAP_TYPE_PNG) );
|
$self->SetIcon(Wx::Icon->new($Slic3r::var->("Slic3r_128px.png"), wxBITMAP_TYPE_PNG) );
|
||||||
|
|
||||||
# store input params
|
# store input params
|
||||||
@ -37,7 +37,7 @@ sub new {
|
|||||||
|
|
||||||
# initialize status bar
|
# initialize status bar
|
||||||
$self->{statusbar} = Slic3r::GUI::ProgressStatusBar->new($self, -1);
|
$self->{statusbar} = Slic3r::GUI::ProgressStatusBar->new($self, -1);
|
||||||
$self->{statusbar}->SetStatusText("Version $Slic3r::VERSION - Remember to check for updates at http://slic3r.org/");
|
$self->{statusbar}->SetStatusText("Version $Slic3r::VERSION - Remember to check for updates at http://github.com/prusa3d/slic3r/releases");
|
||||||
$self->SetStatusBar($self->{statusbar});
|
$self->SetStatusBar($self->{statusbar});
|
||||||
|
|
||||||
$self->{loaded} = 1;
|
$self->{loaded} = 1;
|
||||||
@ -294,13 +294,19 @@ sub _init_menubar {
|
|||||||
$self->config_wizard;
|
$self->config_wizard;
|
||||||
});
|
});
|
||||||
$helpMenu->AppendSeparator();
|
$helpMenu->AppendSeparator();
|
||||||
|
$self->_append_menu_item($helpMenu, "Prusa 3D Drivers", 'Open the Prusa3D drivers download page in your browser', sub {
|
||||||
|
Wx::LaunchDefaultBrowser('http://www.prusa3d.com/drivers/');
|
||||||
|
});
|
||||||
|
$self->_append_menu_item($helpMenu, "Prusa Edition Releases", 'Open the Prusa Edition releases page in your browser', sub {
|
||||||
|
Wx::LaunchDefaultBrowser('http://github.com/prusa3d/slic3r/releases');
|
||||||
|
});
|
||||||
|
# my $versioncheck = $self->_append_menu_item($helpMenu, "Check for &Updates...", 'Check for new Slic3r versions', sub {
|
||||||
|
# wxTheApp->check_version(1);
|
||||||
|
# });
|
||||||
|
# $versioncheck->Enable(wxTheApp->have_version_check);
|
||||||
$self->_append_menu_item($helpMenu, "Slic3r &Website", 'Open the Slic3r website in your browser', sub {
|
$self->_append_menu_item($helpMenu, "Slic3r &Website", 'Open the Slic3r website in your browser', sub {
|
||||||
Wx::LaunchDefaultBrowser('http://slic3r.org/');
|
Wx::LaunchDefaultBrowser('http://slic3r.org/');
|
||||||
});
|
});
|
||||||
my $versioncheck = $self->_append_menu_item($helpMenu, "Check for &Updates...", 'Check for new Slic3r versions', sub {
|
|
||||||
wxTheApp->check_version(1);
|
|
||||||
});
|
|
||||||
$versioncheck->Enable(wxTheApp->have_version_check);
|
|
||||||
$self->_append_menu_item($helpMenu, "Slic3r &Manual", 'Open the Slic3r manual in your browser', sub {
|
$self->_append_menu_item($helpMenu, "Slic3r &Manual", 'Open the Slic3r manual in your browser', sub {
|
||||||
Wx::LaunchDefaultBrowser('http://manual.slic3r.org/');
|
Wx::LaunchDefaultBrowser('http://manual.slic3r.org/');
|
||||||
});
|
});
|
||||||
|
@ -1002,7 +1002,7 @@ sub build {
|
|||||||
gcode_flavor use_relative_e_distances
|
gcode_flavor use_relative_e_distances
|
||||||
serial_port serial_speed
|
serial_port serial_speed
|
||||||
octoprint_host octoprint_apikey
|
octoprint_host octoprint_apikey
|
||||||
use_firmware_retraction pressure_advance vibration_limit
|
use_firmware_retraction pressure_advance
|
||||||
use_volumetric_e
|
use_volumetric_e
|
||||||
start_gcode end_gcode before_layer_gcode layer_gcode toolchange_gcode
|
start_gcode end_gcode before_layer_gcode layer_gcode toolchange_gcode
|
||||||
nozzle_diameter extruder_offset
|
nozzle_diameter extruder_offset
|
||||||
@ -1208,7 +1208,6 @@ sub build {
|
|||||||
$optgroup->append_single_option_line('use_firmware_retraction');
|
$optgroup->append_single_option_line('use_firmware_retraction');
|
||||||
$optgroup->append_single_option_line('use_volumetric_e');
|
$optgroup->append_single_option_line('use_volumetric_e');
|
||||||
$optgroup->append_single_option_line('pressure_advance');
|
$optgroup->append_single_option_line('pressure_advance');
|
||||||
$optgroup->append_single_option_line('vibration_limit');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
@ -7,7 +7,6 @@ has 'fh' => (is => 'ro', required => 1);
|
|||||||
has '_gcodegen' => (is => 'rw');
|
has '_gcodegen' => (is => 'rw');
|
||||||
has '_cooling_buffer' => (is => 'rw');
|
has '_cooling_buffer' => (is => 'rw');
|
||||||
has '_spiral_vase' => (is => 'rw');
|
has '_spiral_vase' => (is => 'rw');
|
||||||
has '_vibration_limit' => (is => 'rw');
|
|
||||||
has '_arc_fitting' => (is => 'rw');
|
has '_arc_fitting' => (is => 'rw');
|
||||||
has '_pressure_regulator' => (is => 'rw');
|
has '_pressure_regulator' => (is => 'rw');
|
||||||
has '_pressure_equalizer' => (is => 'rw');
|
has '_pressure_equalizer' => (is => 'rw');
|
||||||
@ -109,9 +108,6 @@ sub BUILD {
|
|||||||
$self->_spiral_vase(Slic3r::GCode::SpiralVase->new(config => $self->config))
|
$self->_spiral_vase(Slic3r::GCode::SpiralVase->new(config => $self->config))
|
||||||
if $self->config->spiral_vase;
|
if $self->config->spiral_vase;
|
||||||
|
|
||||||
$self->_vibration_limit(Slic3r::GCode::VibrationLimit->new(config => $self->config))
|
|
||||||
if $self->config->vibration_limit != 0;
|
|
||||||
|
|
||||||
$self->_arc_fitting(Slic3r::GCode::ArcFitting->new(config => $self->config))
|
$self->_arc_fitting(Slic3r::GCode::ArcFitting->new(config => $self->config))
|
||||||
if $self->config->gcode_arcs;
|
if $self->config->gcode_arcs;
|
||||||
|
|
||||||
@ -664,11 +660,6 @@ sub filter {
|
|||||||
my ($self, $gcode, $flush) = @_;
|
my ($self, $gcode, $flush) = @_;
|
||||||
$flush //= 0;
|
$flush //= 0;
|
||||||
|
|
||||||
# apply vibration limit if enabled;
|
|
||||||
# this injects pauses according to time (thus depends on actual speeds)
|
|
||||||
$gcode = $self->_vibration_limit->process($gcode)
|
|
||||||
if defined $self->_vibration_limit;
|
|
||||||
|
|
||||||
# apply pressure regulation if enabled;
|
# apply pressure regulation if enabled;
|
||||||
# this depends on actual speeds
|
# this depends on actual speeds
|
||||||
$gcode = $self->_pressure_regulator->process($gcode, $flush)
|
$gcode = $self->_pressure_regulator->process($gcode, $flush)
|
||||||
|
@ -685,7 +685,7 @@ sub _support_material {
|
|||||||
flow => $self->support_material_flow,
|
flow => $self->support_material_flow,
|
||||||
interface_flow => $self->support_material_flow(FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE),
|
interface_flow => $self->support_material_flow(FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE),
|
||||||
soluble_interface => ($self->config->support_material_contact_distance == 0),
|
soluble_interface => ($self->config->support_material_contact_distance == 0),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,8 +306,6 @@ $j
|
|||||||
--gcode-arcs Use G2/G3 commands for native arcs (experimental, not supported
|
--gcode-arcs Use G2/G3 commands for native arcs (experimental, not supported
|
||||||
by all firmwares)
|
by all firmwares)
|
||||||
--gcode-comments Make G-code verbose by adding comments (default: no)
|
--gcode-comments Make G-code verbose by adding comments (default: no)
|
||||||
--vibration-limit Limit the frequency of moves on X and Y axes (Hz, set zero to disable;
|
|
||||||
default: $config->{vibration_limit})
|
|
||||||
--pressure-advance Adjust pressure using the experimental advance algorithm (K constant,
|
--pressure-advance Adjust pressure using the experimental advance algorithm (K constant,
|
||||||
set zero to disable; default: $config->{pressure_advance})
|
set zero to disable; default: $config->{pressure_advance})
|
||||||
|
|
||||||
|
@ -109,7 +109,6 @@ $config->set('disable_fan_first_layers', 0);
|
|||||||
$config->set('bridge_speed', 99);
|
$config->set('bridge_speed', 99);
|
||||||
$config->set('top_solid_layers', 1); # internal bridges use solid_infil speed
|
$config->set('top_solid_layers', 1); # internal bridges use solid_infil speed
|
||||||
$config->set('bottom_solid_layers', 1); # internal bridges use solid_infil speed
|
$config->set('bottom_solid_layers', 1); # internal bridges use solid_infil speed
|
||||||
$config->set('vibration_limit', 30); # test that fan is turned on even when vibration limit (or other G-code post-processor) is enabled
|
|
||||||
|
|
||||||
my $print = Slic3r::Test::init_print('overhang', config => $config);
|
my $print = Slic3r::Test::init_print('overhang', config => $config);
|
||||||
my $fan = 0;
|
my $fan = 0;
|
||||||
|
@ -1,98 +0,0 @@
|
|||||||
use Test::More tests => 9;
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
|
|
||||||
BEGIN {
|
|
||||||
use FindBin;
|
|
||||||
use lib "$FindBin::Bin/../lib";
|
|
||||||
}
|
|
||||||
|
|
||||||
use Slic3r;
|
|
||||||
use Slic3r::Geometry qw(epsilon);
|
|
||||||
use Slic3r::Test;
|
|
||||||
|
|
||||||
my $config = Slic3r::Config->new_from_defaults;
|
|
||||||
|
|
||||||
# tolerance, in minutes
|
|
||||||
# (our time estimation differs from the internal one because of decimals truncation)
|
|
||||||
my $epsilon = 0.002;
|
|
||||||
|
|
||||||
my $test = sub {
|
|
||||||
my ($conf) = @_;
|
|
||||||
$conf ||= $config;
|
|
||||||
|
|
||||||
my $print = Slic3r::Test::init_print('2x20x10', config => $conf);
|
|
||||||
|
|
||||||
my $min_time = 1 / ($conf->vibration_limit * 60); # minimum time between direction changes in minutes
|
|
||||||
my %dir = (X => 0, Y => 0);
|
|
||||||
my %dir_time = (X => 0, Y => 0);
|
|
||||||
my %dir_sleep_time = (X => 0, Y => 0);
|
|
||||||
my $last_cmd_pause = 0;
|
|
||||||
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
|
|
||||||
my ($self, $cmd, $args, $info) = @_;
|
|
||||||
|
|
||||||
if ($cmd !~ /^G[01]$/) {
|
|
||||||
if ($cmd eq 'G4') {
|
|
||||||
$last_cmd_pause = (($args->{P} // 0) / 1000 + ($args->{S} // 0)) / 60; # in minutes
|
|
||||||
$dir_sleep_time{$_} += $last_cmd_pause for qw(X Y);
|
|
||||||
$last_cmd_pause -= $epsilon; # error builds up
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Z moves are slow enough that we can consider any vibration interrupted
|
|
||||||
if ($info->{dist_Z}) {
|
|
||||||
$dir_time{$_} += 99999 for qw(X Y);
|
|
||||||
$last_cmd_pause = 0;
|
|
||||||
return;
|
|
||||||
} elsif ($info->{dist_E} != 0 && $info->{dist_XY} == 0) {
|
|
||||||
my $time = abs($info->{dist_E}) / ($args->{F} // $self->F); # in minutes
|
|
||||||
$dir_time{$_} += $time for qw(X Y);
|
|
||||||
$last_cmd_pause = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
# compute move time (this assumes that the speed is XY-bound, which happens very likely)
|
|
||||||
my $time = abs($info->{dist_XY}) / ($args->{F} // $self->F); # in minutes
|
|
||||||
|
|
||||||
my $one_axis_would_trigger_limit_without_pause = 0;
|
|
||||||
foreach my $axis (qw(X Y)) {
|
|
||||||
# get the direction by comparing the new $axis coordinate with the current one
|
|
||||||
# 1 = positive, 0 = no change, -1 = negative
|
|
||||||
my $dir = $info->{"new_$axis"} <=> $self->$axis;
|
|
||||||
|
|
||||||
# are we changing direction on this axis?
|
|
||||||
if ($dir != 0 && $dir{$axis} != $dir) {
|
|
||||||
# this move changes direction on this axis
|
|
||||||
if ($dir{$axis} != 0) {
|
|
||||||
if (($dir_time{$axis} + $dir_sleep_time{$axis}) < ($min_time - $epsilon)) {
|
|
||||||
fail 'vibration limit exceeded';
|
|
||||||
}
|
|
||||||
$one_axis_would_trigger_limit_without_pause = 1
|
|
||||||
if ($dir_time{$axis} - $last_cmd_pause) < $min_time;
|
|
||||||
}
|
|
||||||
$dir{$axis} = $dir;
|
|
||||||
$dir_time{$axis} = 0;
|
|
||||||
$dir_sleep_time{$axis} = 0;
|
|
||||||
}
|
|
||||||
$dir_time{$axis} += $time;
|
|
||||||
}
|
|
||||||
fail 'no unnecessary pauses are added'
|
|
||||||
if $last_cmd_pause > $epsilon && !$one_axis_would_trigger_limit_without_pause;
|
|
||||||
|
|
||||||
$last_cmd_pause = 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
1;
|
|
||||||
};
|
|
||||||
|
|
||||||
$config->set('gcode_comments', 1);
|
|
||||||
$config->set('perimeters', 1);
|
|
||||||
foreach my $frequency (5, 10, 15) {
|
|
||||||
foreach my $gapfillspeed (20, 50, 100) {
|
|
||||||
$config->set('vibration_limit', $frequency);
|
|
||||||
ok $test->(), "vibrations limited to ${frequency}Hz (gap fill speed = ${gapfillspeed} mm/s)";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__END__
|
|
@ -24,6 +24,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
|
|||||||
// case ipRectilinear: return new FillRectilinear();
|
// case ipRectilinear: return new FillRectilinear();
|
||||||
case ipLine: return new FillLine();
|
case ipLine: return new FillLine();
|
||||||
case ipGrid: return new FillGrid2();
|
case ipGrid: return new FillGrid2();
|
||||||
|
case ipTriangles: return new FillTriangles();
|
||||||
// case ipGrid: return new FillGrid();
|
// case ipGrid: return new FillGrid();
|
||||||
case ipArchimedeanChords: return new FillArchimedeanChords();
|
case ipArchimedeanChords: return new FillArchimedeanChords();
|
||||||
case ipHilbertCurve: return new FillHilbertCurve();
|
case ipHilbertCurve: return new FillHilbertCurve();
|
||||||
|
@ -1449,10 +1449,20 @@ Polylines FillGrid2::fill_surface(const Surface *surface, const FillParams ¶
|
|||||||
Polylines polylines_out;
|
Polylines polylines_out;
|
||||||
if (! fill_surface_by_lines(surface, params, 0.f, polylines_out) ||
|
if (! fill_surface_by_lines(surface, params, 0.f, polylines_out) ||
|
||||||
! fill_surface_by_lines(surface, params, float(M_PI / 2.), polylines_out)) {
|
! fill_surface_by_lines(surface, params, float(M_PI / 2.), polylines_out)) {
|
||||||
printf("FillRectilinear2::fill_surface() failed to fill a region.\n");
|
printf("FillGrid2::fill_surface() failed to fill a region.\n");
|
||||||
|
}
|
||||||
|
return polylines_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Polylines FillTriangles::fill_surface(const Surface *surface, const FillParams ¶ms)
|
||||||
|
{
|
||||||
|
Polylines polylines_out;
|
||||||
|
if (! fill_surface_by_lines(surface, params, 0.f, polylines_out) ||
|
||||||
|
! fill_surface_by_lines(surface, params, float(M_PI / 3.), polylines_out) ||
|
||||||
|
! fill_surface_by_lines(surface, params, float(2. * M_PI / 3.), polylines_out)) {
|
||||||
|
printf("FillTriangles::fill_surface() failed to fill a region.\n");
|
||||||
|
}
|
||||||
return polylines_out;
|
return polylines_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
@ -35,6 +35,17 @@ protected:
|
|||||||
virtual float _layer_angle(size_t idx) const { return 0.f; }
|
virtual float _layer_angle(size_t idx) const { return 0.f; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FillTriangles : public FillRectilinear2
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~FillTriangles() {}
|
||||||
|
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill::Base.
|
||||||
|
virtual float _layer_angle(size_t idx) const { return 0.f; }
|
||||||
|
};
|
||||||
|
|
||||||
}; // namespace Slic3r
|
}; // namespace Slic3r
|
||||||
|
|
||||||
#endif // slic3r_FillRectilinear2_hpp_
|
#endif // slic3r_FillRectilinear2_hpp_
|
||||||
|
@ -343,9 +343,92 @@ linint(double value, double oldmin, double oldmax, double newmin, double newmax)
|
|||||||
return (value - oldmin) * (newmax - newmin) / (oldmax - oldmin) + newmin;
|
return (value - oldmin) * (newmax - newmin) / (oldmax - oldmin) + newmin;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pointfs
|
#if 0
|
||||||
arrange(size_t total_parts, Pointf part, coordf_t dist, const BoundingBoxf* bb)
|
// Point with a weight, by which the points are sorted.
|
||||||
|
// If the points have the same weight, sort them lexicographically by their positions.
|
||||||
|
struct ArrangeItem {
|
||||||
|
ArrangeItem() {}
|
||||||
|
Pointf pos;
|
||||||
|
coordf_t weight;
|
||||||
|
bool operator<(const ArrangeItem &other) const {
|
||||||
|
return weight < other.weight ||
|
||||||
|
((weight == other.weight) && (pos.y < other.pos.y || (pos.y == other.pos.y && pos.x < other.pos.x)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Pointfs arrange(size_t num_parts, const Pointf &part_size, coordf_t gap, const BoundingBoxf* bed_bounding_box)
|
||||||
{
|
{
|
||||||
|
// Use actual part size (the largest) plus separation distance (half on each side) in spacing algorithm.
|
||||||
|
const Pointf cell_size(part_size.x + gap, part_size.y + gap);
|
||||||
|
|
||||||
|
const BoundingBoxf bed_bbox = (bed_bounding_box != NULL && bed_bounding_box->defined) ?
|
||||||
|
*bed_bounding_box :
|
||||||
|
// Bogus bed size, large enough not to trigger the unsufficient bed size error.
|
||||||
|
BoundingBoxf(
|
||||||
|
Pointf(0, 0),
|
||||||
|
Pointf(cell_size.x * num_parts, cell_size.y * num_parts));
|
||||||
|
|
||||||
|
// This is how many cells we have available into which to put parts.
|
||||||
|
size_t cellw = size_t(floor((bed_bbox.size().x + gap) / cell_size.x));
|
||||||
|
size_t cellh = size_t(floor((bed_bbox.size().y + gap) / cell_size.y));
|
||||||
|
if (num_parts > cellw * cellh)
|
||||||
|
CONFESS("%zu parts won't fit in your print area!\n", num_parts);
|
||||||
|
|
||||||
|
// Get a bounding box of cellw x cellh cells, centered at the center of the bed.
|
||||||
|
Pointf cells_size(cellw * cell_size.x - gap, cellh * cell_size.y - gap);
|
||||||
|
Pointf cells_offset(bed_bbox.center() - 0.5 * cells_size);
|
||||||
|
BoundingBoxf cells_bb(cells_offset, cells_size + cells_offset);
|
||||||
|
|
||||||
|
// List of cells, sorted by distance from center.
|
||||||
|
std::vector<ArrangeItem> cellsorder(cellw * cellh, ArrangeItem());
|
||||||
|
for (size_t j = 0; j < cellh; ++ j) {
|
||||||
|
// Center of the jth row on the bed.
|
||||||
|
coordf_t cy = linint(j + 0.5, 0., double(cellh), cells_bb.min.y, cells_bb.max.y);
|
||||||
|
// Offset from the bed center.
|
||||||
|
coordf_t yd = cells_bb.center().y - cy;
|
||||||
|
for (size_t i = 0; i < cellw; ++ i) {
|
||||||
|
// Center of the ith column on the bed.
|
||||||
|
coordf_t cx = linint(i + 0.5, 0., double(cellw), cells_bb.min.x, cells_bb.max.x);
|
||||||
|
// Offset from the bed center.
|
||||||
|
coordf_t xd = cells_bb.center().x - cx;
|
||||||
|
// Cell with a distance from the bed center.
|
||||||
|
ArrangeItem &ci = cellsorder[j * cellw + i];
|
||||||
|
// Cell center
|
||||||
|
ci.pos.x = cx;
|
||||||
|
ci.pos.y = cy;
|
||||||
|
// Square distance of the cell center to the bed center.
|
||||||
|
ci.weight = xd * xd + yd * yd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Sort the cells lexicographically by their distances to the bed center and left to right / bttom to top.
|
||||||
|
std::sort(cellsorder.begin(), cellsorder.end());
|
||||||
|
cellsorder.erase(cellsorder.begin() + num_parts, cellsorder.end());
|
||||||
|
|
||||||
|
// Return the (left,top) corners of the cells.
|
||||||
|
Pointfs positions;
|
||||||
|
positions.reserve(num_parts);
|
||||||
|
for (std::vector<ArrangeItem>::const_iterator it = cellsorder.begin(); it != cellsorder.end(); ++ it)
|
||||||
|
positions.push_back(Pointf(it->pos.x - 0.5 * part_size.x, it->pos.y - 0.5 * part_size.y));
|
||||||
|
return positions;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
class ArrangeItem {
|
||||||
|
public:
|
||||||
|
Pointf pos;
|
||||||
|
size_t index_x, index_y;
|
||||||
|
coordf_t dist;
|
||||||
|
};
|
||||||
|
class ArrangeItemIndex {
|
||||||
|
public:
|
||||||
|
coordf_t index;
|
||||||
|
ArrangeItem item;
|
||||||
|
ArrangeItemIndex(coordf_t _index, ArrangeItem _item) : index(_index), item(_item) {};
|
||||||
|
};
|
||||||
|
Pointfs
|
||||||
|
arrange(size_t total_parts, const Pointf &part_size, coordf_t dist, const BoundingBoxf* bb)
|
||||||
|
{
|
||||||
|
Pointf part = part_size;
|
||||||
|
|
||||||
// use actual part size (the largest) plus separation distance (half on each side) in spacing algorithm
|
// use actual part size (the largest) plus separation distance (half on each side) in spacing algorithm
|
||||||
part.x += dist;
|
part.x += dist;
|
||||||
part.y += dist;
|
part.y += dist;
|
||||||
@ -463,6 +546,7 @@ arrange(size_t total_parts, Pointf part, coordf_t dist, const BoundingBoxf* bb)
|
|||||||
|
|
||||||
return positions;
|
return positions;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SLIC3R_DEBUG
|
#ifdef SLIC3R_DEBUG
|
||||||
// The following code for the visualization of the boost Voronoi diagram is based on:
|
// The following code for the visualization of the boost Voronoi diagram is based on:
|
||||||
|
@ -25,20 +25,8 @@ double rad2deg_dir(double angle);
|
|||||||
double deg2rad(double angle);
|
double deg2rad(double angle);
|
||||||
void simplify_polygons(const Polygons &polygons, double tolerance, Polygons* retval);
|
void simplify_polygons(const Polygons &polygons, double tolerance, Polygons* retval);
|
||||||
|
|
||||||
class ArrangeItem {
|
|
||||||
public:
|
|
||||||
Pointf pos;
|
|
||||||
size_t index_x, index_y;
|
|
||||||
coordf_t dist;
|
|
||||||
};
|
|
||||||
class ArrangeItemIndex {
|
|
||||||
public:
|
|
||||||
coordf_t index;
|
|
||||||
ArrangeItem item;
|
|
||||||
ArrangeItemIndex(coordf_t _index, ArrangeItem _item) : index(_index), item(_item) {};
|
|
||||||
};
|
|
||||||
double linint(double value, double oldmin, double oldmax, double newmin, double newmax);
|
double linint(double value, double oldmin, double oldmax, double newmin, double newmax);
|
||||||
Pointfs arrange(size_t total_parts, Pointf part, coordf_t dist, const BoundingBoxf* bb);
|
Pointfs arrange(size_t num_parts, const Pointf &part_size, coordf_t gap, const BoundingBoxf* bed_bounding_box);
|
||||||
|
|
||||||
class MedialAxis {
|
class MedialAxis {
|
||||||
public:
|
public:
|
||||||
|
@ -312,24 +312,6 @@ Point::vector_to(const Point &point) const
|
|||||||
return Vector(point.x - this->x, point.y - this->y);
|
return Vector(point.x - this->x, point.y - this->y);
|
||||||
}
|
}
|
||||||
|
|
||||||
Point
|
|
||||||
operator+(const Point& point1, const Point& point2)
|
|
||||||
{
|
|
||||||
return Point(point1.x + point2.x, point1.y + point2.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
Point
|
|
||||||
operator-(const Point& point1, const Point& point2)
|
|
||||||
{
|
|
||||||
return Point(point1.x - point2.x, point1.y - point2.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
Point
|
|
||||||
operator*(double scalar, const Point& point2)
|
|
||||||
{
|
|
||||||
return Point(scalar * point2.x, scalar * point2.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream&
|
std::ostream&
|
||||||
operator<<(std::ostream &stm, const Pointf &pointf)
|
operator<<(std::ostream &stm, const Pointf &pointf)
|
||||||
{
|
{
|
||||||
|
@ -66,9 +66,9 @@ class Point
|
|||||||
Vector vector_to(const Point &point) const;
|
Vector vector_to(const Point &point) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
Point operator+(const Point& point1, const Point& point2);
|
inline Point operator+(const Point& point1, const Point& point2) { return Point(point1.x + point2.x, point1.y + point2.y); }
|
||||||
Point operator-(const Point& point1, const Point& point2);
|
inline Point operator-(const Point& point1, const Point& point2) { return Point(point1.x - point2.x, point1.y - point2.y); }
|
||||||
Point operator*(double scalar, const Point& point2);
|
inline Point operator*(double scalar, const Point& point2) { return Point(scalar * point2.x, scalar * point2.y); }
|
||||||
|
|
||||||
class Point3 : public Point
|
class Point3 : public Point
|
||||||
{
|
{
|
||||||
@ -102,6 +102,10 @@ class Pointf
|
|||||||
Vectorf vector_to(const Pointf &point) const;
|
Vectorf vector_to(const Pointf &point) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline Pointf operator+(const Pointf& point1, const Pointf& point2) { return Pointf(point1.x + point2.x, point1.y + point2.y); }
|
||||||
|
inline Pointf operator-(const Pointf& point1, const Pointf& point2) { return Pointf(point1.x - point2.x, point1.y - point2.y); }
|
||||||
|
inline Pointf operator*(double scalar, const Pointf& point2) { return Pointf(scalar * point2.x, scalar * point2.y); }
|
||||||
|
|
||||||
class Pointf3 : public Pointf
|
class Pointf3 : public Pointf
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -233,7 +233,6 @@ Print::invalidate_state_by_config_options(const std::vector<t_config_option_key>
|
|||||||
|| *opt_key == "travel_speed"
|
|| *opt_key == "travel_speed"
|
||||||
|| *opt_key == "use_firmware_retraction"
|
|| *opt_key == "use_firmware_retraction"
|
||||||
|| *opt_key == "use_relative_e_distances"
|
|| *opt_key == "use_relative_e_distances"
|
||||||
|| *opt_key == "vibration_limit"
|
|
||||||
|| *opt_key == "wipe"
|
|| *opt_key == "wipe"
|
||||||
|| *opt_key == "z_offset"
|
|| *opt_key == "z_offset"
|
||||||
|| *opt_key == "max_volumetric_extrusion_rate_slope_negative"
|
|| *opt_key == "max_volumetric_extrusion_rate_slope_negative"
|
||||||
|
@ -371,6 +371,7 @@ PrintConfigDef::PrintConfigDef()
|
|||||||
def->enum_keys_map = ConfigOptionEnum<InfillPattern>::get_enum_values();
|
def->enum_keys_map = ConfigOptionEnum<InfillPattern>::get_enum_values();
|
||||||
def->enum_values.push_back("rectilinear");
|
def->enum_values.push_back("rectilinear");
|
||||||
def->enum_values.push_back("grid");
|
def->enum_values.push_back("grid");
|
||||||
|
def->enum_values.push_back("triangles");
|
||||||
def->enum_values.push_back("line");
|
def->enum_values.push_back("line");
|
||||||
def->enum_values.push_back("concentric");
|
def->enum_values.push_back("concentric");
|
||||||
def->enum_values.push_back("honeycomb");
|
def->enum_values.push_back("honeycomb");
|
||||||
@ -380,6 +381,7 @@ PrintConfigDef::PrintConfigDef()
|
|||||||
def->enum_values.push_back("octagramspiral");
|
def->enum_values.push_back("octagramspiral");
|
||||||
def->enum_labels.push_back("Rectilinear");
|
def->enum_labels.push_back("Rectilinear");
|
||||||
def->enum_labels.push_back("Grid");
|
def->enum_labels.push_back("Grid");
|
||||||
|
def->enum_labels.push_back("Triangles");
|
||||||
def->enum_labels.push_back("Line");
|
def->enum_labels.push_back("Line");
|
||||||
def->enum_labels.push_back("Concentric");
|
def->enum_labels.push_back("Concentric");
|
||||||
def->enum_labels.push_back("Honeycomb");
|
def->enum_labels.push_back("Honeycomb");
|
||||||
@ -1325,14 +1327,6 @@ PrintConfigDef::PrintConfigDef()
|
|||||||
def->cli = "use-volumetric-e!";
|
def->cli = "use-volumetric-e!";
|
||||||
def->default_value = new ConfigOptionBool(false);
|
def->default_value = new ConfigOptionBool(false);
|
||||||
|
|
||||||
def = this->add("vibration_limit", coFloat);
|
|
||||||
def->label = "Vibration limit (deprecated)";
|
|
||||||
def->tooltip = "This experimental option will slow down those moves hitting the configured frequency limit. The purpose of limiting vibrations is to avoid mechanical resonance. Set zero to disable.";
|
|
||||||
def->sidetext = "Hz";
|
|
||||||
def->cli = "vibration-limit=f";
|
|
||||||
def->min = 0;
|
|
||||||
def->default_value = new ConfigOptionFloat(0);
|
|
||||||
|
|
||||||
def = this->add("wipe", coBools);
|
def = this->add("wipe", coBools);
|
||||||
def->label = "Wipe while retracting";
|
def->label = "Wipe while retracting";
|
||||||
def->tooltip = "This flag will move the nozzle while retracting to minimize the possible blob on leaky extruders.";
|
def->tooltip = "This flag will move the nozzle while retracting to minimize the possible blob on leaky extruders.";
|
||||||
|
@ -30,7 +30,7 @@ enum GCodeFlavor {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum InfillPattern {
|
enum InfillPattern {
|
||||||
ipRectilinear, ipGrid, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
|
ipRectilinear, ipGrid, ipTriangles, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
|
||||||
ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral,
|
ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -58,6 +58,7 @@ template<> inline t_config_enum_values ConfigOptionEnum<InfillPattern>::get_enum
|
|||||||
t_config_enum_values keys_map;
|
t_config_enum_values keys_map;
|
||||||
keys_map["rectilinear"] = ipRectilinear;
|
keys_map["rectilinear"] = ipRectilinear;
|
||||||
keys_map["grid"] = ipGrid;
|
keys_map["grid"] = ipGrid;
|
||||||
|
keys_map["triangles"] = ipTriangles;
|
||||||
keys_map["line"] = ipLine;
|
keys_map["line"] = ipLine;
|
||||||
keys_map["concentric"] = ipConcentric;
|
keys_map["concentric"] = ipConcentric;
|
||||||
keys_map["honeycomb"] = ipHoneycomb;
|
keys_map["honeycomb"] = ipHoneycomb;
|
||||||
@ -413,7 +414,6 @@ class PrintConfig : public GCodeConfig
|
|||||||
ConfigOptionInt standby_temperature_delta;
|
ConfigOptionInt standby_temperature_delta;
|
||||||
ConfigOptionInts temperature;
|
ConfigOptionInts temperature;
|
||||||
ConfigOptionInt threads;
|
ConfigOptionInt threads;
|
||||||
ConfigOptionFloat vibration_limit;
|
|
||||||
ConfigOptionBools wipe;
|
ConfigOptionBools wipe;
|
||||||
ConfigOptionFloat z_offset;
|
ConfigOptionFloat z_offset;
|
||||||
|
|
||||||
@ -470,7 +470,6 @@ class PrintConfig : public GCodeConfig
|
|||||||
OPT_PTR(standby_temperature_delta);
|
OPT_PTR(standby_temperature_delta);
|
||||||
OPT_PTR(temperature);
|
OPT_PTR(temperature);
|
||||||
OPT_PTR(threads);
|
OPT_PTR(threads);
|
||||||
OPT_PTR(vibration_limit);
|
|
||||||
OPT_PTR(wipe);
|
OPT_PTR(wipe);
|
||||||
OPT_PTR(z_offset);
|
OPT_PTR(z_offset);
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#define SLIC3R_FORK_NAME "Slic3r Prusa Edition"
|
||||||
#define SLIC3R_VERSION "1.3.0-dev"
|
#define SLIC3R_VERSION "1.3.0-dev"
|
||||||
|
|
||||||
//FIXME This epsilon value is used for many non-related purposes:
|
//FIXME This epsilon value is used for many non-related purposes:
|
||||||
|
@ -22,4 +22,10 @@ DEBUG_OUT_PATH_PREFIX()
|
|||||||
RETVAL = newSVpv(SLIC3R_DEBUG_OUT_PATH_PREFIX, 0);
|
RETVAL = newSVpv(SLIC3R_DEBUG_OUT_PATH_PREFIX, 0);
|
||||||
OUTPUT: RETVAL
|
OUTPUT: RETVAL
|
||||||
|
|
||||||
|
SV*
|
||||||
|
FORK_NAME()
|
||||||
|
CODE:
|
||||||
|
RETVAL = newSVpv(SLIC3R_FORK_NAME, 0);
|
||||||
|
OUTPUT: RETVAL
|
||||||
|
|
||||||
%}
|
%}
|
Loading…
Reference in New Issue
Block a user