Toolpaths preview
This commit is contained in:
parent
d8b1eff62f
commit
907de1011f
@ -12,6 +12,7 @@ use Slic3r::GUI::MainFrame;
|
|||||||
use Slic3r::GUI::Notifier;
|
use Slic3r::GUI::Notifier;
|
||||||
use Slic3r::GUI::Plater;
|
use Slic3r::GUI::Plater;
|
||||||
use Slic3r::GUI::Plater::2D;
|
use Slic3r::GUI::Plater::2D;
|
||||||
|
use Slic3r::GUI::Plater::2DToolpaths;
|
||||||
use Slic3r::GUI::Plater::ObjectPartsPanel;
|
use Slic3r::GUI::Plater::ObjectPartsPanel;
|
||||||
use Slic3r::GUI::Plater::ObjectCutDialog;
|
use Slic3r::GUI::Plater::ObjectCutDialog;
|
||||||
use Slic3r::GUI::Plater::ObjectPreviewDialog;
|
use Slic3r::GUI::Plater::ObjectPreviewDialog;
|
||||||
|
@ -190,6 +190,10 @@ sub _init_menubar {
|
|||||||
$self->_append_menu_item($self->{plater_menu}, "Export AMF...", 'Export current plate as AMF', sub {
|
$self->_append_menu_item($self->{plater_menu}, "Export AMF...", 'Export current plate as AMF', sub {
|
||||||
$plater->export_amf;
|
$plater->export_amf;
|
||||||
});
|
});
|
||||||
|
$self->{plater_menu}->AppendSeparator();
|
||||||
|
$self->_append_menu_item($self->{plater_menu}, "Toolpaths preview…", 'Open a viewer with toolpaths preview', sub {
|
||||||
|
$plater->toolpaths_preview;
|
||||||
|
});
|
||||||
|
|
||||||
$self->{object_menu} = $self->{plater}->object_menu;
|
$self->{object_menu} = $self->{plater}->object_menu;
|
||||||
$self->on_plater_selection_changed(0);
|
$self->on_plater_selection_changed(0);
|
||||||
|
@ -1286,6 +1286,19 @@ sub object_settings_dialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub toolpaths_preview {
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
# TODO: we should check whether steps are done in $print rather then checking the thread
|
||||||
|
if ($self->{process_thread}) {
|
||||||
|
Slic3r::GUI::show_error($self, "Unable to show preview while toolpaths are being generated.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $dlg = Slic3r::GUI::Plater::2DToolpaths::Dialog->new($self, $self->{print});
|
||||||
|
$dlg->ShowModal;
|
||||||
|
}
|
||||||
|
|
||||||
sub object_list_changed {
|
sub object_list_changed {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
|
412
lib/Slic3r/GUI/Plater/2DToolpaths.pm
Normal file
412
lib/Slic3r/GUI/Plater/2DToolpaths.pm
Normal file
@ -0,0 +1,412 @@
|
|||||||
|
package Slic3r::GUI::Plater::2DToolpaths;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use utf8;
|
||||||
|
|
||||||
|
use List::Util qw();
|
||||||
|
use Slic3r::Geometry qw();
|
||||||
|
use Wx qw(:misc :sizer :slider);
|
||||||
|
use Wx::Event qw(EVT_SLIDER);
|
||||||
|
use base 'Wx::Panel';
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my $class = shift;
|
||||||
|
my ($parent, $print) = @_;
|
||||||
|
|
||||||
|
my $self = $class->SUPER::new($parent, -1, wxDefaultPosition);
|
||||||
|
$self->{print} = $print;
|
||||||
|
my $sizer = Wx::BoxSizer->new(wxHORIZONTAL);
|
||||||
|
|
||||||
|
my $canvas = $self->{canvas} = Slic3r::GUI::Plater::2DToolpaths::Canvas->new($self, $print);
|
||||||
|
$sizer->Add($canvas, 1, wxALL | wxEXPAND, 10);
|
||||||
|
|
||||||
|
my $slider = $self->{slider} = Wx::Slider->new(
|
||||||
|
$self, -1,
|
||||||
|
0, # default
|
||||||
|
0, # min
|
||||||
|
$print->total_layer_count-1, # max
|
||||||
|
wxDefaultPosition,
|
||||||
|
wxDefaultSize,
|
||||||
|
wxVERTICAL | wxSL_INVERSE,
|
||||||
|
);
|
||||||
|
$sizer->Add($slider, 0, wxALL | wxEXPAND, 10);
|
||||||
|
|
||||||
|
EVT_SLIDER($self, $slider, sub {
|
||||||
|
$canvas->set_layer($slider->GetValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
$self->SetSizer($sizer);
|
||||||
|
$self->SetMinSize($self->GetSize);
|
||||||
|
$sizer->SetSizeHints($self);
|
||||||
|
|
||||||
|
$canvas->set_layer(0);
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
package Slic3r::GUI::Plater::2DToolpaths::Canvas;
|
||||||
|
|
||||||
|
use Wx::Event qw(EVT_PAINT EVT_SIZE EVT_ERASE_BACKGROUND EVT_IDLE EVT_MOUSEWHEEL EVT_MOUSE_EVENTS);
|
||||||
|
use OpenGL qw(:glconstants :glfunctions :glufunctions);
|
||||||
|
use base qw(Wx::GLCanvas Class::Accessor);
|
||||||
|
use Wx::GLCanvas qw(:all);
|
||||||
|
use List::Util qw(min);
|
||||||
|
use Slic3r::Geometry qw(scale unscale);
|
||||||
|
|
||||||
|
__PACKAGE__->mk_accessors(qw(print layer_id init dirty bb));
|
||||||
|
|
||||||
|
# make OpenGL::Array thread-safe
|
||||||
|
{
|
||||||
|
no warnings 'redefine';
|
||||||
|
*OpenGL::Array::CLONE_SKIP = sub { 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my ($class, $parent, $print) = @_;
|
||||||
|
|
||||||
|
my $self = $class->SUPER::new($parent);
|
||||||
|
$self->print($print);
|
||||||
|
$self->bb($self->print->bounding_box);
|
||||||
|
|
||||||
|
EVT_PAINT($self, sub {
|
||||||
|
my $dc = Wx::PaintDC->new($self);
|
||||||
|
$self->Render($dc);
|
||||||
|
});
|
||||||
|
EVT_SIZE($self, sub { $self->dirty(1) });
|
||||||
|
EVT_IDLE($self, sub {
|
||||||
|
return unless $self->dirty;
|
||||||
|
return if !$self->IsShownOnScreen;
|
||||||
|
$self->Resize( $self->GetSizeWH );
|
||||||
|
$self->Refresh;
|
||||||
|
});
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub set_layer {
|
||||||
|
my ($self, $layer_id) = @_;
|
||||||
|
|
||||||
|
$self->layer_id($layer_id);
|
||||||
|
$self->dirty(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Render {
|
||||||
|
my ($self, $dc) = @_;
|
||||||
|
|
||||||
|
# prevent calling SetCurrent() when window is not shown yet
|
||||||
|
return unless $self->IsShownOnScreen;
|
||||||
|
return unless my $context = $self->GetContext;
|
||||||
|
$self->SetCurrent($context);
|
||||||
|
$self->InitGL;
|
||||||
|
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glLoadIdentity();
|
||||||
|
my $bb = $self->bb;
|
||||||
|
my ($x1, $y1, $x2, $y2) = ($bb->x_min, $bb->y_min, $bb->x_max, $bb->y_max);
|
||||||
|
my ($x, $y) = $self->GetSizeWH;
|
||||||
|
if (($x2 - $x1)/($y2 - $y1) > $x/$y) {
|
||||||
|
# adjust Y
|
||||||
|
my $new_y = $y * ($x2 - $x1) / $x;
|
||||||
|
$y1 = ($y2 + $y1)/2 - $new_y/2;
|
||||||
|
$y2 = $y1 + $new_y;
|
||||||
|
} else {
|
||||||
|
my $new_x = $x * ($y2 - $y1) / $y;
|
||||||
|
$x1 = ($x2 + $x1)/2 - $new_x/2;
|
||||||
|
$x2 = $x1 + $new_x;
|
||||||
|
}
|
||||||
|
glOrtho($x1, $x2, $y1, $y2, 0, 1);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glLoadIdentity();
|
||||||
|
|
||||||
|
glClearColor(1, 1, 1, 0);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
foreach my $object (@{$self->print->objects}) {
|
||||||
|
my $layer = $object->get_layer($self->layer_id);
|
||||||
|
foreach my $layerm (@{$layer->regions}) {
|
||||||
|
glColor3f(0.7, 0, 0);
|
||||||
|
$self->_draw_extrusionpath($object, $_) for @{$layerm->perimeters};
|
||||||
|
|
||||||
|
glColor3f(0, 0, 0.7);
|
||||||
|
$self->_draw_extrusionpath($object, $_) for map @$_, @{$layerm->fills};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glFlush();
|
||||||
|
$self->SwapBuffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _draw_extrusionpath {
|
||||||
|
my ($self, $object, $path) = @_;
|
||||||
|
|
||||||
|
my $polyline = $path->isa('Slic3r::ExtrusionLoop')
|
||||||
|
? $path->polygon->split_at_first_point
|
||||||
|
: $path->polyline;
|
||||||
|
|
||||||
|
glLineWidth(1);
|
||||||
|
foreach my $copy (@{ $object->_shifted_copies }) {
|
||||||
|
foreach my $line (@{$polyline->lines}) {
|
||||||
|
$line->translate(@$copy);
|
||||||
|
glBegin(GL_LINES);
|
||||||
|
glVertex2f(@{$line->a});
|
||||||
|
glVertex2f(@{$line->b});
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub InitGL {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
return if $self->init;
|
||||||
|
return unless $self->GetContext;
|
||||||
|
$self->init(1);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub GetContext {
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
if (Wx::wxVERSION >= 2.009) {
|
||||||
|
return $self->{context} ||= Wx::GLContext->new($self);
|
||||||
|
} else {
|
||||||
|
return $self->SUPER::GetContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub SetCurrent {
|
||||||
|
my ($self, $context) = @_;
|
||||||
|
|
||||||
|
if (Wx::wxVERSION >= 2.009) {
|
||||||
|
return $self->SUPER::SetCurrent($context);
|
||||||
|
} else {
|
||||||
|
return $self->SUPER::SetCurrent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Resize {
|
||||||
|
my ($self, $x, $y) = @_;
|
||||||
|
|
||||||
|
return unless $self->GetContext;
|
||||||
|
$self->dirty(0);
|
||||||
|
|
||||||
|
$self->SetCurrent($self->GetContext);
|
||||||
|
|
||||||
|
my ($x1, $y1, $x2, $y2) = (0, 0, $x, $y);
|
||||||
|
if (0 && $x > $y) {
|
||||||
|
$x2 = $y;
|
||||||
|
$x1 = ($x - $y)/2;
|
||||||
|
}
|
||||||
|
if (0 && $y > $x) {
|
||||||
|
$y2 = $x;
|
||||||
|
$y1 = ($y - $x)/2;
|
||||||
|
}
|
||||||
|
glViewport($x1, $y1, $x2, $y2);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub line {
|
||||||
|
my (
|
||||||
|
$x1, $y1, $x2, $y2, # coordinates of the line
|
||||||
|
$w, # width/thickness of the line in pixel
|
||||||
|
$Cr, $Cg, $Cb, # RGB color components
|
||||||
|
$Br, $Bg, $Bb, # color of background when alphablend=false
|
||||||
|
# Br=alpha of color when alphablend=true
|
||||||
|
$alphablend, # use alpha blend or not
|
||||||
|
) = @_;
|
||||||
|
|
||||||
|
my $t;
|
||||||
|
my $R;
|
||||||
|
my $f = $w - int($w);
|
||||||
|
my $A;
|
||||||
|
|
||||||
|
if ($alphablend) {
|
||||||
|
$A = $Br;
|
||||||
|
} else {
|
||||||
|
$A = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
# determine parameters t,R
|
||||||
|
if ($w >= 0 && $w < 1) {
|
||||||
|
$t = 0.05; $R = 0.48 + 0.32 * $f;
|
||||||
|
if (!$alphablend) {
|
||||||
|
$Cr += 0.88 * (1-$f);
|
||||||
|
$Cg += 0.88 * (1-$f);
|
||||||
|
$Cb += 0.88 * (1-$f);
|
||||||
|
$Cr = 1.0 if ($Cr > 1.0);
|
||||||
|
$Cg = 1.0 if ($Cg > 1.0);
|
||||||
|
$Cb = 1.0 if ($Cb > 1.0);
|
||||||
|
} else {
|
||||||
|
$A *= $f;
|
||||||
|
}
|
||||||
|
} elsif ($w >= 1.0 && $w < 2.0) {
|
||||||
|
$t = 0.05 + $f*0.33; $R = 0.768 + 0.312*$f;
|
||||||
|
} elsif ($w >= 2.0 && $w < 3.0) {
|
||||||
|
$t = 0.38 + $f*0.58; $R = 1.08;
|
||||||
|
} elsif ($w >= 3.0 && $w < 4.0) {
|
||||||
|
$t = 0.96 + $f*0.48; $R = 1.08;
|
||||||
|
} elsif ($w >= 4.0 && $w < 5.0) {
|
||||||
|
$t= 1.44 + $f*0.46; $R = 1.08;
|
||||||
|
} elsif ($w >= 5.0 && $w < 6.0) {
|
||||||
|
$t= 1.9 + $f*0.6; $R = 1.08;
|
||||||
|
} elsif ($w >= 6.0) {
|
||||||
|
my $ff = $w - 6.0;
|
||||||
|
$t = 2.5 + $ff*0.50; $R = 1.08;
|
||||||
|
}
|
||||||
|
#printf( "w=%f, f=%f, C=%.4f\n", $w, $f, $C);
|
||||||
|
|
||||||
|
# determine angle of the line to horizontal
|
||||||
|
my $tx = 0; my $ty = 0; # core thinkness of a line
|
||||||
|
my $Rx = 0; my $Ry = 0; # fading edge of a line
|
||||||
|
my $cx = 0; my $cy = 0; # cap of a line
|
||||||
|
my $ALW = 0.01;
|
||||||
|
my $dx = $x2 - $x1;
|
||||||
|
my $dy = $y2 - $y1;
|
||||||
|
if (abs($dx) < $ALW) {
|
||||||
|
# vertical
|
||||||
|
$tx = $t; $ty = 0;
|
||||||
|
$Rx = $R; $Ry = 0;
|
||||||
|
if ($w > 0.0 && $w < 1.0) {
|
||||||
|
$tx *= 8;
|
||||||
|
} elsif ($w == 1.0) {
|
||||||
|
$tx *= 10;
|
||||||
|
}
|
||||||
|
} elsif (abs($dy) < $ALW) {
|
||||||
|
#horizontal
|
||||||
|
$tx = 0; $ty = $t;
|
||||||
|
$Rx = 0; $Ry = $R;
|
||||||
|
if ($w > 0.0 && $w < 1.0) {
|
||||||
|
$ty *= 8;
|
||||||
|
} elsif ($w == 1.0) {
|
||||||
|
$ty *= 10;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($w < 3) { # approximate to make things even faster
|
||||||
|
my $m = $dy/$dx;
|
||||||
|
# and calculate tx,ty,Rx,Ry
|
||||||
|
if ($m > -0.4142 && $m <= 0.4142) {
|
||||||
|
# -22.5 < $angle <= 22.5, approximate to 0 (degree)
|
||||||
|
$tx = $t * 0.1; $ty = $t;
|
||||||
|
$Rx = $R * 0.6; $Ry = $R;
|
||||||
|
} elsif ($m > 0.4142 && $m <= 2.4142) {
|
||||||
|
# 22.5 < $angle <= 67.5, approximate to 45 (degree)
|
||||||
|
$tx = $t * -0.7071; $ty = $t * 0.7071;
|
||||||
|
$Rx = $R * -0.7071; $Ry = $R * 0.7071;
|
||||||
|
} elsif ($m > 2.4142 || $m <= -2.4142) {
|
||||||
|
# 67.5 < $angle <= 112.5, approximate to 90 (degree)
|
||||||
|
$tx = $t; $ty = $t*0.1;
|
||||||
|
$Rx = $R; $Ry = $R*0.6;
|
||||||
|
} elsif ($m > -2.4142 && $m < -0.4142) {
|
||||||
|
# 112.5 < angle < 157.5, approximate to 135 (degree)
|
||||||
|
$tx = $t * 0.7071; $ty = $t * 0.7071;
|
||||||
|
$Rx = $R * 0.7071; $Ry = $R * 0.7071;
|
||||||
|
} else {
|
||||||
|
# error in determining angle
|
||||||
|
printf("error in determining angle: m=%.4f\n", $m);
|
||||||
|
}
|
||||||
|
} else { # calculate to exact
|
||||||
|
$dx= $y1 - $y2;
|
||||||
|
$dy= $x2 - $x1;
|
||||||
|
my $L = sqrt($dx*$dx + $dy*$dy);
|
||||||
|
$dx /= $L;
|
||||||
|
$dy /= $L;
|
||||||
|
$cx = -0.6*$dy; $cy=0.6*$dx;
|
||||||
|
$tx = $t*$dx; $ty = $t*$dy;
|
||||||
|
$Rx = $R*$dx; $Ry = $R*$dy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# draw the line by triangle strip
|
||||||
|
glBegin(GL_TRIANGLE_STRIP);
|
||||||
|
if (!$alphablend) {
|
||||||
|
glColor3f($Br, $Bg, $Bb);
|
||||||
|
} else {
|
||||||
|
glColor4f($Cr, $Cg, $Cb, 0);
|
||||||
|
}
|
||||||
|
glVertex2f($x1 - $tx - $Rx, $y1 - $ty - $Ry); # fading edge
|
||||||
|
glVertex2f($x2 - $tx - $Rx, $y2 - $ty - $Ry);
|
||||||
|
|
||||||
|
if (!$alphablend) {
|
||||||
|
glColor3f($Cr, $Cg, $Cb);
|
||||||
|
} else {
|
||||||
|
glColor4f($Cr, $Cg, $Cb, $A);
|
||||||
|
}
|
||||||
|
glVertex2f($x1 - $tx, $y1 - $ty); # core
|
||||||
|
glVertex2f($x2 - $tx, $y2 - $ty);
|
||||||
|
glVertex2f($x1 + $tx, $y1 + $ty);
|
||||||
|
glVertex2f($x2 + $tx, $y2 + $ty);
|
||||||
|
|
||||||
|
if ((abs($dx) < $ALW || abs($dy) < $ALW) && $w <= 1.0) {
|
||||||
|
# printf("skipped one fading edge\n");
|
||||||
|
} else {
|
||||||
|
if (!$alphablend) {
|
||||||
|
glColor3f($Br, $Bg, $Bb);
|
||||||
|
} else {
|
||||||
|
glColor4f($Cr, $Cg, $Cb, 0);
|
||||||
|
}
|
||||||
|
glVertex2f($x1 + $tx+ $Rx, $y1 + $ty + $Ry); # fading edge
|
||||||
|
glVertex2f($x2 + $tx+ $Rx, $y2 + $ty + $Ry);
|
||||||
|
}
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
# cap
|
||||||
|
if ($w < 3) {
|
||||||
|
# do not draw cap
|
||||||
|
} else {
|
||||||
|
# draw cap
|
||||||
|
glBegin(GL_TRIANGLE_STRIP);
|
||||||
|
if (!$alphablend) {
|
||||||
|
glColor3f($Br, $Bg, $Bb);
|
||||||
|
} else {
|
||||||
|
glColor4f($Cr, $Cg, $Cb, 0);
|
||||||
|
}
|
||||||
|
glVertex2f($x1 - $Rx + $cx, $y1 - $Ry + $cy);
|
||||||
|
glVertex2f($x1 + $Rx + $cx, $y1 + $Ry + $cy);
|
||||||
|
glColor3f($Cr, $Cg, $Cb);
|
||||||
|
glVertex2f($x1 - $tx - $Rx, $y1 - $ty - $Ry);
|
||||||
|
glVertex2f($x1 + $tx + $Rx, $y1 + $ty + $Ry);
|
||||||
|
glEnd();
|
||||||
|
glBegin(GL_TRIANGLE_STRIP);
|
||||||
|
if (!$alphablend) {
|
||||||
|
glColor3f($Br, $Bg, $Bb);
|
||||||
|
} else {
|
||||||
|
glColor4f($Cr, $Cg, $Cb, 0);
|
||||||
|
}
|
||||||
|
glVertex2f($x2 - $Rx - $cx, $y2 - $Ry - $cy);
|
||||||
|
glVertex2f($x2 + $Rx - $cx, $y2 + $Ry - $cy);
|
||||||
|
glColor3f($Cr, $Cg, $Cb);
|
||||||
|
glVertex2f($x2 - $tx - $Rx, $y2 - $ty - $Ry);
|
||||||
|
glVertex2f($x2 + $tx + $Rx, $y2 + $ty + $Ry);
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
package Slic3r::GUI::Plater::2DToolpaths::Dialog;
|
||||||
|
|
||||||
|
use Wx qw(:dialog :id :misc :sizer);
|
||||||
|
use Wx::Event qw(EVT_CLOSE);
|
||||||
|
use base 'Wx::Dialog';
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my $class = shift;
|
||||||
|
my ($parent, $print) = @_;
|
||||||
|
my $self = $class->SUPER::new($parent, -1, "Toolpaths", wxDefaultPosition, [500,500], wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);
|
||||||
|
|
||||||
|
my $sizer = Wx::BoxSizer->new(wxVERTICAL);
|
||||||
|
$sizer->Add(Slic3r::GUI::Plater::2DToolpaths->new($self, $print), 1, wxEXPAND, 0);
|
||||||
|
$self->SetSizer($sizer);
|
||||||
|
$self->SetMinSize($self->GetSize);
|
||||||
|
|
||||||
|
# needed to actually free memory
|
||||||
|
EVT_CLOSE($self, sub {
|
||||||
|
$self->EndModal(wxID_OK);
|
||||||
|
$self->Destroy;
|
||||||
|
});
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
@ -24,7 +24,10 @@ use constant SELECTED_COLOR => [0,1,0,1];
|
|||||||
use constant COLORS => [ [1,1,1], [1,0.5,0.5], [0.5,1,0.5], [0.5,0.5,1] ];
|
use constant COLORS => [ [1,1,1], [1,0.5,0.5], [0.5,1,0.5], [0.5,0.5,1] ];
|
||||||
|
|
||||||
# make OpenGL::Array thread-safe
|
# make OpenGL::Array thread-safe
|
||||||
*OpenGL::Array::CLONE_SKIP = sub { 1 };
|
{
|
||||||
|
no warnings 'redefine';
|
||||||
|
*OpenGL::Array::CLONE_SKIP = sub { 1 };
|
||||||
|
}
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
my ($class, $parent, $object) = @_;
|
my ($class, $parent, $object) = @_;
|
||||||
|
@ -390,6 +390,16 @@ sub raw_mesh {
|
|||||||
return $mesh;
|
return $mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub raw_bounding_box {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
my @meshes = map $_->mesh, grep !$_->modifier, @{ $self->volumes };
|
||||||
|
die "No meshes found" if !@meshes;
|
||||||
|
my $bb = (shift @meshes)->bounding_box;
|
||||||
|
$bb->merge($_->bounding_box) for @meshes;
|
||||||
|
return $bb;
|
||||||
|
}
|
||||||
|
|
||||||
# flattens all volumes and instances into a single mesh
|
# flattens all volumes and instances into a single mesh
|
||||||
sub mesh {
|
sub mesh {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
@ -167,9 +167,9 @@ sub add_model_object {
|
|||||||
# initialize print object and store it at the given position
|
# initialize print object and store it at the given position
|
||||||
my $o;
|
my $o;
|
||||||
if (defined $obj_idx) {
|
if (defined $obj_idx) {
|
||||||
$o = $self->set_new_object($obj_idx, $object, $object->bounding_box);
|
$o = $self->set_new_object($obj_idx, $object, $object->raw_bounding_box);
|
||||||
} else {
|
} else {
|
||||||
$o = $self->add_object($object, $object->bounding_box);
|
$o = $self->add_object($object, $object->raw_bounding_box);
|
||||||
}
|
}
|
||||||
|
|
||||||
$o->set_copies([ map Slic3r::Point->new_scale(@{ $_->offset }), @{ $object->instances } ]);
|
$o->set_copies([ map Slic3r::Point->new_scale(@{ $_->offset }), @{ $object->instances } ]);
|
||||||
|
@ -8,7 +8,7 @@ has '_print' => (
|
|||||||
default => sub { Slic3r::Print->new },
|
default => sub { Slic3r::Print->new },
|
||||||
handles => [qw(apply_config extruders expanded_output_filepath
|
handles => [qw(apply_config extruders expanded_output_filepath
|
||||||
total_used_filament total_extruded_volume
|
total_used_filament total_extruded_volume
|
||||||
placeholder_parser)],
|
placeholder_parser process)],
|
||||||
);
|
);
|
||||||
|
|
||||||
has 'duplicate' => (
|
has 'duplicate' => (
|
||||||
|
85
utils/view-toolpaths.pl
Executable file
85
utils/view-toolpaths.pl
Executable file
@ -0,0 +1,85 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
# This script displays 3D preview of a mesh
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
use FindBin;
|
||||||
|
use lib "$FindBin::Bin/../lib";
|
||||||
|
}
|
||||||
|
|
||||||
|
use Getopt::Long qw(:config no_auto_abbrev);
|
||||||
|
use Slic3r;
|
||||||
|
use Slic3r::GUI;
|
||||||
|
use Slic3r::GUI::PreviewCanvas;
|
||||||
|
$|++;
|
||||||
|
|
||||||
|
my %opt = ();
|
||||||
|
{
|
||||||
|
my %options = (
|
||||||
|
'help' => sub { usage() },
|
||||||
|
'load=s' => \$opt{load},
|
||||||
|
);
|
||||||
|
GetOptions(%options) or usage(1);
|
||||||
|
$ARGV[0] or usage(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
# load model
|
||||||
|
my $model = Slic3r::Model->read_from_file($ARGV[0]);
|
||||||
|
|
||||||
|
# load config
|
||||||
|
my $config = Slic3r::Config->new_from_defaults;
|
||||||
|
$config->set('skirts', 0);
|
||||||
|
if ($opt{load}) {
|
||||||
|
$config->apply(Slic3r::Config->load($opt{load}));
|
||||||
|
}
|
||||||
|
|
||||||
|
# init print
|
||||||
|
my $sprint = Slic3r::Print::Simple->new;
|
||||||
|
$sprint->apply_config($config);
|
||||||
|
$sprint->set_model($model);
|
||||||
|
$sprint->process;
|
||||||
|
|
||||||
|
# visualize toolpaths
|
||||||
|
$Slic3r::ViewToolpaths::print = $sprint->_print;
|
||||||
|
my $app = Slic3r::ViewToolpaths->new;
|
||||||
|
$app->MainLoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub usage {
|
||||||
|
my ($exit_code) = @_;
|
||||||
|
|
||||||
|
print <<"EOF";
|
||||||
|
Usage: view-toolpaths.pl [ OPTIONS ] file.stl
|
||||||
|
|
||||||
|
--help Output this usage screen and exit
|
||||||
|
--load CONFIG Loads the supplied config file
|
||||||
|
|
||||||
|
EOF
|
||||||
|
exit ($exit_code || 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
package Slic3r::ViewToolpaths;
|
||||||
|
use Wx qw(:sizer);
|
||||||
|
use base qw(Wx::App);
|
||||||
|
|
||||||
|
our $print;
|
||||||
|
|
||||||
|
sub OnInit {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
my $frame = Wx::Frame->new(undef, -1, 'Toolpaths', [-1, -1], [500, 500]);
|
||||||
|
my $panel = Wx::Panel->new($frame, -1);
|
||||||
|
|
||||||
|
my $sizer = Wx::BoxSizer->new(wxVERTICAL);
|
||||||
|
$sizer->Add(Slic3r::GUI::Plater::2DToolpaths->new($panel, $print), 1, wxEXPAND, 0);
|
||||||
|
$panel->SetSizer($sizer);
|
||||||
|
|
||||||
|
$frame->Show(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
__END__
|
Loading…
Reference in New Issue
Block a user