Some fixes to SupportMaterial memver functions.

This commit is contained in:
Samir55 2018-07-14 23:09:22 +02:00
parent 93b0cd436a
commit 4931e4025e
5 changed files with 298 additions and 175 deletions

View File

@ -1,5 +1,6 @@
#include <catch.hpp>
//#include "/home/ahmedsamir/Work/SamirSlic3r/Slic3r/build/external/Catch/include/catch.hpp"
//#include <catch.hpp>
#include <libslic3r/IO.hpp>
#include "/home/ahmedsamir/Work/SamirSlic3r/Slic3r/build/external/Catch/include/catch.hpp"
#include "libslic3r.h"
#include "TriangleMesh.hpp"
@ -9,6 +10,38 @@
using namespace std;
using namespace Slic3r;
// Testing supports material member functions.
TEST_CASE("", "")
{
// Create a mesh & modelObject.
TriangleMesh mesh = TriangleMesh::make_cube(20, 20, 20);
// Create modelObject.
Model model = Model();
ModelObject *object = model.add_object();
object->add_volume(mesh);
model.add_default_instances();
// Align to origin.
model.align_instances_to_origin();
// Create Print.
Print print = Print();
vector<coordf_t> contact_z = {1.9};
vector<coordf_t> top_z = {1.1};
print.default_object_config.support_material = 1;
print.default_object_config.set_deserialize("raft_layers", "3");
print.add_model_object(model.objects[0]);
print.objects.front()->_slice();
SupportMaterial *support = print.objects.front()->_support_material();
support->generate(print.objects.front());
REQUIRE(print.objects.front()->support_layer_count() == 3);
}
SCENARIO("SupportMaterial: support_layers_z and contact_distance")
{
GIVEN("A print object having one modelObject") {
@ -39,10 +72,10 @@ SCENARIO("SupportMaterial: support_layers_z and contact_distance")
print.add_model_object(model.objects[0]);
print.objects.front()->_slice();
SupportMaterial support = SupportMaterial(&print.config, &print.objects.front()->config);
SupportMaterial *support = print.objects.front()->_support_material();
vector<coordf_t>
support_z = support.support_layers_z(contact_z, top_z, print.default_object_config.layer_height.value);
support_z = support->support_layers_z(contact_z, top_z, print.default_object_config.layer_height.value);
THEN("First layer height is honored") {
REQUIRE((support_z[0] == print.default_object_config.first_layer_height.value));
@ -52,7 +85,7 @@ SCENARIO("SupportMaterial: support_layers_z and contact_distance")
bool check = true;
for (size_t i = 1; i < support_z.size(); ++i)
if (support_z[i] - support_z[i - 1] <= 0) check = false;
REQUIRE(check);
REQUIRE(check == true);
}
THEN("No layers thicker than nozzle diameter") {
@ -60,18 +93,19 @@ SCENARIO("SupportMaterial: support_layers_z and contact_distance")
for (size_t i = 1; i < support_z.size(); ++i)
if (support_z[i] - support_z[i - 1] > print.config.nozzle_diameter.get_at(0) + EPSILON)
check = false;
REQUIRE(check);
REQUIRE(check == true);
}
THEN("Layers above top surfaces are spaced correctly") {
coordf_t expected_top_spacing = support
.contact_distance(print.default_object_config.layer_height, print.config.nozzle_diameter.get_at(0));
->contact_distance(print.default_object_config.layer_height,
print.config.nozzle_diameter.get_at(0));
bool wrong_top_spacing = 0;
for (coordf_t top_z_el : top_z) {
// find layer index of this top surface.
int layer_id = -1;
for (int i = 0; i < support_z.size(); i++) {
size_t layer_id = -1;
for (size_t i = 0; i < support_z.size(); i++) {
if (abs(support_z[i] - top_z_el) < EPSILON) {
layer_id = i;
i = static_cast<int>(support_z.size());

View File

@ -15,6 +15,7 @@
#include "PlaceholderParser.hpp"
#include "SlicingAdaptive.hpp"
#include "LayerHeightSpline.hpp"
#include "SupportMaterial.hpp"
#include <exception>
@ -25,6 +26,7 @@ class InvalidObjectException : public std::exception {};
class Print;
class PrintObject;
class ModelObject;
class SupportMaterial;
// Print step IDs for keeping track of the print state.
enum PrintStep {
@ -132,6 +134,8 @@ class PrintObject
Layer* add_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z);
void delete_layer(int idx);
SupportMaterial* _support_material();
Flow _support_material_flow(FlowRole role = frSupportMaterial);
size_t support_layer_count() const;
void clear_support_layers();
SupportLayer* get_support_layer(int idx) { return this->support_layers.at(idx); };

View File

@ -1095,4 +1095,55 @@ PrintObject::_infill()
this->state.set_done(posInfill);
}
SupportMaterial *
PrintObject::_support_material()
{
// TODO what does this line do //= FLOW_ROLE_SUPPORT_MATERIAL;
Flow first_layer_flow = Flow::new_from_config_width(
frSupportMaterial,
print()->config
.first_layer_extrusion_width, // check why this line is put || config.support_material_extrusion_width,
static_cast<float>(print()->config.nozzle_diameter.get_at(static_cast<size_t>(
config.support_material_extruder
- 1))), // Check why this is put in perl "// $self->print->config->nozzle_diameter->[0]"
static_cast<float>(config.get_abs_value("first_layer_height")),
0 // No bridge flow ratio.
);
return new SupportMaterial(
&print()->config,
&config,
first_layer_flow,
_support_material_flow(),
_support_material_flow(frSupportMaterialInterface)
);
}
Flow
PrintObject::_support_material_flow(FlowRole role)
{
// Create support flow.
int extruder =
(role == frSupportMaterial) ?
config.support_material_extruder.value : config
.support_material_interface_extruder.value;
auto width = config.support_material_extrusion_width; // || config.extrusion_width;
if (role == frSupportMaterialInterface)
width = config.support_material_interface_extrusion_width; // || width;
// We use a bogus layer_height because we use the same flow for all
// support material layers.
Flow support_flow = Flow::new_from_config_width(
role,
width,
static_cast<float>(print()->config.nozzle_diameter
.get_at(static_cast<size_t>(extruder - 1))), // Check this line $self->print->config->nozzle_diameter->[0].
static_cast<float>(config.layer_height.value),
0
);
return support_flow;
}
}

View File

@ -17,16 +17,24 @@ SupportMaterial::generate_toolpaths(PrintObject *object,
map<int, Polygons> interface,
map<int, Polygons> base)
{
int ll = 0;
//cout << "Generate toolpaths " << ll++ << endl;
// Assig the object to the supports class.
this->object = object;
// Shape of contact area.
toolpaths_params params;
params.contact_loops = 1;
params.circle_radius = 1.5 * interface_flow->scaled_width();
params.circle_distance = 3 * params.circle_radius;
params.circle = create_circle(params.circle_radius);
//cout << "Generate toolpaths " << ll++ << endl;
params.circle_radius = 1.5 * interface_flow.scaled_width();
//cout << "Generate toolpaths " << ll++ << endl;
params.circle_distance = 3 * params.circle_radius;
//cout << "Generate toolpaths " << ll++ << endl;
params.circle = create_circle(params.circle_radius);
//cout << "Generate toolpaths " << ll++ << endl;
// TODO Add Slic3r debug. "Generating patterns\n"
// Prepare fillers.
params.pattern = object_config->support_material_pattern.value;
@ -39,12 +47,13 @@ SupportMaterial::generate_toolpaths(PrintObject *object,
else if (params.pattern == smpPillars) {
params.pattern = smpHoneycomb;
}
//cout << "Generate toolpaths " << ll++ << endl;
params.interface_angle = object_config->support_material_angle.value + 90;
params.interface_spacing = object_config->support_material_interface_spacing.value + interface_flow->spacing();
params.interface_density = params.interface_spacing == 0 ? 1 : interface_flow->spacing() / params.interface_spacing;
params.support_spacing = object_config->support_material_spacing.value + flow->spacing();
params.support_density = params.support_spacing == 0 ? 1 : flow->spacing() / params.support_spacing;
params.interface_spacing = object_config->support_material_interface_spacing.value + interface_flow.spacing();
params.interface_density =
static_cast<float>(params.interface_spacing == 0 ? 1 : interface_flow.spacing() / params.interface_spacing);
params.support_spacing = object_config->support_material_spacing.value + flow.spacing();
params.support_density = params.support_spacing == 0 ? 1 : flow.spacing() / params.support_spacing;
parallelize<size_t>(
0,
@ -52,6 +61,7 @@ SupportMaterial::generate_toolpaths(PrintObject *object,
boost::bind(&SupportMaterial::process_layer, this, _1, params),
this->config->threads.value
);
//cout << "Generate toolpaths finished" << ll++ << endl;
}
void
@ -64,39 +74,50 @@ SupportMaterial::generate(PrintObject *object)
// that it will be effective, regardless of how it's built below.
pair<map<coordf_t, Polygons>, map<coordf_t, Polygons>> contact_overhang = contact_area(object);
map<coordf_t, Polygons> &contact = contact_overhang.first;
cout << "Contact size " << contact.size() << endl;
map<coordf_t, Polygons> &overhang = contact_overhang.second;
int ppp = 0;
cout << "Samir " << ppp++ << endl;
// Determine the top surfaces of the object. We need these to determine
// the layer heights of support material and to clip support to the object
// silhouette.
map<coordf_t, Polygons> top = object_top(object, &contact);
cout << "Samir " << ppp++ << endl;
// We now know the upper and lower boundaries for our support material object
// (@$contact_z and @$top_z), so we can generate intermediate layers.
vector<coordf_t> support_z = support_layers_z(get_keys_sorted(contact),
get_keys_sorted(top),
get_max_layer_height(object));
cout << "Samir " << ppp++ << endl;
// If we wanted to apply some special logic to the first support layers lying on
// object's top surfaces this is the place to detect them. TODO
// object's top surfaces this is the place to detect them.
map<int, Polygons> shape;
if (object_config->support_material_pattern.value == smpPillars)
this->generate_pillars_shape(contact, support_z, shape);
cout << "Samir " << ppp++ << endl;
// Propagate contact layers downwards to generate interface layers.
map<int, Polygons> interface = generate_interface_layers(support_z, contact, top);
clip_with_object(interface, support_z, *object);
// clip_with_shape(base, shape); // TODO
if (!shape.empty())
clip_with_shape(interface, shape);
cout << "Samir " << ppp++ << endl;
// Propagate contact layers and interface layers downwards to generate
// the main support layers. TODO
// the main support layers.
map<int, Polygons> base = generate_base_layers(support_z, contact, interface, top);
clip_with_object(base, support_z, *object);
if (!shape.empty())
clip_with_shape(base, shape);
cout << "Samir " << ppp++ << endl;
// Detect what part of base support layers are "reverse interfaces" because they
// lie above object's top surfaces. TODO
// lie above object's top surfaces.
generate_bottom_interface_layers(support_z, base, top, interface);
cout << "Samir " << ppp++ << endl;
// Install support layers into object.
for (int i = 0; i < support_z.size(); i++) {
for (int i = 0; i < int(support_z.size()); i++) {
object->add_support_layer(
i, // id.
(i == 0) ? support_z[0] - 0 : (support_z[i] - support_z[i - 1]), // height.
@ -108,10 +129,11 @@ SupportMaterial::generate(PrintObject *object)
object->support_layers.end()[-1]->lower_layer = object->support_layers.end()[-2];
}
}
cout << "Supports z count is " << support_z.size() << endl;
cout << "Samir " << ppp++ << endl;
// Generate the actual toolpaths and save them into each layer.
generate_toolpaths(object, overhang, contact, interface, base);
cout << "Samir " << ppp++ << endl;
}
vector<coordf_t>
@ -126,7 +148,8 @@ SupportMaterial::support_layers_z(vector<coordf_t> contact_z,
// determine layer height for any non-contact layer
// we use max() to prevent many ultra-thin layers to be inserted in case
// layer_height > nozzle_diameter * 0.75.
auto nozzle_diameter = config->nozzle_diameter.get_at(object_config->support_material_extruder - 1);
auto nozzle_diameter = config->nozzle_diameter.get_at(static_cast<size_t>(
object_config->support_material_extruder - 1));
auto support_material_height = (max_object_layer_height, (nozzle_diameter * 0.75));
coordf_t _contact_distance = this->contact_distance(support_material_height, nozzle_diameter);
@ -191,15 +214,21 @@ SupportMaterial::support_layers_z(vector<coordf_t> contact_z,
pair<map<coordf_t, Polygons>, map<coordf_t, Polygons>>
SupportMaterial::contact_area(PrintObject *object)
{
PrintObjectConfig conf = this->object_config;
//cout << "After " << this->object_config->support_material.value << " ," << (this->object_config->support_material ? " Support Material is enabled" : "Support Material is disabled") << endl;
PrintObjectConfig &conf = *this->object_config;
//cout << conf.support_material.value << " " << (conf.support_material.value ? " Support Material is enabled" : "Support Material is disabled") << endl;
// If user specified a custom angle threshold, convert it to radians.
float threshold_rad;
cout << conf.support_material_threshold << endl;
if (conf.support_material_threshold > 0) {
float threshold_rad = 0.0;
if (!conf.support_material_threshold.percent) {
threshold_rad = static_cast<float>(Geometry::deg2rad(
conf.support_material_threshold.value + 1)); // +1 makes the threshold inclusive
// TODO @Samir55 add debug statetments.
conf.support_material_threshold + 1)); // +1 makes the threshold inclusive
#ifdef SLIC3R_DEBUG
printf("Threshold angle = %d°\n", static_cast<int>(Geometry::rad2deg(threshold_rad)));
#endif
}
// Build support on a build plate only? If so, then collect top surfaces into $buildplate_only_top_surfaces
@ -211,18 +240,19 @@ SupportMaterial::contact_area(PrintObject *object)
Polygons buildplate_only_top_surfaces;
// Determine contact areas.
map<coordf_t, Polygons> contact;
map<coordf_t, Polygons> contact; // contact_z => [ polygons ].
map<coordf_t, Polygons> overhang; // This stores the actual overhang supported by each contact layer
for (int layer_id = 0; layer_id < object->layers.size(); layer_id++) {
// Note $layer_id might != $layer->id when raft_layers > 0
// so $layer_id == 0 means first object layer
// and $layer->id == 0 means first print layer (including raft).
// If no raft, and we're at layer 0, skip to layer 1
if (conf.raft_layers == 0 && layer_id == 0)
cout << "LAYER ID " << layer_id << endl;
if (conf.raft_layers == 0 && layer_id == 0) {
continue;
}
//cout << conf.support_material.value << " " << (conf.support_material.value ? " Support Material is enabled" : "Support Material is disabled") << endl;
// With or without raft, if we're above layer 1, we need to quit
// support generation if supports are disabled, or if we're at a high
// enough layer that enforce-supports no longer applies.
@ -244,45 +274,44 @@ SupportMaterial::contact_area(PrintObject *object)
Polygons projection_new;
for (auto const &region : layer->regions) {
SurfacesPtr top_surfaces = region->slices.filter_by_type(stTop);
for (auto polygon : p(top_surfaces)) {
for (const auto &polygon : p(top_surfaces)) {
projection_new.push_back(polygon);
}
}
if (!projection_new.empty()) {
// Merge the new top surfaces with the preceding top surfaces.
// Merge the new top surfaces with the preceding top surfaces. TODO @Ask about this line.
// Apply the safety offset to the newly added polygons, so they will connect
// with the polygons collected before,
// but don't apply the safety offset during the union operation as it would
// inflate the polygons over and over.
Polygons polygons = offset(projection_new, scale_(0.01));
append_polygons(buildplate_only_top_surfaces, polygons);
//cout << "Old Build plate only surfaces " << buildplate_only_top_surfaces.size() << endl;
append_to(buildplate_only_top_surfaces, offset(projection_new, scale_(0.01)));
//cout << "New Build plate only surfaces " << buildplate_only_top_surfaces.size() << endl;
buildplate_only_top_surfaces = union_(buildplate_only_top_surfaces, 0);
}
}
// Detect overhangs and contact areas needed to support them.
Polygons m_overhang, m_contact;
Polygons tmp_overhang, tmp_contact;
if (layer_id == 0) {
// this is the first object layer, so we're here just to get the object
// footprint for the raft.
// we only consider contours and discard holes to get a more continuous raft.
for (auto const &contour : layer->slices.contours()) {
auto contour_clone = contour;
m_overhang.push_back(contour_clone);
}
for (auto const &contour : layer->slices.contours())
tmp_overhang.push_back(contour);
Polygons polygons = offset(m_overhang, scale_(+SUPPORT_MATERIAL_MARGIN));
append_polygons(m_contact, polygons);
Polygons polygons = offset(tmp_overhang, scale_(+SUPPORT_MATERIAL_MARGIN));
append_to(tmp_contact, polygons);
}
else {
Layer *lower_layer = object->get_layer(layer_id - 1);
for (auto layerm : layer->regions) {
auto fw = layerm->flow(frExternalPerimeter).scaled_width();
for (auto layer_m : layer->regions) {
auto fw = layer_m->flow(frExternalPerimeter).scaled_width();
Polygons difference;
// If a threshold angle was specified, use a different logic for detecting overhangs.
if ((conf.support_material && threshold_rad > 0)
if ((conf.support_material && threshold_rad != 0.0)
|| layer_id <= conf.support_material_enforce_layers
|| (conf.raft_layers > 0 && layer_id
== 0)) { // TODO ASK @Samir why layer_id ==0 check , layer_id will never equal to zero
@ -294,12 +323,11 @@ SupportMaterial::contact_area(PrintObject *object)
}
if (layer_threshold_rad > 0) {
d = scale_(lower_layer->height
* ((cos(layer_threshold_rad)) / (sin(layer_threshold_rad))));
* (cos(layer_threshold_rad) / sin(layer_threshold_rad)));
}
// TODO Check.
difference = diff(
Polygons(layerm->slices),
Polygons(layer_m->slices),
offset(lower_layer->slices, +d)
);
@ -307,15 +335,15 @@ SupportMaterial::contact_area(PrintObject *object)
// is not too high: in that case, $d will be very small (as we need to catch
// very short overhangs), and such contact area would be eaten by the
// enforced spacing, resulting in high threshold angles to be almost ignored
if (d > fw / 2) {
if (d > fw / 2)
difference = diff(
offset(difference, d - fw / 2),
lower_layer->slices);
}
}
else {
difference = diff(
Polygons(layerm->slices),
Polygons(layer_m->slices),
offset(lower_layer->slices,
static_cast<const float>(+conf.get_abs_value("support_material_threshold", fw)))
);
@ -332,7 +360,7 @@ SupportMaterial::contact_area(PrintObject *object)
// Compute the area of bridging perimeters.
Polygons bridged_perimeters;
{
auto bridge_flow = layerm->flow(FlowRole::frPerimeter, 1);
auto bridge_flow = layer_m->flow(FlowRole::frPerimeter, 1);
// Get the lower layer's slices and grow them by half the nozzle diameter
// because we will consider the upper perimeters supported even if half nozzle
@ -340,7 +368,7 @@ SupportMaterial::contact_area(PrintObject *object)
Polygons lower_grown_slices;
{
coordf_t nozzle_diameter = this->config->nozzle_diameter
.get_at(static_cast<size_t>(layerm->region()->config.perimeter_extruder - 1));
.get_at(static_cast<size_t>(layer_m->region()->config.perimeter_extruder - 1));
lower_grown_slices = offset(
lower_layer->slices,
@ -348,26 +376,29 @@ SupportMaterial::contact_area(PrintObject *object)
);
}
// TODO Revise Here.
// Get all perimeters as polylines.
// TODO: split_at_first_point() (called by as_polyline() for ExtrusionLoops)
// could split a bridge mid-way.
Polylines overhang_perimeters;
overhang_perimeters.push_back(layerm->perimeters.flatten().as_polyline());
for (auto extr_path : ExtrusionPaths(layer_m->perimeters.flatten())) {
overhang_perimeters.push_back(extr_path.as_polyline());
}
// Only consider the overhang parts of such perimeters,
// overhangs being those parts not supported by
// workaround for Clipper bug, see Slic3r::Polygon::clip_as_polyline()
overhang_perimeters[0].translate(1, 0);
for (auto &overhang_perimeter : overhang_perimeters)
overhang_perimeter.translate(1, 0);
overhang_perimeters = diff_pl(overhang_perimeters, lower_grown_slices);
// Only consider straight overhangs.
Polylines new_overhangs_perimeters_polylines;
for (auto p : overhang_perimeters)
for (const auto &p : overhang_perimeters)
if (p.is_straight())
new_overhangs_perimeters_polylines.push_back(p);
overhang_perimeters = new_overhangs_perimeters_polylines;
new_overhangs_perimeters_polylines = Polylines();
// Only consider overhangs having endpoints inside layer's slices
for (auto &p : overhang_perimeters) {
@ -375,7 +406,8 @@ SupportMaterial::contact_area(PrintObject *object)
p.extend_end(fw);
}
for (auto p : overhang_perimeters) {
new_overhangs_perimeters_polylines = Polylines();
for (const auto &p : overhang_perimeters) {
if (layer->slices.contains_b(p.first_point())
&& layer->slices.contains_b(p.last_point())) {
new_overhangs_perimeters_polylines.push_back(p);
@ -392,56 +424,45 @@ SupportMaterial::contact_area(PrintObject *object)
coord_t widths[] = {bridge_flow.scaled_width(),
bridge_flow.scaled_spacing(),
fw,
layerm->flow(FlowRole::frPerimeter).scaled_width()};
layer_m->flow(FlowRole::frPerimeter).scaled_width()};
auto w = *max_element(widths, widths + 4);
// Also apply safety offset to ensure no gaps are left in between.
// TODO CHeck this.
for (auto &p : overhang_perimeters) {
Polygons ps = union_(offset(p, w / 2 + 10));
for (auto ps_el : ps)
bridged_perimeters.push_back(ps_el);
}
Polygons ps = offset(overhang_perimeters, w / 2 + 10);
bridged_perimeters = union_(ps);
}
}
if (1) {
// Remove the entire bridges and only support the unsupported edges.
ExPolygons bridges;
for (auto surface : layerm->fill_surfaces.filter_by_type(stBottomBridge)) {
for (auto surface : layer_m->fill_surfaces.filter_by_type(stBottomBridge)) {
if (surface->bridge_angle != -1) {
bridges.push_back(surface->expolygon);
}
}
ExPolygons ps;
for (auto p : bridged_perimeters)
ps.push_back(ExPolygon(p));
for (auto p : bridges)
ps.push_back(p);
Polygons ps = to_polygons(bridges);
append_to(ps, bridged_perimeters);
// TODO ASK about this.
difference = diff(
difference = diff( // TODO ASK about expolygons and polygons miss match.
difference,
to_polygons(ps),
ps,
true
);
// TODO Ask about this.
auto p_intersections = intersection(offset(layerm->unsupported_bridge_edges.polylines,
+scale_(SUPPORT_MATERIAL_MARGIN)),
to_polygons(bridges));
for (auto p: p_intersections) {
difference.push_back(p);
}
append_to(difference,
intersection(
offset(layer_m->unsupported_bridge_edges.polylines,
+scale_(SUPPORT_MATERIAL_MARGIN)), to_polygons(bridges)));
}
else {
// just remove bridged areas.
difference = diff(
difference,
layerm->bridged,
1
layer_m->bridged,
true
);
}
} // if ($conf->dont_support_bridges)
@ -455,7 +476,7 @@ SupportMaterial::contact_area(PrintObject *object)
if (difference.empty()) continue;
// NOTE: this is not the full overhang as it misses the outermost half of the perimeter width!
append_polygons(m_overhang, difference);
append_polygons(tmp_overhang, difference);
// Let's define the required contact area by using a max gap of half the upper
// extrusion width and extending the area according to the configured margin.
@ -466,25 +487,24 @@ SupportMaterial::contact_area(PrintObject *object)
if (buildplate_only) {
// Trim the inflated contact surfaces by the top surfaces as well.
append_polygons(slices_margin, buildplate_only_top_surfaces);
append_to(slices_margin, buildplate_only_top_surfaces);
slices_margin = union_(slices_margin);
}
// TODO Ask how to port this.
/*
for ($fw/2, map {scale MARGIN_STEP} 1..(MARGIN / MARGIN_STEP)) {
$diff = diff(
offset($diff, $_),
$slices_margin,
vector<coord_t> scale_vector
(static_cast<unsigned long>(SUPPORT_MATERIAL_MARGIN / MARGIN_STEP), scale_(MARGIN_STEP));
scale_vector.push_back(fw / 2);
for (int i = static_cast<int>(scale_vector.size()) - 1; i >= 0; i--) {
difference = diff(
offset(difference, i),
slices_margin
);
}
*/
}
}
append_polygons(m_contact, difference);
append_polygons(tmp_contact, difference);
}
}
if (contact.empty())
if (tmp_contact.empty())
continue;
// Now apply the contact areas to the layer were they need to be made.
@ -503,7 +523,7 @@ SupportMaterial::contact_area(PrintObject *object)
.solid_infill_extruder - 1)));
}
int nozzle_diameters_count = static_cast<int>(nozzle_diameters.size() > 0 ? nozzle_diameters.size() : 1);
int nozzle_diameters_count = static_cast<int>(!nozzle_diameters.empty() ? nozzle_diameters.size() : 1);
auto nozzle_diameter =
accumulate(nozzle_diameters.begin(), nozzle_diameters.end(), 0.0) / nozzle_diameters_count;
@ -512,10 +532,10 @@ SupportMaterial::contact_area(PrintObject *object)
// Ignore this contact area if it's too low.
if (contact_z < conf.first_layer_height - EPSILON)
continue;
//cout << contact_z << " " << tmp_contact.size() << endl;
contact[contact_z] = m_contact;
overhang[contact_z] = m_overhang;
contact[contact_z] = tmp_contact;
overhang[contact_z] = tmp_overhang;
}
}
@ -532,46 +552,42 @@ SupportMaterial::object_top(PrintObject *object, map<coordf_t, Polygons> *contac
return top;
Polygons projection;
for (auto i = static_cast<int>(object->layers.size() - 1); i >= 0; i--) {
for (auto i = static_cast<int>(object->layers.size()) - 1; i >= 0; i--) {
Layer *layer = object->layers[i];
SurfacesPtr m_top;
for (auto r : layer->regions)
for (auto s : r->slices.filter_by_type(stTop))
m_top.push_back(s);
append_to(m_top, r->slices.filter_by_type(stTop));
if (!m_top.empty()) {
// compute projection of the contact areas above this top layer
// first add all the 'new' contact areas to the current projection
// ('new' means all the areas that are lower than the last top layer
// we considered).
// TODO Ask about this line
/*
my $min_top = min(keys %top) // max(keys %$contact);
*/
double min_top = top.begin()->first;
if (m_top.empty()) continue;
// Use <= instead of just < because otherwise we'd ignore any contact regions
// having the same Z of top layers.
for (auto el : *contact)
if (el.first > layer->print_z && el.first <= min_top)
for (const auto &p : el.second)
projection.push_back(p);
// compute projection of the contact areas above this top layer
// first add all the 'new' contact areas to the current projection
// ('new' means all the areas that are lower than the last top layer
// we considered).
double min_top = (!top.empty() ? top.begin()->first : contact->rbegin()->first);
// Now find whether any projection falls onto this top surface.
Polygons touching = intersection(projection, p(m_top));
if (!touching.empty()) {
// 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.
top[layer->print_z] = offset(touching, flow->scaled_width());
}
// Use <= instead of just < because otherwise we'd ignore any contact regions
// having the same Z of top layers.
for (auto el : *contact)
if (el.first > layer->print_z && el.first <= min_top)
for (const auto &p : el.second)
projection.push_back(p);
// Remove the areas that touched from the projection that will continue on
// next, lower, top surfaces.
projection = diff(projection, touching);
// Now find whether any projection falls onto this top surface.
Polygons touching = intersection(projection, p(m_top));
if (!touching.empty()) {
// 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.
top[layer->print_z] = offset(touching, flow.scaled_width());
}
// Remove the areas that touched from the projection that will continue on
// next, lower, top surfaces.
projection = diff(projection, touching);
}
return top;
}
@ -584,9 +600,13 @@ SupportMaterial::generate_pillars_shape(const map<coordf_t, Polygons> &contact,
// This prevents supplying an empty point set to BoundingBox constructor.
if (contact.empty()) return;
int u = 0;
cout << "Pillars generation " << contact.size() << endl;
coord_t pillar_size = scale_(object_config->support_material_pillar_size.value);
coord_t pillar_spacing = scale_(object_config->support_material_pillar_spacing.value);
cout << "Samir U " << u++ << endl;
Polygons grid;
{
auto pillar = Polygon({
@ -615,21 +635,28 @@ SupportMaterial::generate_pillars_shape(const map<coordf_t, Polygons> &contact,
grid = union_(pillars);
}
cout << "Samir U " << u++ << endl; //1
cout << "Support z size " << support_z.size() << endl;
// Add pillars to every layer.
for (auto i = 0; i < support_z.size(); i++) {
shape[i] = grid;
}
cout << "Samir U " << u++ << endl;
// Build capitals.
cout << "contacts START " << endl;
for (auto el : contact) {
cout << el.first << endl;
}
cout << "contacts END" << endl;
for (auto i = 0; i < support_z.size(); i++) {
coordf_t z = support_z[i];
cout << z << endl;
auto capitals = intersection(
grid,
contact.at(z)
contact.count(z) > 0 ? contact.at(z) : Polygons()
);
cout << "Samir U " << u++ << endl;
// Work on one pillar at time (if any) to prevent the capitals from being merged
// but store the contact area supported by the capital because we need to make
// sure nothing is left.
@ -641,17 +668,17 @@ SupportMaterial::generate_pillars_shape(const map<coordf_t, Polygons> &contact,
for (int j = i - 1; j >= 0; j--) {
auto jz = support_z[j];
capital_polygons = offset(Polygons{capital}, -interface_flow->scaled_width() / 2);
capital_polygons = offset(Polygons{capital}, -interface_flow.scaled_width() / 2);
if (capitals.empty()) break;
append_to(shape[i], capital_polygons);
}
}
cout << "Samir U " << u++ << endl;
// Work on one pillar at time (if any) to prevent the capitals from being merged
// but store the contact area supported by the capital because we need to make
// sure nothing is left.
auto contact_not_supported_by_capitals = diff(
contact.at(z),
contact.count(z) > 0 ? contact.at(z) : Polygons(),
contact_supported_by_capitals
);
@ -661,6 +688,7 @@ SupportMaterial::generate_pillars_shape(const map<coordf_t, Polygons> &contact,
}
}
}
cout << "Samir U " << u++ << endl;
}
map<int, Polygons>
@ -672,7 +700,7 @@ SupportMaterial::generate_base_layers(vector<coordf_t> support_z,
// Let's now generate support layers under interface layers.
map<int, Polygons> base;
{
for (int i = static_cast<int>(support_z.size() - 1); i >= 0; i--) {
for (auto i = static_cast<int>(support_z.size()) - 1; i >= 0; i--) {
auto z = support_z[i];
auto overlapping_layers = this->overlapping_layers(i, support_z);
vector<coordf_t> overlapping_z;
@ -683,7 +711,7 @@ SupportMaterial::generate_base_layers(vector<coordf_t> support_z,
// (1 interface layer means we only have contact layer, so $interface->{$i+1} is empty).
Polygons upper_contact;
if (object_config->support_material_interface_layers.value <= 1) {
append_polygons(upper_contact, contact[support_z[i + 1]]);
append_polygons(upper_contact, (i + 1 < support_z.size() ? contact[support_z[i + 1]] : contact[-1]));
}
Polygons ps_1;
@ -723,6 +751,7 @@ SupportMaterial::generate_interface_layers(vector<coordf_t> support_z,
for (int layer_id = 0; layer_id < support_z.size(); layer_id++) {
// Todo Ask about how to port this line. "my $this = $contact->{$z} // next;"
auto z = support_z[layer_id];
if (contact.count(z) <= 0)
continue;
Polygons &_contact = contact[z];
@ -773,7 +802,7 @@ SupportMaterial::generate_bottom_interface_layers(const vector<coordf_t> &suppor
if (object_config->support_material_interface_layers.value == 0)
return;
auto area_threshold = interface_flow->scaled_spacing() * interface_flow->scaled_spacing();
auto area_threshold = interface_flow.scaled_spacing() * interface_flow.scaled_spacing();
// Loop through object's top surfaces. TODO CHeck if the keys are sorted.
for (auto &top_el : top) {
@ -895,12 +924,12 @@ SupportMaterial::clip_with_object(map<int, Polygons> &support, vector<coordf_t>
slices.push_back(s);
}
}
support_layer.second = diff(support_layer.second, offset(slices, flow->scaled_width()));
support_layer.second = diff(support_layer.second, offset(slices, flow.scaled_width()));
}
/*
$support->{$i} = diff(
$support->{$i},
offset([ map @$_, map @{$_->slices}, @layers ], +$self->flow->scaled_width),
offset([ map @$_, map @{$_->slices}, @layers ], +$self->flow.scaled_width),
);
*/
}
@ -912,8 +941,8 @@ SupportMaterial::process_layer(int layer_id, toolpaths_params params)
coordf_t z = layer->print_z;
// We redefine flows locally by applyinh this layer's height.
auto _flow = *flow;
auto _interface_flow = *interface_flow;
Flow _flow = flow;
Flow _interface_flow = interface_flow;
_flow.height = static_cast<float>(layer->height);
_interface_flow.height = static_cast<float>(layer->height);
@ -1104,9 +1133,9 @@ SupportMaterial::process_layer(int layer_id, toolpaths_params params)
Fill *filler = fillers["support"];
filler->angle = static_cast<float>(Geometry::deg2rad(params.angles[layer_id % int(params.angles.size())]));
// We don't use $base_flow->spacing because we need a constant spacing
// We don't use $base_flow.spacing because we need a constant spacing
// value that guarantees that all layers are correctly aligned.
filler->min_spacing = flow->spacing();
filler->min_spacing = flow.spacing();
auto density = params.support_density;
Flow *base_flow = &_flow;
@ -1122,7 +1151,7 @@ SupportMaterial::process_layer(int layer_id, toolpaths_params params)
filler = fillers["interface"];
filler->angle = static_cast<float>(Geometry::deg2rad(object_config->support_material_angle.value + 90));
density = 0.5;
base_flow = first_layer_flow;
base_flow = &first_layer_flow;
// Use the proper spacing for first layer as we don't need to align
// its pattern to the other layers.

View File

@ -24,6 +24,8 @@ namespace Slic3r
// how much we extend support around the actual contact area
constexpr coordf_t SUPPORT_MATERIAL_MARGIN = 1.5;
constexpr coordf_t MARGIN_STEP = SUPPORT_MATERIAL_MARGIN / 3;
constexpr coordf_t PILLAR_SIZE = 2.5;
constexpr coordf_t PILLAR_SPACING = 10;
@ -61,24 +63,13 @@ struct toolpaths_params
class SupportMaterial
{
public:
friend PrintObject;
PrintConfig *config; ///< The print config
PrintObjectConfig *object_config; ///< The object print config.
Flow *flow; ///< The intermediate layers print flow.
Flow *first_layer_flow; ///< The first (base) layers print flow.
Flow *interface_flow; ///< The interface layers print flow.
SupportMaterial(PrintConfig *print_config,
PrintObjectConfig *print_object_config,
Flow *flow = nullptr,
Flow *first_layer_flow = nullptr,
Flow *interface_flow = nullptr)
: config(print_config),
object_config(print_object_config),
flow(flow),
first_layer_flow(first_layer_flow),
interface_flow(interface_flow),
object(nullptr)
{}
Flow flow; ///< The intermediate layers print flow.
Flow first_layer_flow; ///< The first (base) layers print flow.
Flow interface_flow; ///< The interface layers print flow.
/// Generate the extrusions paths for the support matterial generated for the given print object.
void generate_toolpaths(PrintObject *object,
@ -97,7 +88,7 @@ public:
pair<map<coordf_t, Polygons>, map<coordf_t, Polygons>> contact_area(PrintObject *object);
// Is this expolygons or polygons?
// TODO Is this expolygons or polygons?
map<coordf_t, Polygons> object_top(PrintObject *object, map<coordf_t, Polygons> *contact);
void generate_pillars_shape(const map<coordf_t, Polygons> &contact,
@ -133,6 +124,20 @@ public:
void process_layer(int layer_id, toolpaths_params params);
private:
/// SupportMaterial is generated by PrintObject.
SupportMaterial(PrintConfig *print_config,
PrintObjectConfig *print_object_config,
Flow flow,
Flow first_layer_flow,
Flow interface_flow)
: config(print_config),
object_config(print_object_config),
flow(Flow(0, 0, 0)),
first_layer_flow(Flow(0, 0, 0)),
interface_flow(Flow(0, 0, 0)),
object(nullptr)
{}
// Get the maximum layer height given a print object.
coordf_t get_max_layer_height(PrintObject *object);