From 955bc957bac5afafca26ead0894c9fdf1e0a3a20 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 20 Dec 2016 12:19:13 +0100 Subject: New supports now do rafts at least to the extent the test cases run through. New supports enabled, old supports will go away soon. --- xs/src/libslic3r/EdgeGrid.cpp | 35 +++- xs/src/libslic3r/EdgeGrid.hpp | 2 +- xs/src/libslic3r/Fill/FillRectilinear2.cpp | 6 +- xs/src/libslic3r/Print.hpp | 1 + xs/src/libslic3r/PrintObject.cpp | 7 + xs/src/libslic3r/Slicing.cpp | 27 ++- xs/src/libslic3r/Slicing.hpp | 18 ++ xs/src/libslic3r/SupportMaterial.cpp | 313 ++++++++++++++--------------- xs/src/libslic3r/SupportMaterial.hpp | 67 ++---- xs/src/libslic3r/SurfaceCollection.cpp | 14 +- xs/src/libslic3r/libslic3r.h | 2 +- 11 files changed, 247 insertions(+), 245 deletions(-) (limited to 'xs/src') diff --git a/xs/src/libslic3r/EdgeGrid.cpp b/xs/src/libslic3r/EdgeGrid.cpp index 4d1432722..b39b12ab8 100644 --- a/xs/src/libslic3r/EdgeGrid.cpp +++ b/xs/src/libslic3r/EdgeGrid.cpp @@ -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 EndPointMapType; + // 0) Prepare a binary grid. + size_t cell_rows = m_rows + 2; + size_t cell_cols = m_cols + 2; + std::vector 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 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 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); } } diff --git a/xs/src/libslic3r/EdgeGrid.hpp b/xs/src/libslic3r/EdgeGrid.hpp index 2473ce423..a0b23211e 100644 --- a/xs/src/libslic3r/EdgeGrid.hpp +++ b/xs/src/libslic3r/EdgeGrid.hpp @@ -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 { diff --git a/xs/src/libslic3r/Fill/FillRectilinear2.cpp b/xs/src/libslic3r/Fill/FillRectilinear2.cpp index 3f7232e06..5122de144 100644 --- a/xs/src/libslic3r/Fill/FillRectilinear2.cpp +++ b/xs/src/libslic3r/Fill/FillRectilinear2.cpp @@ -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; diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index f97f888cd..e8b0e0a03 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -159,6 +159,7 @@ public: void bridge_over_infill(); void _make_perimeters(); void _infill(); + void _generate_support_material(); private: Print* _print; diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index 8d6ddaf21..3c92aad24 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -2,6 +2,7 @@ #include "BoundingBox.hpp" #include "ClipperUtils.hpp" #include "Geometry.hpp" +#include "SupportMaterial.hpp" #include @@ -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 diff --git a/xs/src/libslic3r/Slicing.cpp b/xs/src/libslic3r/Slicing.cpp index 0de781c64..5bd6bfc27 100644 --- a/xs/src/libslic3r/Slicing.cpp +++ b/xs/src/libslic3r/Slicing.cpp @@ -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; } diff --git a/xs/src/libslic3r/Slicing.hpp b/xs/src/libslic3r/Slicing.hpp index 349be2e4a..02ae7dd9e 100644 --- a/xs/src/libslic3r/Slicing.hpp +++ b/xs/src/libslic3r/Slicing.hpp @@ -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; }; diff --git a/xs/src/libslic3r/SupportMaterial.cpp b/xs/src/libslic3r/SupportMaterial.cpp index 8bf9e9fc7..7806e36a5 100644 --- a/xs/src/libslic3r/SupportMaterial.cpp +++ b/xs/src/libslic3r/SupportMaterial.cpp @@ -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 extruders = m_object->print()->object_extruders(); - coordf_t nozzle_dmr = 0; - for (std::set::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); + 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)); + } + 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; } - } 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); + // 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; + } } - #endif - return raft_polygons; + + 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 filler_interface = std::unique_ptr(Fill::new_from_type(ipRectilinear)); std::unique_ptr filler_support = std::unique_ptr(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) ? diff --git a/xs/src/libslic3r/SupportMaterial.hpp b/xs/src/libslic3r/SupportMaterial.hpp index abcaf676a..c9cbee488 100644 --- a/xs/src/libslic3r/SupportMaterial.hpp +++ b/xs/src/libslic3r/SupportMaterial.hpp @@ -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 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 &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; - - 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_material_interface_spacing; + coordf_t m_support_layer_height_min; coordf_t m_support_layer_height_max; coordf_t m_support_interface_layer_height_max; diff --git a/xs/src/libslic3r/SurfaceCollection.cpp b/xs/src/libslic3r/SurfaceCollection.cpp index cfeae4ccc..70272fede 100644 --- a/xs/src/libslic3r/SurfaceCollection.cpp +++ b/xs/src/libslic3r/SurfaceCollection.cpp @@ -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 diff --git a/xs/src/libslic3r/libslic3r.h b/xs/src/libslic3r/libslic3r.h index 89db6d81e..d2a3c7c86 100644 --- a/xs/src/libslic3r/libslic3r.h +++ b/xs/src/libslic3r/libslic3r.h @@ -123,7 +123,7 @@ parallelize(std::queue queue, boost::function 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, &queue, &queue_mutex, func)); workers.join_all(); } -- cgit v1.2.3