New supports now do rafts at least to the extent the test cases run through.

New supports enabled, old supports will go away soon.
This commit is contained in:
bubnikv 2016-12-20 12:19:13 +01:00
parent 5614e997a4
commit 955bc957ba
17 changed files with 279 additions and 308 deletions

View file

@ -377,7 +377,9 @@ sub mouse_event {
$self->_layer_height_edited(undef);
} elsif ($e->Moving) {
$self->_mouse_pos($pos);
$self->Refresh;
# Only refresh if picking is enabled, in that case the objects may get highlighted if the mouse cursor
# hovers over.
$self->Refresh if ($self->enable_picking);
} else {
$e->Skip();
}
@ -1047,9 +1049,10 @@ sub Render {
$self->draw_active_object_annotations;
glFlush();
$self->SwapBuffers();
# Calling glFinish has a performance penalty, but it seems to fix some OpenGL driver hang-up with extremely large scenes.
glFinish();
}
sub draw_volumes {

View file

@ -260,44 +260,35 @@ sub generate_support_material {
$self->clear_support_layers;
if ((!$self->config->support_material && $self->config->raft_layers == 0) || scalar(@{$self->layers}) < 2) {
$self->set_step_done(STEP_SUPPORTMATERIAL);
return;
if (($self->config->support_material || $self->config->raft_layers > 0) && scalar(@{$self->layers}) > 1) {
$self->print->status_cb->(85, "Generating support material");
if (0) {
# Old supports, Perl implementation.
my $first_layer_flow = Slic3r::Flow->new_from_width(
width => ($self->print->config->first_layer_extrusion_width || $self->config->support_material_extrusion_width),
role => FLOW_ROLE_SUPPORT_MATERIAL,
nozzle_diameter => $self->print->config->nozzle_diameter->[ $self->config->support_material_extruder-1 ]
// $self->print->config->nozzle_diameter->[0],
layer_height => $self->config->get_abs_value('first_layer_height'),
bridge_flow_ratio => 0,
);
my $support_material = Slic3r::Print::SupportMaterial->new(
print_config => $self->print->config,
object_config => $self->config,
first_layer_flow => $first_layer_flow,
flow => $self->support_material_flow,
interface_flow => $self->support_material_flow(FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE),
);
$support_material->generate($self);
} else {
# New supports, C++ implementation.
$self->_generate_support_material;
}
}
$self->print->status_cb->(85, "Generating support material");
$self->_support_material->generate($self);
$self->set_step_done(STEP_SUPPORTMATERIAL);
}
sub _support_material {
my ($self) = @_;
my $first_layer_flow = Slic3r::Flow->new_from_width(
width => ($self->print->config->first_layer_extrusion_width || $self->config->support_material_extrusion_width),
role => FLOW_ROLE_SUPPORT_MATERIAL,
nozzle_diameter => $self->print->config->nozzle_diameter->[ $self->config->support_material_extruder-1 ]
// $self->print->config->nozzle_diameter->[0],
layer_height => $self->config->get_abs_value('first_layer_height'),
bridge_flow_ratio => 0,
);
if (1) {
# Old supports, Perl implementation.
return Slic3r::Print::SupportMaterial->new(
print_config => $self->print->config,
object_config => $self->config,
first_layer_flow => $first_layer_flow,
flow => $self->support_material_flow,
interface_flow => $self->support_material_flow(FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE),
);
} else {
# New supports, C++ implementation.
return Slic3r::Print::SupportMaterial2->new($self);
}
}
# Idempotence of this method is guaranteed by the fact that we don't remove things from
# fill_surfaces but we only turn them into VOID surfaces, thus preserving the boundaries.
sub clip_fill_surfaces {

View file

@ -20,6 +20,7 @@ has 'interface_flow' => (is => 'rw', required => 1);
use constant DEBUG_CONTACT_ONLY => 0;
# increment used to reach MARGIN in steps to avoid trespassing thin objects
use constant MARGIN => 1.5;
use constant MARGIN_STEP => MARGIN/3;
# generate a tree-like structure to save material

View file

@ -209,7 +209,6 @@ xsp/Polygon.xsp
xsp/Polyline.xsp
xsp/PolylineCollection.xsp
xsp/Print.xsp
xsp/SupportMaterial.xsp
xsp/Surface.xsp
xsp/SurfaceCollection.xsp
xsp/TriangleMesh.xsp

View file

@ -1222,17 +1222,39 @@ bool EdgeGrid::Grid::signed_distance(const Point &pt, coord_t search_radius, coo
return true;
}
Polygons EdgeGrid::Grid::contours_simplified() const
Polygons EdgeGrid::Grid::contours_simplified(coord_t offset) const
{
typedef std::unordered_multimap<Point, int, PointHash> EndPointMapType;
// 0) Prepare a binary grid.
size_t cell_rows = m_rows + 2;
size_t cell_cols = m_cols + 2;
std::vector<char> cell_inside(cell_rows * cell_cols, false);
for (int r = 0; r < int(cell_rows); ++ r)
for (int c = 0; c < int(cell_cols); ++ c)
cell_inside[r * cell_cols + c] = cell_inside_or_crossing(r - 1, c - 1);
// Fill in empty cells, which have a left / right neighbor filled.
// Fill in empty cells, which have the top / bottom neighbor filled.
{
std::vector<char> cell_inside2(cell_inside);
for (int r = 1; r + 1 < int(cell_rows); ++ r) {
for (int c = 1; c + 1 < int(cell_cols); ++ c) {
int addr = r * cell_cols + c;
if ((cell_inside2[addr - 1] && cell_inside2[addr + 1]) ||
(cell_inside2[addr - cell_cols] && cell_inside2[addr + cell_cols]))
cell_inside[addr] = true;
}
}
}
// 1) Collect the lines.
std::vector<Line> lines;
EndPointMapType start_point_to_line_idx;
for (int r = 0; r <= int(m_rows); ++ r) {
for (int c = 0; c <= int(m_cols); ++ c) {
bool left = cell_inside_or_crossing(r , c-1);
bool top = cell_inside_or_crossing(r-1, c );
bool current = cell_inside_or_crossing(r , c );
int addr = (r + 1) * cell_cols + c + 1;
bool left = cell_inside[addr - 1];
bool top = cell_inside[addr - cell_cols];
bool current = cell_inside[addr];
if (left != current) {
lines.push_back(
left ?
@ -1312,7 +1334,6 @@ Polygons EdgeGrid::Grid::contours_simplified() const
// Remove collineaer points.
Points pts;
pts.reserve(poly.points.size());
coord_t downscale = 5;
for (size_t j = 0; j < poly.points.size(); ++ j) {
size_t j0 = (j == 0) ? poly.points.size() - 1 : j - 1;
size_t j2 = (j + 1 == poly.points.size()) ? 0 : j + 1;
@ -1320,8 +1341,8 @@ Polygons EdgeGrid::Grid::contours_simplified() const
if (v.x != 0 && v.y != 0) {
// This is a corner point. Copy it to the output contour.
Point p = poly.points[j];
p.y += (v.x < 0) ? downscale : -downscale;
p.x += (v.y > 0) ? downscale : -downscale;
p.y += (v.x < 0) ? - offset : offset;
p.x += (v.y > 0) ? - offset : offset;
pts.push_back(p);
}
}

View file

@ -58,7 +58,7 @@ public:
const size_t cols() const { return m_cols; }
// For supports: Contours enclosing the rasterized edges.
Polygons contours_simplified() const;
Polygons contours_simplified(coord_t offset) const;
protected:
struct Cell {

View file

@ -882,7 +882,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
Point refpt = rotate_vector.second.rotated(- rotate_vector.first);
// _align_to_grid will not work correctly with positive pattern_shift.
coord_t pattern_shift_scaled = coord_t(scale_(pattern_shift)) % line_spacing;
refpt.x -= (pattern_shift_scaled > 0) ? pattern_shift_scaled : (line_spacing + pattern_shift_scaled);
refpt.x -= (pattern_shift_scaled >= 0) ? pattern_shift_scaled : (line_spacing + pattern_shift_scaled);
bounding_box.merge(_align_to_grid(
bounding_box.min,
Point(line_spacing, line_spacing),
@ -892,7 +892,9 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
// Intersect a set of euqally spaced vertical lines wiht expolygon.
// n_vlines = ceil(bbox_width / line_spacing)
size_t n_vlines = (bounding_box.max.x - bounding_box.min.x + line_spacing - 1) / line_spacing;
coord_t x0 = bounding_box.min.x + (line_spacing + SCALED_EPSILON) / 2;
coord_t x0 = bounding_box.min.x;
if (full_infill)
x0 += (line_spacing + SCALED_EPSILON) / 2;
#ifdef SLIC3R_DEBUG
static int iRun = 0;

View file

@ -159,6 +159,7 @@ public:
void bridge_over_infill();
void _make_perimeters();
void _infill();
void _generate_support_material();
private:
Print* _print;

View file

@ -2,6 +2,7 @@
#include "BoundingBox.hpp"
#include "ClipperUtils.hpp"
#include "Geometry.hpp"
#include "SupportMaterial.hpp"
#include <boost/log/trivial.hpp>
@ -1243,4 +1244,10 @@ PrintObject::_infill()
this->state.set_done(posInfill);
}
void PrintObject::_generate_support_material()
{
PrintObjectSupportMaterial support_material(this, PrintObject::slicing_parameters());
support_material.generate(*this);
}
} // namespace Slic3r

View file

@ -33,10 +33,18 @@ SlicingParameters SlicingParameters::create_from_config(
SlicingParameters params;
params.layer_height = object_config.layer_height.value;
params.first_print_layer_height = first_layer_height;
params.first_object_layer_height = first_layer_height;
params.object_print_z_min = 0.;
params.object_print_z_max = object_height;
params.base_raft_layers = object_config.raft_layers.value;
params.soluble_interface = soluble_interface;
if (! soluble_interface) {
params.gap_raft_object = object_config.support_material_contact_distance.value;
params.gap_object_support = object_config.support_material_contact_distance.value;
params.gap_support_object = object_config.support_material_contact_distance.value;
}
if (params.base_raft_layers > 0) {
params.interface_raft_layers = (params.base_raft_layers + 1) / 2;
@ -70,18 +78,21 @@ SlicingParameters SlicingParameters::create_from_config(
if (params.has_raft()) {
// Raise first object layer Z by the thickness of the raft itself plus the extra distance required by the support material logic.
//FIXME The last raft layer is the contact layer, which shall be printed with a bridging flow for ease of separation. Currently it is not the case.
coordf_t print_z = first_layer_height + object_config.support_material_contact_distance.value;
if (params.raft_layers() == 1) {
// There is only the contact layer.
params.contact_raft_layer_height = first_layer_height;
params.raft_contact_top_z = first_layer_height;
} else {
print_z +=
// Number of the base raft layers is decreased by the first layer, which has already been added to print_z.
coordf_t(params.base_raft_layers - 1) * params.base_raft_layer_height +
// Number of the interface raft layers is decreased by the contact layer.
coordf_t(params.interface_raft_layers - 1) * params.interface_raft_layer_height +
params.contact_raft_layer_height;
assert(params.base_raft_layers > 0);
assert(params.interface_raft_layers > 0);
// Number of the base raft layers is decreased by the first layer.
params.raft_base_top_z = first_layer_height + coordf_t(params.base_raft_layers - 1) * params.base_raft_layer_height;
// Number of the interface raft layers is decreased by the contact layer.
params.raft_interface_top_z = params.raft_base_top_z + coordf_t(params.interface_raft_layers - 1) * params.interface_raft_layer_height;
params.raft_contact_top_z = params.raft_interface_top_z + params.contact_raft_layer_height;
}
params.object_print_z_min = print_z;
coordf_t print_z = params.raft_contact_top_z + params.gap_raft_object;
params.object_print_z_min = print_z;
params.object_print_z_max += print_z;
}

View file

@ -53,6 +53,10 @@ struct SlicingParameters
// or by the variable layer thickness table.
coordf_t layer_height;
// First layer height of the print, this may be used for the first layer of the raft
// or for the first layer of the print.
coordf_t first_print_layer_height;
// Thickness of the first layer. This is either the first print layer thickness if printed without a raft,
// or a bridging flow thickness if printed over a non-soluble raft,
// or a normal layer height if printed over a soluble raft.
@ -61,6 +65,16 @@ struct SlicingParameters
// If the object is printed over a non-soluble raft, the first layer may be printed with a briding flow.
bool first_object_layer_bridging;
// Soluble interface? (PLA soluble in water, HIPS soluble in lemonen)
// otherwise the interface must be broken off.
bool soluble_interface;
// Gap when placing object over raft.
coordf_t gap_raft_object;
// Gap when placing support over object.
coordf_t gap_object_support;
// Gap when placing object over support.
coordf_t gap_support_object;
// Minimum / maximum layer height, to be used for the automatic adaptive layer height algorithm,
// or by an interactive layer height editor.
coordf_t min_layer_height;
@ -69,6 +83,10 @@ struct SlicingParameters
// Bottom and top of the printed object.
// If printed without a raft, object_print_z_min = 0 and object_print_z_max = object height.
// Otherwise object_print_z_min is equal to the raft height.
coordf_t raft_base_top_z;
coordf_t raft_interface_top_z;
coordf_t raft_contact_top_z;
// In case of a soluble interface, object_print_z_min == raft_contact_top_z, otherwise there is a gap between the raft and the 1st object layer.
coordf_t object_print_z_min;
coordf_t object_print_z_max;
};

View file

@ -31,60 +31,35 @@ namespace Slic3r {
#define PILLAR_SIZE (2.5)
#define PILLAR_SPACING 10
PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object) :
PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object, const SlicingParameters &slicing_params) :
m_object (object),
m_print_config (&object->print()->config),
m_object_config (&object->config),
m_slicing_params (slicing_params),
m_first_layer_flow (Flow::new_from_config_width(
frSupportMaterial,
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
(object->print()->config.first_layer_extrusion_width.value > 0) ? object->print()->config.first_layer_extrusion_width : object->config.support_material_extrusion_width,
object->print()->config.nozzle_diameter.get_at(object->config.support_material_extruder-1),
object->config.get_abs_value("first_layer_height"),
slicing_params.first_print_layer_height,
false
)),
m_support_material_flow (Flow::new_from_config_width(
frSupportMaterial,
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
(object->config.support_material_extrusion_width.value > 0) ? object->config.support_material_extrusion_width : object->config.extrusion_width,
object->print()->config.nozzle_diameter.get_at(object->config.support_material_extruder-1),
object->config.layer_height.value,
slicing_params.layer_height,
false)),
m_support_material_interface_flow(Flow::new_from_config_width(
frSupportMaterialInterface,
(object->config.support_material_extrusion_width.value > 0) ? object->config.support_material_extrusion_width : object->config.extrusion_width,
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
(object->config.support_material_extrusion_width > 0) ? object->config.support_material_extrusion_width : object->config.extrusion_width,
object->print()->config.nozzle_diameter.get_at(object->config.support_material_interface_extruder-1),
object->config.layer_height.value,
false)),
m_soluble_interface (object->config.support_material_contact_distance.value == 0),
m_support_material_raft_base_flow(0, 0, 0, false),
m_support_material_raft_interface_flow(0, 0, 0, false),
m_support_material_raft_contact_flow(0, 0, 0, false),
m_has_raft (object->config.raft_layers.value > 0),
m_num_base_raft_layers (0),
m_num_interface_raft_layers (0),
m_num_contact_raft_layers (0),
// If set, the raft contact layer is laid with round strings, which are easily detachable
// from both the below and above layes.
// Otherwise a normal flow is used and the strings are squashed against the layer below,
// creating a firm bond with the layer below and making the interface top surface flat.
#if 1
// This is the standard Slic3r behavior.
m_raft_contact_layer_bridging(false),
m_object_1st_layer_bridging (true),
#else
// This is more akin to what Simplify3D or Zortrax do.
m_raft_contact_layer_bridging(true),
m_object_1st_layer_bridging (false),
#endif
m_raft_height (0.),
m_raft_base_height (0.),
m_raft_interface_height (0.),
m_raft_contact_height (0.),
// 50 mirons layer
m_support_layer_height_min (0.05),
m_support_layer_height_max (0.),
@ -101,79 +76,6 @@ PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object
// the support layers will be synchronized with the object layers exactly, no layer will be combined.
m_combine_support_layers (true)
{
// Based on the raft style and size, initialize the raft layers and the 1st object layer attributes.
size_t num_raft_layers = m_object_config->raft_layers.value;
//FIXME better to draw thin strings, which are easier to remove from the object.
if (m_has_raft)
{
if (m_raft_contact_layer_bridging)
m_support_material_raft_contact_flow = Flow::new_from_spacing(
m_support_material_raft_interface_flow.spacing(),
m_support_material_raft_interface_flow.nozzle_diameter,
m_support_material_raft_interface_flow.height,
true);
if (m_raft_contact_layer_bridging && num_raft_layers == 1)
// The bridging contact layer will not bond to the bed well on its own.
// Ensure there is at least the 1st layer printed with a firm squash.
++ num_raft_layers;
// Split the raft layers into a single contact layer
// and an equal number of interface and base layers,
// with m_num_interface_raft_layers >= m_num_base_raft_layers.
m_num_contact_raft_layers = 1;
m_num_interface_raft_layers = num_raft_layers / 2;
m_num_base_raft_layers = num_raft_layers - m_num_contact_raft_layers - m_num_interface_raft_layers;
assert(m_num_interface_raft_layers >= m_num_base_raft_layers);
assert(m_num_contact_raft_layers + m_num_base_raft_layers + m_num_interface_raft_layers == num_raft_layers);
m_raft_contact_height = m_num_contact_raft_layers * m_support_material_raft_contact_flow.height;
if (m_num_base_raft_layers > 0) {
m_raft_base_height = first_layer_height() + (m_num_base_raft_layers - 1) * m_support_material_raft_base_flow.height;
m_raft_interface_height = m_num_interface_raft_layers * m_support_material_raft_interface_flow.height;
} else if (m_num_interface_raft_layers > 0) {
m_raft_base_height = 0;
m_raft_interface_height = first_layer_height() + (m_num_interface_raft_layers - 1) * m_support_material_raft_interface_flow.height;
} else {
m_raft_base_height = 0;
m_raft_interface_height = 0;
}
m_raft_height = m_raft_base_height + m_raft_interface_height + m_raft_contact_height;
// Find the layer height of the 1st object layer.
if (m_object_1st_layer_bridging) {
// Use an average nozzle diameter.
std::set<size_t> extruders = m_object->print()->object_extruders();
coordf_t nozzle_dmr = 0;
for (std::set<size_t>::const_iterator it = extruders.begin(); it != extruders.end(); ++ it) {
nozzle_dmr += m_object->print()->config.nozzle_diameter.get_at(*it);
}
nozzle_dmr /= extruders.size();
m_object_1st_layer_height = nozzle_dmr;
} else {
m_object_1st_layer_height = m_object->config.layer_height.value;
for (t_layer_height_ranges::const_iterator it = m_object->layer_height_ranges.begin(); it != m_object->layer_height_ranges.end(); ++ it) {
if (m_object_1st_layer_height >= it->first.first && m_object_1st_layer_height <= it->first.second) {
m_object_1st_layer_height = it->second;
break;
}
}
}
m_object_1st_layer_gap = m_soluble_interface ? 0. : m_object_config->support_material_contact_distance.value;
m_object_1st_layer_print_z = m_raft_height + m_object_1st_layer_gap + m_object_1st_layer_height;
}
else
{
// No raft.
m_raft_contact_layer_bridging = false;
m_object_1st_layer_bridging = false;
m_object_1st_layer_height = m_first_layer_flow.height;
m_object_1st_layer_gap = 0;
m_object_1st_layer_print_z = m_object_1st_layer_height;
}
}
// Using the std::deque as an allocator.
@ -286,7 +188,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object)
// There is a contact layer below the 1st object layer in the bottom contacts.
// There is also a 1st intermediate layer containing bases of support columns.
// Extend the bases of the support columns and create the raft base.
Polygons raft = this->generate_raft_base(object, bottom_contacts, intermediate_layers);
MyLayersPtr raft_layers = this->generate_raft_base(object, top_contacts, intermediate_layers, layer_storage);
/*
// If we wanted to apply some special logic to the first support layers lying on
@ -323,7 +225,8 @@ void PrintObjectSupportMaterial::generate(PrintObject &object)
// Install support layers into the object.
MyLayersPtr layers_sorted;
layers_sorted.reserve(bottom_contacts.size() + top_contacts.size() + intermediate_layers.size() + interface_layers.size());
layers_sorted.reserve(raft_layers.size() + bottom_contacts.size() + top_contacts.size() + intermediate_layers.size() + interface_layers.size());
layers_append(layers_sorted, raft_layers);
layers_append(layers_sorted, bottom_contacts);
layers_append(layers_sorted, top_contacts);
layers_append(layers_sorted, intermediate_layers);
@ -351,7 +254,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object)
BOOST_LOG_TRIVIAL(info) << "Support generator - Generating tool paths";
// Generate the actual toolpaths and save them into each layer.
this->generate_toolpaths(object, raft, bottom_contacts, top_contacts, intermediate_layers, interface_layers);
this->generate_toolpaths(object, raft_layers, bottom_contacts, top_contacts, intermediate_layers, interface_layers);
BOOST_LOG_TRIVIAL(info) << "Support generator - End";
}
@ -670,7 +573,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
MyLayer &new_layer = layer_allocate(layer_storage, sltTopContact);
const Layer *layer_below = (layer_id > 0) ? object.get_layer(layer_id - 1) : NULL;
new_layer.idx_object_layer_above = layer_id;
if (m_soluble_interface) {
if (m_slicing_params.soluble_interface) {
// Align the contact surface height with a layer immediately below the supported layer.
new_layer.height = layer_below ?
// Interface layer will be synchronized with the object.
@ -984,16 +887,16 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
// Grow top surfaces so that interface and support generation are generated
// with some spacing from object - it looks we don't need the actual
// top shapes so this can be done here
layer_new.height = m_soluble_interface ?
layer_new.height = m_slicing_params.soluble_interface ?
// Align the interface layer with the object's layer height.
object.get_layer(layer_id + 1)->height :
// Place a bridge flow interface layer over the top surface.
m_support_material_interface_flow.nozzle_diameter;
layer_new.print_z = layer.print_z + layer_new.height +
(m_soluble_interface ? 0. : m_object_config->support_material_contact_distance.value);
(m_slicing_params.soluble_interface ? 0. : m_object_config->support_material_contact_distance.value);
layer_new.bottom_z = layer.print_z;
layer_new.idx_object_layer_below = layer_id;
layer_new.bridging = ! m_soluble_interface;
layer_new.bridging = ! m_slicing_params.soluble_interface;
//FIXME how much to inflate the top surface?
layer_new.polygons = offset(touching, float(m_support_material_flow.scaled_width()));
#ifdef SLIC3R_DEBUG
@ -1011,7 +914,8 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
// Create an EdgeGrid, initialize it with projection, initialize signed distance field.
Slic3r::EdgeGrid::Grid grid;
coord_t grid_resolution = scale_(1.5f);
coordf_t support_spacing = m_object_config->support_material_spacing.value + m_support_material_flow.spacing();
coord_t grid_resolution = scale_(support_spacing); // scale_(1.5f);
BoundingBox bbox = get_extents(projection);
bbox.offset(20);
bbox.align_to_grid(grid_resolution);
@ -1020,7 +924,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
grid.calculate_sdf();
// Extract a bounding contour from the grid.
Polygons projection_simplified = grid.contours_simplified();
Polygons projection_simplified = grid.contours_simplified(-5);
#ifdef SLIC3R_DEBUG
{
BoundingBox bbox = get_extents(projection);
@ -1031,12 +935,15 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
svg.draw(union_ex(projection_simplified, false), "red", 0.5);
}
#endif /* SLIC3R_DEBUG */
projection = std::move(projection_simplified);
layer_support_areas[layer_id] = diff(
grid.contours_simplified(m_support_material_flow.scaled_spacing()/2 + 5),
to_polygons(layer.slices.expolygons),
true);
// Remove the areas that touched from the projection that will continue on next, lower, top surfaces.
// Remove the areas that touched from the projection that will continue on next, lower, top surfaces.
// projection = diff(projection, touching);
projection = diff(projection, to_polygons(layer.slices.expolygons), true);
layer_support_areas[layer_id] = projection;
projection = diff(projection_simplified, to_polygons(layer.slices.expolygons), true);
// layer_support_areas[layer_id] = projection;
}
std::reverse(bottom_contacts.begin(), bottom_contacts.end());
} // ! top_contacts.empty()
@ -1058,7 +965,7 @@ void PrintObjectSupportMaterial::trim_top_contacts_by_bottom_contacts(
// For all top contact layers overlapping with the thick bottom contact layer:
for (size_t idx_top = idx_top_first; idx_top < top_contacts.size(); ++ idx_top) {
MyLayer &layer_top = *top_contacts[idx_top];
coordf_t interface_z = m_soluble_interface ?
coordf_t interface_z = m_slicing_params.soluble_interface ?
(layer_top.bottom_z + EPSILON) :
(layer_top.bottom_z - m_support_layer_height_min);
if (interface_z < layer_bottom.print_z) {
@ -1093,9 +1000,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_int
return intermediate_layers;
std::sort(extremes.begin(), extremes.end());
// Top of the 0th layer.
coordf_t top_z_0th = this->raft_base_height() + this->raft_interface_height();
assert(extremes.front().z() > top_z_0th && extremes.front().z() >= this->first_layer_height());
assert(extremes.front().z() > m_slicing_params.raft_interface_top_z && extremes.front().z() >= m_slicing_params.first_print_layer_height);
// Generate intermediate layers.
// The first intermediate layer is the same as the 1st layer if there is no raft,
@ -1103,7 +1008,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_int
// Intermediate layers are always printed with a normal etrusion flow (non-bridging).
for (size_t idx_extreme = 0; idx_extreme < extremes.size(); ++ idx_extreme) {
LayerExtreme *extr1 = (idx_extreme == 0) ? NULL : &extremes[idx_extreme-1];
coordf_t extr1z = (extr1 == NULL) ? top_z_0th : extr1->z();
coordf_t extr1z = (extr1 == NULL) ? m_slicing_params.raft_interface_top_z : extr1->z();
LayerExtreme &extr2 = extremes[idx_extreme];
coordf_t extr2z = extr2.z();
coordf_t dist = extr2z - extr1z;
@ -1112,7 +1017,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_int
size_t n_layers_extra = size_t(ceil(dist / m_support_layer_height_max));
assert(n_layers_extra > 0);
coordf_t step = dist / coordf_t(n_layers_extra);
if (! m_soluble_interface && ! m_synchronize_support_layers_with_object && extr2.layer->layer_type == sltTopContact) {
if (! m_slicing_params.soluble_interface && ! m_synchronize_support_layers_with_object && extr2.layer->layer_type == sltTopContact) {
assert(extr2.layer->height == 0.);
// This is a top interface layer, which does not have a height assigned yet. Do it now.
if (m_synchronize_support_layers_with_object) {
@ -1345,43 +1250,74 @@ void PrintObjectSupportMaterial::generate_base_layers(
#endif /* SLIC3R_DEBUG */
}
Polygons PrintObjectSupportMaterial::generate_raft_base(
PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_raft_base(
const PrintObject &object,
const MyLayersPtr &bottom_contacts,
MyLayersPtr &intermediate_layers) const
const MyLayersPtr &top_contacts,
MyLayersPtr &intermediate_layers,
MyLayerStorage &layer_storage) const
{
assert(! bottom_contacts.empty());
// Areas covered by the raft, supporting the raft interface and the support columns.
Polygons raft_polygons;
#if 0
// How much to inflate the support columns to be stable. This also applies to the 1st layer, if no raft layers are to be printed.
const float inflate_factor = scale_(3.);
if (this->has_raft()) {
MyLayer &contacts = *bottom_contacts.front();
MyLayer &columns_base = *intermediate_layers.front();
if (m_num_base_raft_layers == 0 && m_num_interface_raft_layers == 0 && m_num_contact_raft_layers == 1) {
// Having only the contact layer, which has the height of the 1st layer.
// We are free to merge the contacts with the columns_base, they will be printed the same way.
polygons_append(contacts.polygons, offset(columns_base.polygons, inflate_factor));
contacts.polygons = union_(contacts.polygons);
} else {
// Having multiple raft layers.
assert(m_num_interface_raft_layers > 0);
// Extend the raft base by the bases of the support columns, add the raft contacts.
raft_polygons = raft_interface_polygons;
//FIXME make the offset configurable.
polygons_append(raft_polygons, offset(columns_base.polygons, inflate_factor));
raft_polygons = union_(raft_polygons);
}
} else {
// No raft. The 1st intermediate layer contains the bases of the support columns.
// Expand the polygons, but trim with the object.
MyLayer &columns_base = *intermediate_layers.front();
columns_base.polygons = diff(
offset(columns_base.polygons, inflate_factor),
offset(m_object->get_layer(0), safety_factor);
MyLayer *contacts = top_contacts.empty() ? nullptr : top_contacts.front();
MyLayer *columns_base = intermediate_layers.empty() ? nullptr : intermediate_layers.front();
if (contacts != nullptr && contacts->print_z > m_slicing_params.raft_contact_top_z + EPSILON)
// This is not the raft contact layer.
contacts = nullptr;
// Output vector.
MyLayersPtr raft_layers;
// Expand the 1st intermediate layer, which contains the bases of the support columns.
Polygons base;
if (columns_base != nullptr) {
base = offset(columns_base->polygons, inflate_factor);
// Modify the 1st intermediate layer with the expanded support columns.
columns_base->polygons = diff(
base,
offset(m_object->layers.front()->slices.expolygons, scale_(m_gap_xy)));
if (contacts != nullptr)
columns_base->polygons = diff(columns_base->polygons, contacts->polygons);
}
if (m_slicing_params.has_raft() && contacts != nullptr) {
// Merge the untrimmed columns base with the expanded raft interface, to be used for the support base and interface.
base = union_(base, offset(contacts->polygons, inflate_factor));
}
#endif
return raft_polygons;
if (m_slicing_params.has_raft() && m_slicing_params.raft_layers() > 1 && ! base.empty()) {
// Do not add the raft contact layer, only add the raft layers below the contact layer.
// Insert the 1st layer.
{
MyLayer &new_layer = layer_allocate(layer_storage, (m_slicing_params.base_raft_layers > 0) ? sltRaftBase : sltRaftInterface);
raft_layers.push_back(&new_layer);
new_layer.print_z = m_slicing_params.first_print_layer_height;
new_layer.height = m_slicing_params.first_print_layer_height;
new_layer.bottom_z = 0.;
new_layer.polygons = base;
}
// Insert the base layers.
for (size_t i = 1; i < m_slicing_params.base_raft_layers; ++ i) {
coordf_t print_z = raft_layers.back()->print_z;
MyLayer &new_layer = layer_allocate(layer_storage, sltRaftBase);
raft_layers.push_back(&new_layer);
new_layer.print_z = print_z + m_slicing_params.base_raft_layer_height;
new_layer.height = m_slicing_params.base_raft_layer_height;
new_layer.bottom_z = print_z;
new_layer.polygons = base;
}
// Insert the interface layers.
for (size_t i = 1; i < m_slicing_params.interface_raft_layers; ++ i) {
coordf_t print_z = raft_layers.back()->print_z;
MyLayer &new_layer = layer_allocate(layer_storage, sltRaftInterface);
raft_layers.push_back(&new_layer);
new_layer.print_z = print_z + m_slicing_params.interface_raft_layer_height;
new_layer.height = m_slicing_params.interface_raft_layer_height;
new_layer.bottom_z = print_z;
new_layer.polygons = base;
}
}
return raft_layers;
}
// Convert some of the intermediate layers into top/bottom interface layers.
@ -1474,6 +1410,7 @@ static inline void fill_expolygons_generate_paths(
FillParams fill_params;
fill_params.density = density;
fill_params.complete = true;
fill_params.dont_adjust = true;
for (ExPolygons::const_iterator it_expolygon = expolygons.begin(); it_expolygon != expolygons.end(); ++ it_expolygon) {
Surface surface(stInternal, *it_expolygon);
extrusion_entities_append_paths(
@ -1495,6 +1432,7 @@ static inline void fill_expolygons_generate_paths(
FillParams fill_params;
fill_params.density = density;
fill_params.complete = true;
fill_params.dont_adjust = true;
for (ExPolygons::iterator it_expolygon = expolygons.begin(); it_expolygon != expolygons.end(); ++ it_expolygon) {
Surface surface(stInternal, std::move(*it_expolygon));
extrusion_entities_append_paths(
@ -1636,7 +1574,7 @@ void LoopInterfaceProcessor::generate(MyLayerExtruded &top_contact_layer, const
void PrintObjectSupportMaterial::generate_toolpaths(
const PrintObject &object,
const Polygons &raft,
const MyLayersPtr &raft_layers,
const MyLayersPtr &bottom_contacts,
const MyLayersPtr &top_contacts,
const MyLayersPtr &intermediate_layers,
@ -1667,7 +1605,8 @@ void PrintObjectSupportMaterial::generate_toolpaths(
std::unique_ptr<Fill> filler_interface = std::unique_ptr<Fill>(Fill::new_from_type(ipRectilinear));
std::unique_ptr<Fill> filler_support = std::unique_ptr<Fill>(Fill::new_from_type(infill_pattern));
{
BoundingBox bbox_object = object.bounding_box();
// BoundingBox bbox_object = object.bounding_box();
BoundingBox bbox_object(Point(-scale_(1.), -scale_(1.0)), Point(scale_(1.), scale_(1.)));
filler_interface->set_bounding_box(bbox_object);
filler_support->set_bounding_box(bbox_object);
}
@ -1694,12 +1633,64 @@ void PrintObjectSupportMaterial::generate_toolpaths(
},
);
*/
// Insert the raft base layers.
size_t support_layer_id = 0;
for (; support_layer_id < size_t(std::max(0, int(m_slicing_params.raft_layers()) - 1)); ++ support_layer_id) {
SupportLayer &support_layer = *object.support_layers[support_layer_id];
assert(support_layer_id < raft_layers.size());
MyLayer &raft_layer = *raft_layers[support_layer_id];
//FIXME When paralellizing, each thread shall have its own copy of the fillers.
Fill *filler = filler_support.get();
filler->angle = 0.;
// We don't use $base_flow->spacing because we need a constant spacing
// value that guarantees that all layers are correctly aligned.
Flow flow(m_support_material_flow.width, raft_layer.height, m_support_material_flow.nozzle_diameter, raft_layer.bridging);
filler->spacing = m_support_material_flow.spacing();
float density = support_density;
// find centerline of the external loop/extrusions
ExPolygons to_infill = (support_layer_id == 0 || ! with_sheath) ?
// union_ex(base_polygons, true) :
offset2_ex(raft_layer.polygons, SCALED_EPSILON, - SCALED_EPSILON) :
offset2_ex(raft_layer.polygons, SCALED_EPSILON, - SCALED_EPSILON - 0.5*flow.scaled_width());
if (support_layer_id == 0) {
// Base flange.
filler = filler_interface.get();
filler->angle = m_object_config->support_material_angle + 90.;
density = 0.5f;
flow = m_first_layer_flow;
// use the proper spacing for first layer as we don't need to align
// its pattern to the other layers
//FIXME When paralellizing, each thread shall have its own copy of the fillers.
filler->spacing = flow.spacing();
} else if (with_sheath) {
// Draw a perimeter all around the support infill. This makes the support stable, but difficult to remove.
// TODO: use brim ordering algorithm
Polygons to_infill_polygons = to_polygons(to_infill);
// TODO: use offset2_ex()
to_infill = offset_ex(to_infill, - flow.scaled_spacing());
extrusion_entities_append_paths(
support_layer.support_fills.entities,
to_polylines(STDMOVE(to_infill_polygons)),
erSupportMaterial, flow.mm3_per_mm(), flow.width, flow.height);
}
fill_expolygons_generate_paths(
// Destination
support_layer.support_fills.entities,
// Regions to fill
STDMOVE(to_infill),
// Filler and its parameters
filler, density,
// Extrusion parameters
erSupportMaterial, flow);
}
// Indices of the 1st layer in their respective container at the support layer height.
size_t idx_layer_bottom_contact = 0;
size_t idx_layer_top_contact = 0;
size_t idx_layer_intermediate = 0;
size_t idx_layer_inteface = 0;
for (size_t support_layer_id = 0; support_layer_id < object.support_layers.size(); ++ support_layer_id)
for (; support_layer_id < object.support_layers.size(); ++ support_layer_id)
{
SupportLayer &support_layer = *object.support_layers[support_layer_id];
@ -1754,7 +1745,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
// If no loops are allowed, we treat the contact layer exactly as a generic interface layer.
if (interface_layer.could_merge(top_contact_layer))
interface_layer.merge(std::move(top_contact_layer));
}
}
if (! interface_layer.empty() && ! base_layer.empty()) {
// turn base support into interface when it's contained in our holes
@ -1814,7 +1805,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
// We don't use $base_flow->spacing because we need a constant spacing
// value that guarantees that all layers are correctly aligned.
Flow flow(m_support_material_flow.width, base_layer.layer->height, m_support_material_flow.nozzle_diameter, base_layer.layer->bridging);
filler->spacing = flow.spacing();
filler->spacing = m_support_material_flow.spacing();
float density = support_density;
// find centerline of the external loop/extrusions
ExPolygons to_infill = (support_layer_id == 0 || ! with_sheath) ?

View file

@ -3,6 +3,7 @@
#include "Flow.hpp"
#include "PrintConfig.hpp"
#include "Slicing.hpp"
namespace Slic3r {
@ -22,7 +23,8 @@ class PrintObjectSupportMaterial
public:
enum SupporLayerType {
sltUnknown = 0,
sltRaft,
sltRaftBase,
sltRaftInterface,
stlFirstLayer,
sltBottomContact,
sltBottomInterface,
@ -118,37 +120,17 @@ public:
typedef std::deque<MyLayer> MyLayerStorage;
public:
PrintObjectSupportMaterial(const PrintObject *object);
PrintObjectSupportMaterial(const PrintObject *object, const SlicingParameters &slicing_params);
// Height of the 1st layer is user configured as it is important for the print
// to stick to he print bed.
coordf_t first_layer_height() const { return m_object_config->first_layer_height.value; }
// Is raft enabled?
bool has_raft() const { return m_has_raft; }
bool has_raft() const { return m_slicing_params.has_raft(); }
// Has any support?
bool has_support() const { return m_object_config->support_material.value; }
// How many raft layers are there below the 1st object layer?
// The 1st object layer_id will be offsetted by this number.
size_t num_raft_layers() const { return m_object_config->raft_layers.value; }
// num_raft_layers() == num_raft_base_layers() + num_raft_interface_layers() + num_raft_contact_layers().
size_t num_raft_base_layers() const { return m_num_base_raft_layers; }
size_t num_raft_interface_layers() const { return m_num_interface_raft_layers; }
size_t num_raft_contact_layers() const { return m_num_contact_raft_layers; }
coordf_t raft_height() const { return m_raft_height; }
coordf_t raft_base_height() const { return m_raft_base_height; }
coordf_t raft_interface_height() const { return m_raft_interface_height; }
coordf_t raft_contact_height() const { return m_raft_contact_height; }
bool raft_bridging() const { return m_raft_contact_layer_bridging; }
// 1st layer of the object will be printed depeding on the raft settings.
coordf_t first_object_layer_print_z() const { return m_object_1st_layer_print_z; }
coordf_t first_object_layer_height() const { return m_object_1st_layer_height; }
coordf_t first_object_layer_gap() const { return m_object_1st_layer_gap; }
bool first_object_layer_bridging() const { return m_object_1st_layer_bridging; }
// Generate support material for the object.
// New support layers will be added to the object,
// with extrusion paths and islands filled in for each support layer.
@ -185,10 +167,11 @@ private:
MyLayersPtr &intermediate_layers,
std::vector<Polygons> &layer_support_areas) const;
Polygons generate_raft_base(
MyLayersPtr generate_raft_base(
const PrintObject &object,
const MyLayersPtr &bottom_contacts,
MyLayersPtr &intermediate_layers) const;
const MyLayersPtr &top_contacts,
MyLayersPtr &intermediate_layers,
MyLayerStorage &layer_storage) const;
MyLayersPtr generate_interface_layers(
const PrintObject &object,
@ -205,7 +188,7 @@ private:
// Produce the actual G-code.
void generate_toolpaths(
const PrintObject &object,
const Polygons &raft,
const MyLayersPtr &raft_layers,
const MyLayersPtr &bottom_contacts,
const MyLayersPtr &top_contacts,
const MyLayersPtr &intermediate_layers,
@ -214,36 +197,14 @@ private:
const PrintObject *m_object;
const PrintConfig *m_print_config;
const PrintObjectConfig *m_object_config;
SlicingParameters m_slicing_params;
Flow m_first_layer_flow;
Flow m_support_material_flow;
coordf_t m_support_material_spacing;
Flow m_support_material_interface_flow;
bool m_soluble_interface;
coordf_t m_support_material_interface_spacing;
Flow m_support_material_raft_base_flow;
Flow m_support_material_raft_interface_flow;
Flow m_support_material_raft_contact_flow;
bool m_has_raft;
size_t m_num_base_raft_layers;
size_t m_num_interface_raft_layers;
size_t m_num_contact_raft_layers;
// If set, the raft contact layer is laid with round strings, which are easily detachable
// from both the below and above layes.
// Otherwise a normal flow is used and the strings are squashed against the layer below,
// creating a firm bond with the layer below and making the interface top surface flat.
coordf_t m_raft_height;
coordf_t m_raft_base_height;
coordf_t m_raft_interface_height;
coordf_t m_raft_contact_height;
bool m_raft_contact_layer_bridging;
coordf_t m_object_1st_layer_print_z;
coordf_t m_object_1st_layer_height;
coordf_t m_object_1st_layer_gap;
bool m_object_1st_layer_bridging;
coordf_t m_object_layer_height_max;
coordf_t m_support_layer_height_min;
coordf_t m_support_layer_height_max;
coordf_t m_support_interface_layer_height_max;

View file

@ -8,22 +8,12 @@ namespace Slic3r {
SurfaceCollection::operator Polygons() const
{
Polygons polygons;
for (Surfaces::const_iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) {
Polygons surface_p = surface->expolygon;
polygons.insert(polygons.end(), surface_p.begin(), surface_p.end());
}
return polygons;
return to_polygons(surfaces);
}
SurfaceCollection::operator ExPolygons() const
{
ExPolygons expp;
expp.reserve(this->surfaces.size());
for (Surfaces::const_iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) {
expp.push_back(surface->expolygon);
}
return expp;
return to_expolygons(surfaces);
}
void

View file

@ -123,7 +123,7 @@ parallelize(std::queue<T> queue, boost::function<void(T)> func,
if (threads_count == 0) threads_count = 2;
boost::mutex queue_mutex;
boost::thread_group workers;
for (int i = 0; i < fminf(threads_count, queue.size()); i++)
for (int i = 0; i < std::min(threads_count, int(queue.size())); ++ i)
workers.add_thread(new boost::thread(&_parallelize_do<T>, &queue, &queue_mutex, func));
workers.join_all();
}

View file

@ -119,6 +119,7 @@ _constant()
void bridge_over_infill();
void _make_perimeters();
void _infill();
void _generate_support_material();
void adjust_layer_height_profile(coordf_t z, coordf_t layer_thickness_delta, coordf_t band_width, int action)
%code%{

View file

@ -1,26 +0,0 @@
%module{Slic3r::XS};
%{
#include <xsinit.h>
#include "libslic3r/SupportMaterial.hpp"
%}
%name{Slic3r::Print::SupportMaterial2} class PrintObjectSupportMaterial {
PrintObjectSupportMaterial(PrintObject *print_object);
~PrintObjectSupportMaterial();
void generate(PrintObject *object)
%code{% THIS->generate(*object); %};
};
%package{Slic3r::Print::SupportMaterial};
%{
SV*
MARGIN()
PROTOTYPE:
CODE:
RETVAL = newSVnv(SUPPORT_MATERIAL_MARGIN);
OUTPUT: RETVAL
%}