mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-07-31 12:12:09 +08:00
Some fixes to SupportMaterial memver functions.
This commit is contained in:
parent
93b0cd436a
commit
4931e4025e
@ -1,5 +1,6 @@
|
|||||||
#include <catch.hpp>
|
//#include <catch.hpp>
|
||||||
//#include "/home/ahmedsamir/Work/SamirSlic3r/Slic3r/build/external/Catch/include/catch.hpp"
|
#include <libslic3r/IO.hpp>
|
||||||
|
#include "/home/ahmedsamir/Work/SamirSlic3r/Slic3r/build/external/Catch/include/catch.hpp"
|
||||||
|
|
||||||
#include "libslic3r.h"
|
#include "libslic3r.h"
|
||||||
#include "TriangleMesh.hpp"
|
#include "TriangleMesh.hpp"
|
||||||
@ -9,6 +10,38 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace Slic3r;
|
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")
|
SCENARIO("SupportMaterial: support_layers_z and contact_distance")
|
||||||
{
|
{
|
||||||
GIVEN("A print object having one modelObject") {
|
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.add_model_object(model.objects[0]);
|
||||||
print.objects.front()->_slice();
|
print.objects.front()->_slice();
|
||||||
|
|
||||||
SupportMaterial support = SupportMaterial(&print.config, &print.objects.front()->config);
|
SupportMaterial *support = print.objects.front()->_support_material();
|
||||||
|
|
||||||
vector<coordf_t>
|
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") {
|
THEN("First layer height is honored") {
|
||||||
REQUIRE((support_z[0] == print.default_object_config.first_layer_height.value));
|
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;
|
bool check = true;
|
||||||
for (size_t i = 1; i < support_z.size(); ++i)
|
for (size_t i = 1; i < support_z.size(); ++i)
|
||||||
if (support_z[i] - support_z[i - 1] <= 0) check = false;
|
if (support_z[i] - support_z[i - 1] <= 0) check = false;
|
||||||
REQUIRE(check);
|
REQUIRE(check == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
THEN("No layers thicker than nozzle diameter") {
|
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)
|
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)
|
if (support_z[i] - support_z[i - 1] > print.config.nozzle_diameter.get_at(0) + EPSILON)
|
||||||
check = false;
|
check = false;
|
||||||
REQUIRE(check);
|
REQUIRE(check == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
THEN("Layers above top surfaces are spaced correctly") {
|
THEN("Layers above top surfaces are spaced correctly") {
|
||||||
coordf_t expected_top_spacing = support
|
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;
|
bool wrong_top_spacing = 0;
|
||||||
for (coordf_t top_z_el : top_z) {
|
for (coordf_t top_z_el : top_z) {
|
||||||
// find layer index of this top surface.
|
// find layer index of this top surface.
|
||||||
int layer_id = -1;
|
size_t layer_id = -1;
|
||||||
for (int i = 0; i < support_z.size(); i++) {
|
for (size_t i = 0; i < support_z.size(); i++) {
|
||||||
if (abs(support_z[i] - top_z_el) < EPSILON) {
|
if (abs(support_z[i] - top_z_el) < EPSILON) {
|
||||||
layer_id = i;
|
layer_id = i;
|
||||||
i = static_cast<int>(support_z.size());
|
i = static_cast<int>(support_z.size());
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "PlaceholderParser.hpp"
|
#include "PlaceholderParser.hpp"
|
||||||
#include "SlicingAdaptive.hpp"
|
#include "SlicingAdaptive.hpp"
|
||||||
#include "LayerHeightSpline.hpp"
|
#include "LayerHeightSpline.hpp"
|
||||||
|
#include "SupportMaterial.hpp"
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
|
||||||
@ -25,6 +26,7 @@ class InvalidObjectException : public std::exception {};
|
|||||||
class Print;
|
class Print;
|
||||||
class PrintObject;
|
class PrintObject;
|
||||||
class ModelObject;
|
class ModelObject;
|
||||||
|
class SupportMaterial;
|
||||||
|
|
||||||
// Print step IDs for keeping track of the print state.
|
// Print step IDs for keeping track of the print state.
|
||||||
enum PrintStep {
|
enum PrintStep {
|
||||||
@ -132,6 +134,8 @@ class PrintObject
|
|||||||
Layer* add_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z);
|
Layer* add_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z);
|
||||||
void delete_layer(int idx);
|
void delete_layer(int idx);
|
||||||
|
|
||||||
|
SupportMaterial* _support_material();
|
||||||
|
Flow _support_material_flow(FlowRole role = frSupportMaterial);
|
||||||
size_t support_layer_count() const;
|
size_t support_layer_count() const;
|
||||||
void clear_support_layers();
|
void clear_support_layers();
|
||||||
SupportLayer* get_support_layer(int idx) { return this->support_layers.at(idx); };
|
SupportLayer* get_support_layer(int idx) { return this->support_layers.at(idx); };
|
||||||
|
@ -1095,4 +1095,55 @@ PrintObject::_infill()
|
|||||||
this->state.set_done(posInfill);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,16 +17,24 @@ SupportMaterial::generate_toolpaths(PrintObject *object,
|
|||||||
map<int, Polygons> interface,
|
map<int, Polygons> interface,
|
||||||
map<int, Polygons> base)
|
map<int, Polygons> base)
|
||||||
{
|
{
|
||||||
|
int ll = 0;
|
||||||
|
//cout << "Generate toolpaths " << ll++ << endl;
|
||||||
// Assig the object to the supports class.
|
// Assig the object to the supports class.
|
||||||
this->object = object;
|
this->object = object;
|
||||||
|
|
||||||
// Shape of contact area.
|
// Shape of contact area.
|
||||||
toolpaths_params params;
|
toolpaths_params params;
|
||||||
params.contact_loops = 1;
|
params.contact_loops = 1;
|
||||||
params.circle_radius = 1.5 * interface_flow->scaled_width();
|
//cout << "Generate toolpaths " << ll++ << endl;
|
||||||
params.circle_distance = 3 * params.circle_radius;
|
|
||||||
params.circle = create_circle(params.circle_radius);
|
|
||||||
|
|
||||||
|
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"
|
// TODO Add Slic3r debug. "Generating patterns\n"
|
||||||
// Prepare fillers.
|
// Prepare fillers.
|
||||||
params.pattern = object_config->support_material_pattern.value;
|
params.pattern = object_config->support_material_pattern.value;
|
||||||
@ -39,12 +47,13 @@ SupportMaterial::generate_toolpaths(PrintObject *object,
|
|||||||
else if (params.pattern == smpPillars) {
|
else if (params.pattern == smpPillars) {
|
||||||
params.pattern = smpHoneycomb;
|
params.pattern = smpHoneycomb;
|
||||||
}
|
}
|
||||||
|
//cout << "Generate toolpaths " << ll++ << endl;
|
||||||
params.interface_angle = object_config->support_material_angle.value + 90;
|
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_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.interface_density =
|
||||||
params.support_spacing = object_config->support_material_spacing.value + flow->spacing();
|
static_cast<float>(params.interface_spacing == 0 ? 1 : interface_flow.spacing() / params.interface_spacing);
|
||||||
params.support_density = params.support_spacing == 0 ? 1 : flow->spacing() / params.support_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>(
|
parallelize<size_t>(
|
||||||
0,
|
0,
|
||||||
@ -52,6 +61,7 @@ SupportMaterial::generate_toolpaths(PrintObject *object,
|
|||||||
boost::bind(&SupportMaterial::process_layer, this, _1, params),
|
boost::bind(&SupportMaterial::process_layer, this, _1, params),
|
||||||
this->config->threads.value
|
this->config->threads.value
|
||||||
);
|
);
|
||||||
|
//cout << "Generate toolpaths finished" << ll++ << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -64,39 +74,50 @@ SupportMaterial::generate(PrintObject *object)
|
|||||||
// that it will be effective, regardless of how it's built below.
|
// 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);
|
pair<map<coordf_t, Polygons>, map<coordf_t, Polygons>> contact_overhang = contact_area(object);
|
||||||
map<coordf_t, Polygons> &contact = contact_overhang.first;
|
map<coordf_t, Polygons> &contact = contact_overhang.first;
|
||||||
|
cout << "Contact size " << contact.size() << endl;
|
||||||
map<coordf_t, Polygons> &overhang = contact_overhang.second;
|
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
|
// 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
|
// the layer heights of support material and to clip support to the object
|
||||||
// silhouette.
|
// silhouette.
|
||||||
map<coordf_t, Polygons> top = object_top(object, &contact);
|
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
|
// We now know the upper and lower boundaries for our support material object
|
||||||
// (@$contact_z and @$top_z), so we can generate intermediate layers.
|
// (@$contact_z and @$top_z), so we can generate intermediate layers.
|
||||||
vector<coordf_t> support_z = support_layers_z(get_keys_sorted(contact),
|
vector<coordf_t> support_z = support_layers_z(get_keys_sorted(contact),
|
||||||
get_keys_sorted(top),
|
get_keys_sorted(top),
|
||||||
get_max_layer_height(object));
|
get_max_layer_height(object));
|
||||||
|
cout << "Samir " << ppp++ << endl;
|
||||||
// If we wanted to apply some special logic to the first support layers lying on
|
// 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.
|
// Propagate contact layers downwards to generate interface layers.
|
||||||
map<int, Polygons> interface = generate_interface_layers(support_z, contact, top);
|
map<int, Polygons> interface = generate_interface_layers(support_z, contact, top);
|
||||||
clip_with_object(interface, support_z, *object);
|
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
|
// 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
|
// 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.
|
// 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(
|
object->add_support_layer(
|
||||||
i, // id.
|
i, // id.
|
||||||
(i == 0) ? support_z[0] - 0 : (support_z[i] - support_z[i - 1]), // height.
|
(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];
|
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 the actual toolpaths and save them into each layer.
|
||||||
generate_toolpaths(object, overhang, contact, interface, base);
|
generate_toolpaths(object, overhang, contact, interface, base);
|
||||||
|
cout << "Samir " << ppp++ << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<coordf_t>
|
vector<coordf_t>
|
||||||
@ -126,7 +148,8 @@ SupportMaterial::support_layers_z(vector<coordf_t> contact_z,
|
|||||||
// determine layer height for any non-contact layer
|
// determine layer height for any non-contact layer
|
||||||
// we use max() to prevent many ultra-thin layers to be inserted in case
|
// we use max() to prevent many ultra-thin layers to be inserted in case
|
||||||
// layer_height > nozzle_diameter * 0.75.
|
// 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));
|
auto support_material_height = (max_object_layer_height, (nozzle_diameter * 0.75));
|
||||||
coordf_t _contact_distance = this->contact_distance(support_material_height, nozzle_diameter);
|
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>>
|
pair<map<coordf_t, Polygons>, map<coordf_t, Polygons>>
|
||||||
SupportMaterial::contact_area(PrintObject *object)
|
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.
|
// If user specified a custom angle threshold, convert it to radians.
|
||||||
float threshold_rad;
|
float threshold_rad = 0.0;
|
||||||
cout << conf.support_material_threshold << endl;
|
|
||||||
if (conf.support_material_threshold > 0) {
|
if (!conf.support_material_threshold.percent) {
|
||||||
threshold_rad = static_cast<float>(Geometry::deg2rad(
|
threshold_rad = static_cast<float>(Geometry::deg2rad(
|
||||||
conf.support_material_threshold.value + 1)); // +1 makes the threshold inclusive
|
conf.support_material_threshold + 1)); // +1 makes the threshold inclusive
|
||||||
// TODO @Samir55 add debug statetments.
|
|
||||||
|
#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
|
// 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;
|
Polygons buildplate_only_top_surfaces;
|
||||||
|
|
||||||
// Determine contact areas.
|
// 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
|
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++) {
|
for (int layer_id = 0; layer_id < object->layers.size(); layer_id++) {
|
||||||
// Note $layer_id might != $layer->id when raft_layers > 0
|
// Note $layer_id might != $layer->id when raft_layers > 0
|
||||||
// so $layer_id == 0 means first object layer
|
// so $layer_id == 0 means first object layer
|
||||||
// and $layer->id == 0 means first print layer (including raft).
|
// and $layer->id == 0 means first print layer (including raft).
|
||||||
|
|
||||||
// If no raft, and we're at layer 0, skip to layer 1
|
// 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;
|
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
|
// 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
|
// support generation if supports are disabled, or if we're at a high
|
||||||
// enough layer that enforce-supports no longer applies.
|
// enough layer that enforce-supports no longer applies.
|
||||||
@ -244,45 +274,44 @@ SupportMaterial::contact_area(PrintObject *object)
|
|||||||
Polygons projection_new;
|
Polygons projection_new;
|
||||||
for (auto const ®ion : layer->regions) {
|
for (auto const ®ion : layer->regions) {
|
||||||
SurfacesPtr top_surfaces = region->slices.filter_by_type(stTop);
|
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);
|
projection_new.push_back(polygon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!projection_new.empty()) {
|
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
|
// Apply the safety offset to the newly added polygons, so they will connect
|
||||||
// with the polygons collected before,
|
// with the polygons collected before,
|
||||||
// but don't apply the safety offset during the union operation as it would
|
// but don't apply the safety offset during the union operation as it would
|
||||||
// inflate the polygons over and over.
|
// inflate the polygons over and over.
|
||||||
Polygons polygons = offset(projection_new, scale_(0.01));
|
//cout << "Old Build plate only surfaces " << buildplate_only_top_surfaces.size() << endl;
|
||||||
append_polygons(buildplate_only_top_surfaces, polygons);
|
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);
|
buildplate_only_top_surfaces = union_(buildplate_only_top_surfaces, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect overhangs and contact areas needed to support them.
|
// Detect overhangs and contact areas needed to support them.
|
||||||
Polygons m_overhang, m_contact;
|
Polygons tmp_overhang, tmp_contact;
|
||||||
if (layer_id == 0) {
|
if (layer_id == 0) {
|
||||||
// this is the first object layer, so we're here just to get the object
|
// this is the first object layer, so we're here just to get the object
|
||||||
// footprint for the raft.
|
// footprint for the raft.
|
||||||
// we only consider contours and discard holes to get a more continuous raft.
|
// we only consider contours and discard holes to get a more continuous raft.
|
||||||
for (auto const &contour : layer->slices.contours()) {
|
for (auto const &contour : layer->slices.contours())
|
||||||
auto contour_clone = contour;
|
tmp_overhang.push_back(contour);
|
||||||
m_overhang.push_back(contour_clone);
|
|
||||||
}
|
|
||||||
|
|
||||||
Polygons polygons = offset(m_overhang, scale_(+SUPPORT_MATERIAL_MARGIN));
|
Polygons polygons = offset(tmp_overhang, scale_(+SUPPORT_MATERIAL_MARGIN));
|
||||||
append_polygons(m_contact, polygons);
|
append_to(tmp_contact, polygons);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Layer *lower_layer = object->get_layer(layer_id - 1);
|
Layer *lower_layer = object->get_layer(layer_id - 1);
|
||||||
for (auto layerm : layer->regions) {
|
for (auto layer_m : layer->regions) {
|
||||||
auto fw = layerm->flow(frExternalPerimeter).scaled_width();
|
auto fw = layer_m->flow(frExternalPerimeter).scaled_width();
|
||||||
Polygons difference;
|
Polygons difference;
|
||||||
|
|
||||||
// If a threshold angle was specified, use a different logic for detecting overhangs.
|
// 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
|
|| layer_id <= conf.support_material_enforce_layers
|
||||||
|| (conf.raft_layers > 0 && layer_id
|
|| (conf.raft_layers > 0 && layer_id
|
||||||
== 0)) { // TODO ASK @Samir why layer_id ==0 check , layer_id will never equal to zero
|
== 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) {
|
if (layer_threshold_rad > 0) {
|
||||||
d = scale_(lower_layer->height
|
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(
|
difference = diff(
|
||||||
Polygons(layerm->slices),
|
Polygons(layer_m->slices),
|
||||||
offset(lower_layer->slices, +d)
|
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
|
// 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
|
// very short overhangs), and such contact area would be eaten by the
|
||||||
// enforced spacing, resulting in high threshold angles to be almost ignored
|
// enforced spacing, resulting in high threshold angles to be almost ignored
|
||||||
if (d > fw / 2) {
|
if (d > fw / 2)
|
||||||
difference = diff(
|
difference = diff(
|
||||||
offset(difference, d - fw / 2),
|
offset(difference, d - fw / 2),
|
||||||
lower_layer->slices);
|
lower_layer->slices);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
difference = diff(
|
difference = diff(
|
||||||
Polygons(layerm->slices),
|
Polygons(layer_m->slices),
|
||||||
offset(lower_layer->slices,
|
offset(lower_layer->slices,
|
||||||
static_cast<const float>(+conf.get_abs_value("support_material_threshold", fw)))
|
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.
|
// Compute the area of bridging perimeters.
|
||||||
Polygons bridged_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
|
// 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
|
// 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;
|
Polygons lower_grown_slices;
|
||||||
{
|
{
|
||||||
coordf_t nozzle_diameter = this->config->nozzle_diameter
|
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_grown_slices = offset(
|
||||||
lower_layer->slices,
|
lower_layer->slices,
|
||||||
@ -348,26 +376,29 @@ SupportMaterial::contact_area(PrintObject *object)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO Revise Here.
|
||||||
// Get all perimeters as polylines.
|
// Get all perimeters as polylines.
|
||||||
// TODO: split_at_first_point() (called by as_polyline() for ExtrusionLoops)
|
// TODO: split_at_first_point() (called by as_polyline() for ExtrusionLoops)
|
||||||
// could split a bridge mid-way.
|
// could split a bridge mid-way.
|
||||||
Polylines overhang_perimeters;
|
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,
|
// Only consider the overhang parts of such perimeters,
|
||||||
// overhangs being those parts not supported by
|
// overhangs being those parts not supported by
|
||||||
// workaround for Clipper bug, see Slic3r::Polygon::clip_as_polyline()
|
// 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);
|
overhang_perimeters = diff_pl(overhang_perimeters, lower_grown_slices);
|
||||||
|
|
||||||
// Only consider straight overhangs.
|
// Only consider straight overhangs.
|
||||||
Polylines new_overhangs_perimeters_polylines;
|
Polylines new_overhangs_perimeters_polylines;
|
||||||
for (auto p : overhang_perimeters)
|
for (const auto &p : overhang_perimeters)
|
||||||
if (p.is_straight())
|
if (p.is_straight())
|
||||||
new_overhangs_perimeters_polylines.push_back(p);
|
new_overhangs_perimeters_polylines.push_back(p);
|
||||||
|
|
||||||
overhang_perimeters = new_overhangs_perimeters_polylines;
|
overhang_perimeters = new_overhangs_perimeters_polylines;
|
||||||
new_overhangs_perimeters_polylines = Polylines();
|
|
||||||
|
|
||||||
// Only consider overhangs having endpoints inside layer's slices
|
// Only consider overhangs having endpoints inside layer's slices
|
||||||
for (auto &p : overhang_perimeters) {
|
for (auto &p : overhang_perimeters) {
|
||||||
@ -375,7 +406,8 @@ SupportMaterial::contact_area(PrintObject *object)
|
|||||||
p.extend_end(fw);
|
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())
|
if (layer->slices.contains_b(p.first_point())
|
||||||
&& layer->slices.contains_b(p.last_point())) {
|
&& layer->slices.contains_b(p.last_point())) {
|
||||||
new_overhangs_perimeters_polylines.push_back(p);
|
new_overhangs_perimeters_polylines.push_back(p);
|
||||||
@ -392,56 +424,45 @@ SupportMaterial::contact_area(PrintObject *object)
|
|||||||
coord_t widths[] = {bridge_flow.scaled_width(),
|
coord_t widths[] = {bridge_flow.scaled_width(),
|
||||||
bridge_flow.scaled_spacing(),
|
bridge_flow.scaled_spacing(),
|
||||||
fw,
|
fw,
|
||||||
layerm->flow(FlowRole::frPerimeter).scaled_width()};
|
layer_m->flow(FlowRole::frPerimeter).scaled_width()};
|
||||||
|
|
||||||
auto w = *max_element(widths, widths + 4);
|
auto w = *max_element(widths, widths + 4);
|
||||||
|
|
||||||
// Also apply safety offset to ensure no gaps are left in between.
|
// Also apply safety offset to ensure no gaps are left in between.
|
||||||
// TODO CHeck this.
|
Polygons ps = offset(overhang_perimeters, w / 2 + 10);
|
||||||
for (auto &p : overhang_perimeters) {
|
bridged_perimeters = union_(ps);
|
||||||
Polygons ps = union_(offset(p, w / 2 + 10));
|
|
||||||
for (auto ps_el : ps)
|
|
||||||
bridged_perimeters.push_back(ps_el);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (1) {
|
if (1) {
|
||||||
// Remove the entire bridges and only support the unsupported edges.
|
// Remove the entire bridges and only support the unsupported edges.
|
||||||
ExPolygons bridges;
|
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) {
|
if (surface->bridge_angle != -1) {
|
||||||
bridges.push_back(surface->expolygon);
|
bridges.push_back(surface->expolygon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ExPolygons ps;
|
Polygons ps = to_polygons(bridges);
|
||||||
for (auto p : bridged_perimeters)
|
append_to(ps, bridged_perimeters);
|
||||||
ps.push_back(ExPolygon(p));
|
|
||||||
for (auto p : bridges)
|
|
||||||
ps.push_back(p);
|
|
||||||
|
|
||||||
// TODO ASK about this.
|
difference = diff( // TODO ASK about expolygons and polygons miss match.
|
||||||
difference = diff(
|
|
||||||
difference,
|
difference,
|
||||||
to_polygons(ps),
|
ps,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO Ask about this.
|
append_to(difference,
|
||||||
auto p_intersections = intersection(offset(layerm->unsupported_bridge_edges.polylines,
|
intersection(
|
||||||
+scale_(SUPPORT_MATERIAL_MARGIN)),
|
offset(layer_m->unsupported_bridge_edges.polylines,
|
||||||
to_polygons(bridges));
|
+scale_(SUPPORT_MATERIAL_MARGIN)), to_polygons(bridges)));
|
||||||
for (auto p: p_intersections) {
|
|
||||||
difference.push_back(p);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// just remove bridged areas.
|
// just remove bridged areas.
|
||||||
difference = diff(
|
difference = diff(
|
||||||
difference,
|
difference,
|
||||||
layerm->bridged,
|
layer_m->bridged,
|
||||||
1
|
true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} // if ($conf->dont_support_bridges)
|
} // if ($conf->dont_support_bridges)
|
||||||
@ -455,7 +476,7 @@ SupportMaterial::contact_area(PrintObject *object)
|
|||||||
if (difference.empty()) continue;
|
if (difference.empty()) continue;
|
||||||
|
|
||||||
// NOTE: this is not the full overhang as it misses the outermost half of the perimeter width!
|
// 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
|
// 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.
|
// extrusion width and extending the area according to the configured margin.
|
||||||
@ -466,25 +487,24 @@ SupportMaterial::contact_area(PrintObject *object)
|
|||||||
|
|
||||||
if (buildplate_only) {
|
if (buildplate_only) {
|
||||||
// Trim the inflated contact surfaces by the top surfaces as well.
|
// 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);
|
slices_margin = union_(slices_margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Ask how to port this.
|
vector<coord_t> scale_vector
|
||||||
/*
|
(static_cast<unsigned long>(SUPPORT_MATERIAL_MARGIN / MARGIN_STEP), scale_(MARGIN_STEP));
|
||||||
for ($fw/2, map {scale MARGIN_STEP} 1..(MARGIN / MARGIN_STEP)) {
|
scale_vector.push_back(fw / 2);
|
||||||
$diff = diff(
|
for (int i = static_cast<int>(scale_vector.size()) - 1; i >= 0; i--) {
|
||||||
offset($diff, $_),
|
difference = diff(
|
||||||
$slices_margin,
|
offset(difference, i),
|
||||||
|
slices_margin
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
append_polygons(tmp_contact, difference);
|
||||||
append_polygons(m_contact, difference);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (contact.empty())
|
if (tmp_contact.empty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Now apply the contact areas to the layer were they need to be made.
|
// 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)));
|
.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 =
|
auto nozzle_diameter =
|
||||||
accumulate(nozzle_diameters.begin(), nozzle_diameters.end(), 0.0) / nozzle_diameters_count;
|
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.
|
// Ignore this contact area if it's too low.
|
||||||
if (contact_z < conf.first_layer_height - EPSILON)
|
if (contact_z < conf.first_layer_height - EPSILON)
|
||||||
continue;
|
continue;
|
||||||
|
//cout << contact_z << " " << tmp_contact.size() << endl;
|
||||||
|
|
||||||
|
contact[contact_z] = tmp_contact;
|
||||||
contact[contact_z] = m_contact;
|
overhang[contact_z] = tmp_overhang;
|
||||||
overhang[contact_z] = m_overhang;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -532,46 +552,42 @@ SupportMaterial::object_top(PrintObject *object, map<coordf_t, Polygons> *contac
|
|||||||
return top;
|
return top;
|
||||||
|
|
||||||
Polygons projection;
|
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];
|
Layer *layer = object->layers[i];
|
||||||
SurfacesPtr m_top;
|
SurfacesPtr m_top;
|
||||||
|
|
||||||
for (auto r : layer->regions)
|
for (auto r : layer->regions)
|
||||||
for (auto s : r->slices.filter_by_type(stTop))
|
append_to(m_top, r->slices.filter_by_type(stTop));
|
||||||
m_top.push_back(s);
|
|
||||||
|
|
||||||
if (!m_top.empty()) {
|
if (m_top.empty()) continue;
|
||||||
// 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;
|
|
||||||
|
|
||||||
// Use <= instead of just < because otherwise we'd ignore any contact regions
|
// compute projection of the contact areas above this top layer
|
||||||
// having the same Z of top layers.
|
// first add all the 'new' contact areas to the current projection
|
||||||
for (auto el : *contact)
|
// ('new' means all the areas that are lower than the last top layer
|
||||||
if (el.first > layer->print_z && el.first <= min_top)
|
// we considered).
|
||||||
for (const auto &p : el.second)
|
double min_top = (!top.empty() ? top.begin()->first : contact->rbegin()->first);
|
||||||
projection.push_back(p);
|
|
||||||
|
|
||||||
// Now find whether any projection falls onto this top surface.
|
// Use <= instead of just < because otherwise we'd ignore any contact regions
|
||||||
Polygons touching = intersection(projection, p(m_top));
|
// having the same Z of top layers.
|
||||||
if (!touching.empty()) {
|
for (auto el : *contact)
|
||||||
// Grow top surfaces so that interface and support generation are generated
|
if (el.first > layer->print_z && el.first <= min_top)
|
||||||
// with some spacing from object - it looks we don't need the actual
|
for (const auto &p : el.second)
|
||||||
// top shapes so this can be done here.
|
projection.push_back(p);
|
||||||
top[layer->print_z] = offset(touching, flow->scaled_width());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the areas that touched from the projection that will continue on
|
// Now find whether any projection falls onto this top surface.
|
||||||
// next, lower, top surfaces.
|
Polygons touching = intersection(projection, p(m_top));
|
||||||
projection = diff(projection, touching);
|
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;
|
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.
|
// This prevents supplying an empty point set to BoundingBox constructor.
|
||||||
if (contact.empty()) return;
|
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_size = scale_(object_config->support_material_pillar_size.value);
|
||||||
coord_t pillar_spacing = scale_(object_config->support_material_pillar_spacing.value);
|
coord_t pillar_spacing = scale_(object_config->support_material_pillar_spacing.value);
|
||||||
|
|
||||||
|
cout << "Samir U " << u++ << endl;
|
||||||
Polygons grid;
|
Polygons grid;
|
||||||
{
|
{
|
||||||
auto pillar = Polygon({
|
auto pillar = Polygon({
|
||||||
@ -615,21 +635,28 @@ SupportMaterial::generate_pillars_shape(const map<coordf_t, Polygons> &contact,
|
|||||||
|
|
||||||
grid = union_(pillars);
|
grid = union_(pillars);
|
||||||
}
|
}
|
||||||
|
cout << "Samir U " << u++ << endl; //1
|
||||||
|
cout << "Support z size " << support_z.size() << endl;
|
||||||
// Add pillars to every layer.
|
// Add pillars to every layer.
|
||||||
for (auto i = 0; i < support_z.size(); i++) {
|
for (auto i = 0; i < support_z.size(); i++) {
|
||||||
shape[i] = grid;
|
shape[i] = grid;
|
||||||
}
|
}
|
||||||
|
cout << "Samir U " << u++ << endl;
|
||||||
// Build capitals.
|
// 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++) {
|
for (auto i = 0; i < support_z.size(); i++) {
|
||||||
coordf_t z = support_z[i];
|
coordf_t z = support_z[i];
|
||||||
|
|
||||||
|
cout << z << endl;
|
||||||
auto capitals = intersection(
|
auto capitals = intersection(
|
||||||
grid,
|
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
|
// 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
|
// but store the contact area supported by the capital because we need to make
|
||||||
// sure nothing is left.
|
// 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--) {
|
for (int j = i - 1; j >= 0; j--) {
|
||||||
auto jz = support_z[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;
|
if (capitals.empty()) break;
|
||||||
append_to(shape[i], capital_polygons);
|
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
|
// 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
|
// but store the contact area supported by the capital because we need to make
|
||||||
// sure nothing is left.
|
// sure nothing is left.
|
||||||
auto contact_not_supported_by_capitals = diff(
|
auto contact_not_supported_by_capitals = diff(
|
||||||
contact.at(z),
|
contact.count(z) > 0 ? contact.at(z) : Polygons(),
|
||||||
contact_supported_by_capitals
|
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>
|
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.
|
// Let's now generate support layers under interface layers.
|
||||||
map<int, Polygons> base;
|
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 z = support_z[i];
|
||||||
auto overlapping_layers = this->overlapping_layers(i, support_z);
|
auto overlapping_layers = this->overlapping_layers(i, support_z);
|
||||||
vector<coordf_t> overlapping_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).
|
// (1 interface layer means we only have contact layer, so $interface->{$i+1} is empty).
|
||||||
Polygons upper_contact;
|
Polygons upper_contact;
|
||||||
if (object_config->support_material_interface_layers.value <= 1) {
|
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;
|
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++) {
|
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;"
|
// Todo Ask about how to port this line. "my $this = $contact->{$z} // next;"
|
||||||
auto z = support_z[layer_id];
|
auto z = support_z[layer_id];
|
||||||
|
|
||||||
if (contact.count(z) <= 0)
|
if (contact.count(z) <= 0)
|
||||||
continue;
|
continue;
|
||||||
Polygons &_contact = contact[z];
|
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)
|
if (object_config->support_material_interface_layers.value == 0)
|
||||||
return;
|
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.
|
// Loop through object's top surfaces. TODO CHeck if the keys are sorted.
|
||||||
for (auto &top_el : top) {
|
for (auto &top_el : top) {
|
||||||
@ -895,12 +924,12 @@ SupportMaterial::clip_with_object(map<int, Polygons> &support, vector<coordf_t>
|
|||||||
slices.push_back(s);
|
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} = diff(
|
||||||
$support->{$i},
|
$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;
|
coordf_t z = layer->print_z;
|
||||||
|
|
||||||
// We redefine flows locally by applyinh this layer's height.
|
// We redefine flows locally by applyinh this layer's height.
|
||||||
auto _flow = *flow;
|
Flow _flow = flow;
|
||||||
auto _interface_flow = *interface_flow;
|
Flow _interface_flow = interface_flow;
|
||||||
_flow.height = static_cast<float>(layer->height);
|
_flow.height = static_cast<float>(layer->height);
|
||||||
_interface_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"];
|
Fill *filler = fillers["support"];
|
||||||
filler->angle = static_cast<float>(Geometry::deg2rad(params.angles[layer_id % int(params.angles.size())]));
|
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.
|
// value that guarantees that all layers are correctly aligned.
|
||||||
filler->min_spacing = flow->spacing();
|
filler->min_spacing = flow.spacing();
|
||||||
|
|
||||||
auto density = params.support_density;
|
auto density = params.support_density;
|
||||||
Flow *base_flow = &_flow;
|
Flow *base_flow = &_flow;
|
||||||
@ -1122,7 +1151,7 @@ SupportMaterial::process_layer(int layer_id, toolpaths_params params)
|
|||||||
filler = fillers["interface"];
|
filler = fillers["interface"];
|
||||||
filler->angle = static_cast<float>(Geometry::deg2rad(object_config->support_material_angle.value + 90));
|
filler->angle = static_cast<float>(Geometry::deg2rad(object_config->support_material_angle.value + 90));
|
||||||
density = 0.5;
|
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
|
// Use the proper spacing for first layer as we don't need to align
|
||||||
// its pattern to the other layers.
|
// its pattern to the other layers.
|
||||||
|
@ -24,6 +24,8 @@ namespace Slic3r
|
|||||||
// how much we extend support around the actual contact area
|
// how much we extend support around the actual contact area
|
||||||
constexpr coordf_t SUPPORT_MATERIAL_MARGIN = 1.5;
|
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_SIZE = 2.5;
|
||||||
|
|
||||||
constexpr coordf_t PILLAR_SPACING = 10;
|
constexpr coordf_t PILLAR_SPACING = 10;
|
||||||
@ -61,24 +63,13 @@ struct toolpaths_params
|
|||||||
class SupportMaterial
|
class SupportMaterial
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
friend PrintObject;
|
||||||
|
|
||||||
PrintConfig *config; ///< The print config
|
PrintConfig *config; ///< The print config
|
||||||
PrintObjectConfig *object_config; ///< The object print config.
|
PrintObjectConfig *object_config; ///< The object print config.
|
||||||
Flow *flow; ///< The intermediate layers print flow.
|
Flow flow; ///< The intermediate layers print flow.
|
||||||
Flow *first_layer_flow; ///< The first (base) layers print flow.
|
Flow first_layer_flow; ///< The first (base) layers print flow.
|
||||||
Flow *interface_flow; ///< The interface 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)
|
|
||||||
{}
|
|
||||||
|
|
||||||
/// Generate the extrusions paths for the support matterial generated for the given print object.
|
/// Generate the extrusions paths for the support matterial generated for the given print object.
|
||||||
void generate_toolpaths(PrintObject *object,
|
void generate_toolpaths(PrintObject *object,
|
||||||
@ -97,7 +88,7 @@ public:
|
|||||||
|
|
||||||
pair<map<coordf_t, Polygons>, map<coordf_t, Polygons>> contact_area(PrintObject *object);
|
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);
|
map<coordf_t, Polygons> object_top(PrintObject *object, map<coordf_t, Polygons> *contact);
|
||||||
|
|
||||||
void generate_pillars_shape(const 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);
|
void process_layer(int layer_id, toolpaths_params params);
|
||||||
|
|
||||||
private:
|
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.
|
// Get the maximum layer height given a print object.
|
||||||
coordf_t get_max_layer_height(PrintObject *object);
|
coordf_t get_max_layer_height(PrintObject *object);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user