diff --git a/lib/Slic3r/GUI/Projector.pm b/lib/Slic3r/GUI/Projector.pm index 5ccd53b59..e75ac7e09 100644 --- a/lib/Slic3r/GUI/Projector.pm +++ b/lib/Slic3r/GUI/Projector.pm @@ -521,7 +521,6 @@ has 'sender' => (is => 'rw'); has 'timer' => (is => 'rw'); has 'is_printing' => (is => 'rw', default => sub { 0 }); has '_print' => (is => 'rw'); -has '_layers' => (is => 'rw'); has '_heights' => (is => 'rw'); has '_layer_num' => (is => 'rw'); has '_timer_cb' => (is => 'rw'); @@ -545,8 +544,7 @@ sub BUILD { $print->slice; $progress_dialog->Destroy; } - - $self->_layers([ map $print->slices($_), 0..($print->layer_count-1) ]); + $self->_heights($print->heights); } @@ -639,7 +637,7 @@ sub print_completed { sub is_projecting { my ($self) = @_; - return defined $self->screen->layer; + return defined $self->screen->layer_num; } sub project_layer { @@ -650,7 +648,7 @@ sub project_layer { return; } - $self->screen->project_layer($self->_layers->[$layer_num], $layer_num); + $self->screen->project_layer($layer_num); } sub project_next_layer { @@ -719,7 +717,7 @@ sub total_resin { for my $i (0..($self->_print->layer_count-1)) { my $lh = $self->_heights->[$i] - ($i == 0 ? 0 : $self->_heights->[$i-1]); - $vol += unscale(unscale($_->area)) * $lh for @{ $self->_print->slices($i) }; + $vol += unscale(unscale($_->area)) * $lh for @{ $self->_print->layer_slices($i) }; } return $vol/1000/1000; # liters @@ -742,7 +740,7 @@ use List::Util qw(min); use Slic3r::Geometry qw(X Y unscale scale); use Slic3r::Geometry::Clipper qw(intersection_pl); -__PACKAGE__->mk_accessors(qw(config config2 scaling_factor bed_origin layer print layer_num)); +__PACKAGE__->mk_accessors(qw(config config2 scaling_factor bed_origin print layer_num)); sub new { my ($class, $parent, $config, $config2) = @_; @@ -803,9 +801,8 @@ sub _resize { } sub project_layer { - my ($self, $layer, $layer_num) = @_; + my ($self, $layer_num) = @_; - $self->layer($layer); $self->layer_num($layer_num); $self->Refresh; } @@ -873,20 +870,19 @@ sub _repaint { } } - return if !defined $self->layer; - # get layers at this height # draw layers $dc->SetPen(Wx::Pen->new(wxWHITE, 1, wxSOLID)); - my @polygons = sort { $a->contains_point($b->first_point) ? -1 : 1 } map @$_, @{$self->layer}; - foreach my $polygon (@polygons) { - if ($polygon->is_counter_clockwise) { - $dc->SetBrush(Wx::Brush->new(wxWHITE, wxSOLID)); - } else { - $dc->SetBrush(Wx::Brush->new(wxBLACK, wxSOLID)); - } - $dc->DrawPolygon($self->scaled_points_to_pixel($polygon->pp), 0, 0); + return if !$self->print || !defined $self->layer_num; + + if ($self->print->layer_solid($self->layer_num)) { + $self->_paint_expolygon($_, $dc) for @{$self->print->layer_slices($self->layer_num)}; + } else { + $self->_paint_expolygon($_, $dc) for @{$self->print->layer_solid_infill($self->layer_num)}; + $self->_paint_polygon($_, $dc) for map @{$_->grow}, + @{$self->print->layer_perimeters($self->layer_num)}, + @{$self->print->layer_infill($self->layer_num)}; } # draw support material @@ -908,6 +904,24 @@ sub _repaint { } } +sub _paint_expolygon { + my ($self, $expolygon, $dc) = @_; + + my @polygons = sort { $a->contains_point($b->first_point) ? -1 : 1 } @$expolygon; + $self->_paint_polygon($_, $dc) for @polygons; +} + +sub _paint_polygon { + my ($self, $polygon, $dc) = @_; + + if ($polygon->is_counter_clockwise) { + $dc->SetBrush(Wx::Brush->new(wxWHITE, wxSOLID)); + } else { + $dc->SetBrush(Wx::Brush->new(wxBLACK, wxSOLID)); + } + $dc->DrawPolygon($self->scaled_points_to_pixel($polygon->pp), 0, 0); +} + # convert a model coordinate into a pixel coordinate sub unscaled_point_to_pixel { my ($self, $point) = @_; diff --git a/xs/src/libslic3r/ClipperUtils.cpp b/xs/src/libslic3r/ClipperUtils.cpp index 37cc4b698..6ae6b8426 100644 --- a/xs/src/libslic3r/ClipperUtils.cpp +++ b/xs/src/libslic3r/ClipperUtils.cpp @@ -155,7 +155,7 @@ offset(const Polygons &polygons, const float delta, // perform offset ClipperLib::Paths output = _offset(polygons, delta, scale, joinType, miterLimit); - // convert into ExPolygons + // convert into Polygons return ClipperPaths_to_Slic3rMultiPoints(output); } @@ -166,7 +166,7 @@ offset(const Polylines &polylines, const float delta, // perform offset ClipperLib::Paths output = _offset(polylines, delta, scale, joinType, miterLimit); - // convert into ExPolygons + // convert into Polygons return ClipperPaths_to_Slic3rMultiPoints(output); } diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 0c402e50a..864f2da7a 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -533,8 +533,13 @@ class SLAPrintConfig : public virtual StaticPrintConfig { public: + ConfigOptionFloat fill_angle; + ConfigOptionPercent fill_density; + ConfigOptionEnum fill_pattern; ConfigOptionFloatOrPercent first_layer_height; + ConfigOptionFloatOrPercent infill_extrusion_width; ConfigOptionFloat layer_height; + ConfigOptionFloatOrPercent perimeter_extrusion_width; ConfigOptionInt raft_layers; ConfigOptionFloat raft_offset; ConfigOptionBool support_material; @@ -546,8 +551,13 @@ class SLAPrintConfig }; virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) { + OPT_PTR(fill_angle); + OPT_PTR(fill_density); + OPT_PTR(fill_pattern); OPT_PTR(first_layer_height); + OPT_PTR(infill_extrusion_width); OPT_PTR(layer_height); + OPT_PTR(perimeter_extrusion_width); OPT_PTR(raft_layers); OPT_PTR(raft_offset); OPT_PTR(support_material); diff --git a/xs/src/libslic3r/SLAPrint.cpp b/xs/src/libslic3r/SLAPrint.cpp index 985e0e2cb..053cfe05d 100644 --- a/xs/src/libslic3r/SLAPrint.cpp +++ b/xs/src/libslic3r/SLAPrint.cpp @@ -1,5 +1,9 @@ #include "SLAPrint.hpp" #include "ClipperUtils.hpp" +#include "ExtrusionEntity.hpp" +#include "Fill/FillBase.hpp" +#include "Geometry.hpp" +#include "Surface.hpp" #include #include @@ -47,7 +51,73 @@ SLAPrint::slice() TriangleMeshSlicer(&mesh).slice(slice_z, &slices); for (size_t i = 0; i < slices.size(); ++i) - this->layers[i].slices = ExPolygonCollection(slices[i]); + this->layers[i].slices.expolygons = slices[i]; + } + + // generate infill + if (this->config.fill_density < 100) { + const float shell_thickness = this->config.get_abs_value("perimeter_extrusion_width", this->config.layer_height.value); + std::auto_ptr fill = std::auto_ptr(Fill::new_from_type(this->config.fill_pattern.value)); + //fill->bounding_box = this->bb; + fill->spacing = this->config.get_abs_value("infill_extrusion_width", this->config.layer_height.value); + fill->angle = Geometry::deg2rad(this->config.fill_angle.value); + FillParams fill_params; + fill_params.density = this->config.fill_density.value/100; + + ExtrusionPath templ(erInternalInfill); + templ.width = fill->spacing; + + for (size_t i = 0; i < this->layers.size(); ++i) { + Layer &layer = this->layers[i]; + + // In order to detect what regions of this layer need to be solid, + // perform an intersection with layers within the requested shell thickness. + Polygons internal = layer.slices; + for (size_t j = 0; j < this->layers.size(); ++j) { + const Layer &other = this->layers[j]; + if (abs(other.print_z - layer.print_z) > shell_thickness) continue; + + if (j == 0 || j == this->layers.size()-1) { + internal.clear(); + break; + } else if (i != j) { + internal = intersection(internal, other.slices); + if (internal.empty()) break; + } + } + + // If we have no internal infill, just print the whole layer as a solid slice. + if (internal.empty()) continue; + layer.solid = false; + + const Polygons infill = offset(layer.slices, -scale_(shell_thickness)); + + // Generate solid infill. + layer.solid_infill.append(diff_ex(infill, internal, true)); + + // Generate internal infill. + { + fill->layer_id = i; + fill->z = layer.print_z; + + const ExPolygons internal_ex = intersection_ex(infill, internal); + for (ExPolygons::const_iterator it = internal_ex.begin(); it != internal_ex.end(); ++it) { + Polylines polylines = fill->fill_surface(Surface(stInternal, *it), fill_params); + layer.infill.append(polylines, templ); + } + } + + // Generate perimeter(s). + { + const Polygons perimeters = offset(layer.slices, -scale_(shell_thickness)/2); + for (Polygons::const_iterator it = perimeters.begin(); it != perimeters.end(); ++it) { + ExtrusionPath ep(erPerimeter); + ep.polyline = *it; + ep.width = shell_thickness; + layer.perimeters.append(ExtrusionLoop(ep)); + } + } + } } // generate support material @@ -154,23 +224,31 @@ SLAPrint::write_svg(const std::string &outputfile) const layer.print_z - (i == 0 ? 0 : this->layers[i-1].print_z) ); - const ExPolygons &slices = layer.slices.expolygons; - for (ExPolygons::const_iterator it = slices.begin(); it != slices.end(); ++it) { - std::string pd; - Polygons pp = *it; - for (Polygons::const_iterator mp = pp.begin(); mp != pp.end(); ++mp) { - std::ostringstream d; - d << "M "; - for (Points::const_iterator p = mp->points.begin(); p != mp->points.end(); ++p) { - d << unscale(p->x) - this->bb.min.x << " "; - d << size.y - (unscale(p->y) - this->bb.min.y) << " "; // mirror Y coordinates as SVG uses downwards Y - } - d << "z"; - pd += d.str() + " "; + if (layer.solid) { + const ExPolygons &slices = layer.slices.expolygons; + for (ExPolygons::const_iterator it = slices.begin(); it != slices.end(); ++it) { + std::string pd = this->_SVG_path_d(*it); + + fprintf(f,"\t\t\n", + pd.c_str(), "white", "black", "0", unscale(unscale(it->area())) + ); + } + } else { + // Solid infill. + const ExPolygons &solid_infill = layer.solid_infill.expolygons; + for (ExPolygons::const_iterator it = solid_infill.begin(); it != solid_infill.end(); ++it) { + std::string pd = this->_SVG_path_d(*it); + + fprintf(f,"\t\t\n", + pd.c_str(), "white", "black", "0" + ); + } + + // Generate perimeters. + for (ExtrusionEntitiesPtr::const_iterator it = layer.perimeters.entities.begin(); + it != layer.perimeters.entities.end(); ++it) { + //std::string pd = this->_SVG_path_d(it->polygon()); } - fprintf(f,"\t\t\n", - pd.c_str(), "white", "black", "0", unscale(unscale(it->area())) - ); } // don't print support material in raft layers @@ -206,4 +284,28 @@ SLAPrint::sm_pillars_radius() const return radius; } +std::string +SLAPrint::_SVG_path_d(const Polygon &polygon) const +{ + const Sizef3 size = this->bb.size(); + std::ostringstream d; + d << "M "; + for (Points::const_iterator p = polygon.points.begin(); p != polygon.points.end(); ++p) { + d << unscale(p->x) - this->bb.min.x << " "; + d << size.y - (unscale(p->y) - this->bb.min.y) << " "; // mirror Y coordinates as SVG uses downwards Y + } + d << "z"; + return d.str(); +} + +std::string +SLAPrint::_SVG_path_d(const ExPolygon &expolygon) const +{ + std::string pd; + const Polygons pp = expolygon; + for (Polygons::const_iterator mp = pp.begin(); mp != pp.end(); ++mp) + pd += this->_SVG_path_d(*mp) + " "; + return pd; +} + } diff --git a/xs/src/libslic3r/SLAPrint.hpp b/xs/src/libslic3r/SLAPrint.hpp index 09664b386..99d3c2f8e 100644 --- a/xs/src/libslic3r/SLAPrint.hpp +++ b/xs/src/libslic3r/SLAPrint.hpp @@ -19,9 +19,14 @@ class SLAPrint class Layer { public: ExPolygonCollection slices; + ExtrusionEntityCollection perimeters; + ExtrusionEntityCollection infill; + ExPolygonCollection solid_infill; float slice_z, print_z; + bool solid; - Layer(float _slice_z, float _print_z) : slice_z(_slice_z), print_z(_print_z) {}; + Layer(float _slice_z, float _print_z) + : slice_z(_slice_z), print_z(_print_z), solid(true) {}; }; std::vector layers; @@ -41,6 +46,8 @@ class SLAPrint BoundingBoxf3 bb; coordf_t sm_pillars_radius() const; + std::string _SVG_path_d(const Polygon &polygon) const; + std::string _SVG_path_d(const ExPolygon &expolygon) const; }; } diff --git a/xs/xsp/SLAPrint.xsp b/xs/xsp/SLAPrint.xsp index daecce38f..3788d3d14 100644 --- a/xs/xsp/SLAPrint.xsp +++ b/xs/xsp/SLAPrint.xsp @@ -18,16 +18,19 @@ DynamicPrintConfig* config() %code%{ RETVAL = new DynamicPrintConfig; RETVAL->apply(THIS->config); %}; + ExPolygons layer_slices(size_t i) + %code%{ RETVAL = THIS->layers[i].slices; %}; + ExPolygons layer_solid_infill(size_t i) + %code%{ RETVAL = THIS->layers[i].solid_infill.expolygons; %}; + Ref layer_perimeters(size_t i) + %code%{ RETVAL = &THIS->layers[i].perimeters; %}; + Ref layer_infill(size_t i) + %code%{ RETVAL = &THIS->layers[i].infill; %}; + bool layer_solid(size_t i) + %code%{ RETVAL = THIS->layers[i].solid; %}; + %{ -ExPolygons -SLAPrint::slices(i) - size_t i; - CODE: - RETVAL = THIS->layers[i].slices; - OUTPUT: - RETVAL - std::vector SLAPrint::heights() CODE: