Added a single perimeter to the first layer of support or raft.

Fixes [Request] Add optional perimeter to raft #756
Fixes First support layer does not stick to bed #2101

New parameters raft_first_layer_density and raft_first_layer_expansion
to influence the 1st layer of raft or support.
Fixes Allow to disable raft under support structures. #3772
Fixes raft is larger than necessary #2568
Fixes Supports on the build plate should have a solid bottom interface for better adhesion #1165

Changed the 1st layer infill to rectilinear even for soluble materials.
Fixes first layer of support for multi filament support oddly spaced #1445
Fixes Full Soluble Materials interfacing into Models + Soluble material noise on Bed #684
This commit is contained in:
Vojtech Bubnik 2021-02-24 08:48:33 +01:00
parent 77d007c484
commit fcb714cd24
10 changed files with 178 additions and 80 deletions

View file

@ -102,6 +102,7 @@ public:
virtual double min_mm3_per_mm() const = 0; virtual double min_mm3_per_mm() const = 0;
virtual Polyline as_polyline() const = 0; virtual Polyline as_polyline() const = 0;
virtual void collect_polylines(Polylines &dst) const = 0; virtual void collect_polylines(Polylines &dst) const = 0;
virtual void collect_points(Points &dst) const = 0;
virtual Polylines as_polylines() const { Polylines dst; this->collect_polylines(dst); return dst; } virtual Polylines as_polylines() const { Polylines dst; this->collect_polylines(dst); return dst; }
virtual double length() const = 0; virtual double length() const = 0;
virtual double total_volume() const = 0; virtual double total_volume() const = 0;
@ -167,6 +168,7 @@ public:
double min_mm3_per_mm() const override { return this->mm3_per_mm; } double min_mm3_per_mm() const override { return this->mm3_per_mm; }
Polyline as_polyline() const override { return this->polyline; } Polyline as_polyline() const override { return this->polyline; }
void collect_polylines(Polylines &dst) const override { if (! this->polyline.empty()) dst.emplace_back(this->polyline); } void collect_polylines(Polylines &dst) const override { if (! this->polyline.empty()) dst.emplace_back(this->polyline); }
void collect_points(Points &dst) const override { append(dst, this->polyline.points); }
double total_volume() const override { return mm3_per_mm * unscale<double>(length()); } double total_volume() const override { return mm3_per_mm * unscale<double>(length()); }
private: private:
@ -217,6 +219,12 @@ public:
double min_mm3_per_mm() const override; double min_mm3_per_mm() const override;
Polyline as_polyline() const override; Polyline as_polyline() const override;
void collect_polylines(Polylines &dst) const override { Polyline pl = this->as_polyline(); if (! pl.empty()) dst.emplace_back(std::move(pl)); } void collect_polylines(Polylines &dst) const override { Polyline pl = this->as_polyline(); if (! pl.empty()) dst.emplace_back(std::move(pl)); }
void collect_points(Points &dst) const override {
size_t n = std::accumulate(paths.begin(), paths.end(), 0, [](const size_t n, const ExtrusionPath &p){ return n + p.polyline.size(); });
dst.reserve(dst.size() + n);
for (const ExtrusionPath &p : this->paths)
append(dst, p.polyline.points);
}
double total_volume() const override { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; } double total_volume() const override { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; }
}; };
@ -268,6 +276,12 @@ public:
double min_mm3_per_mm() const override; double min_mm3_per_mm() const override;
Polyline as_polyline() const override { return this->polygon().split_at_first_point(); } Polyline as_polyline() const override { return this->polygon().split_at_first_point(); }
void collect_polylines(Polylines &dst) const override { Polyline pl = this->as_polyline(); if (! pl.empty()) dst.emplace_back(std::move(pl)); } void collect_polylines(Polylines &dst) const override { Polyline pl = this->as_polyline(); if (! pl.empty()) dst.emplace_back(std::move(pl)); }
void collect_points(Points &dst) const override {
size_t n = std::accumulate(paths.begin(), paths.end(), 0, [](const size_t n, const ExtrusionPath &p){ return n + p.polyline.size(); });
dst.reserve(dst.size() + n);
for (const ExtrusionPath &p : this->paths)
append(dst, p.polyline.points);
}
double total_volume() const override { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; } double total_volume() const override { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; }
//static inline std::string role_to_string(ExtrusionLoopRole role); //static inline std::string role_to_string(ExtrusionLoopRole role);

View file

@ -117,6 +117,11 @@ public:
extrusion_entity->collect_polylines(dst); extrusion_entity->collect_polylines(dst);
} }
void collect_points(Points &dst) const override {
for (ExtrusionEntity* extrusion_entity : this->entities)
extrusion_entity->collect_points(dst);
}
double length() const override { double length() const override {
throw Slic3r::RuntimeError("Calling length() on a ExtrusionEntityCollection"); throw Slic3r::RuntimeError("Calling length() on a ExtrusionEntityCollection");
return 0.; return 0.;

View file

@ -2573,10 +2573,11 @@ std::string GCode::extrude_infill(const Print &print, const std::vector<ObjectBy
std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fills) std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fills)
{ {
static constexpr const char *support_label = "support material";
static constexpr const char *support_interface_label = "support material interface";
std::string gcode; std::string gcode;
if (! support_fills.entities.empty()) { if (! support_fills.entities.empty()) {
const char *support_label = "support material";
const char *support_interface_label = "support material interface";
const double support_speed = m_config.support_material_speed.value; const double support_speed = m_config.support_material_speed.value;
const double support_interface_speed = m_config.support_material_interface_speed.get_abs_value(support_speed); const double support_interface_speed = m_config.support_material_interface_speed.get_abs_value(support_speed);
for (const ExtrusionEntity *ee : support_fills.entities) { for (const ExtrusionEntity *ee : support_fills.entities) {
@ -2589,9 +2590,14 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill
gcode += this->extrude_path(*path, label, speed); gcode += this->extrude_path(*path, label, speed);
else { else {
const ExtrusionMultiPath *multipath = dynamic_cast<const ExtrusionMultiPath*>(ee); const ExtrusionMultiPath *multipath = dynamic_cast<const ExtrusionMultiPath*>(ee);
assert(multipath != nullptr);
if (multipath) if (multipath)
gcode += this->extrude_multi_path(*multipath, label, speed); gcode += this->extrude_multi_path(*multipath, label, speed);
else {
const ExtrusionEntityCollection *eec = dynamic_cast<const ExtrusionEntityCollection*>(ee);
assert(eec);
if (eec)
gcode += this->extrude_support(*eec);
}
} }
} }
} }

View file

@ -426,7 +426,8 @@ const std::vector<std::string>& Preset::print_options()
"bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "first_layer_speed", "perimeter_acceleration", "infill_acceleration", "bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "first_layer_speed", "perimeter_acceleration", "infill_acceleration",
"bridge_acceleration", "first_layer_acceleration", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield", "bridge_acceleration", "first_layer_acceleration", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield",
"min_skirt_length", "brim_width", "brim_offset", "brim_type", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers", "min_skirt_length", "brim_width", "brim_offset", "brim_type", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers",
"raft_layers", "support_material_pattern", "support_material_with_sheath", "support_material_spacing", "raft_layers", "raft_first_layer_density", "raft_first_layer_expansion",
"support_material_pattern", "support_material_with_sheath", "support_material_spacing",
"support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers", "support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers",
"support_material_interface_spacing", "support_material_interface_contact_loops", "support_material_contact_distance", "support_material_interface_spacing", "support_material_interface_contact_loops", "support_material_contact_distance",
"support_material_buildplate_only", "dont_support_bridges", "notes", "complete_objects", "extruder_clearance_radius", "support_material_buildplate_only", "dont_support_bridges", "notes", "complete_objects", "extruder_clearance_radius",

View file

@ -1731,8 +1731,7 @@ void Print::_make_skirt()
for (const SupportLayer *layer : object->support_layers()) { for (const SupportLayer *layer : object->support_layers()) {
if (layer->print_z > skirt_height_z) if (layer->print_z > skirt_height_z)
break; break;
for (const ExtrusionEntity *extrusion_entity : layer->support_fills.entities) layer->support_fills.collect_points(object_points);
append(object_points, extrusion_entity->as_polyline().points);
} }
// Repeat points for each object copy. // Repeat points for each object copy.
for (const PrintInstance &instance : object->instances()) { for (const PrintInstance &instance : object->instances()) {

View file

@ -1775,6 +1775,25 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionString("")); def->set_default_value(new ConfigOptionString(""));
def->cli = ConfigOptionDef::nocli; def->cli = ConfigOptionDef::nocli;
def = this->add("raft_first_layer_density", coPercent);
def->label = L("First layer density");
def->category = L("Support material");
def->tooltip = L("Density of the first raft or support layer.");
def->sidetext = L("%");
def->min = 0;
def->max = 150;
def->mode = comExpert;
def->set_default_value(new ConfigOptionPercent(90));
def = this->add("raft_first_layer_expansion", coFloat);
def->label = L("First layer expansion");
def->category = L("Support material");
def->tooltip = L("Expansion of the first raft or support layer to improve adhesion to print bed.");
def->sidetext = L("mm");
def->min = 0;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(3.));
def = this->add("raft_layers", coInt); def = this->add("raft_layers", coInt);
def->label = L("Raft layers"); def->label = L("Raft layers");
def->category = L("Support material"); def->category = L("Support material");

View file

@ -473,6 +473,8 @@ public:
// Force the generation of solid shells between adjacent materials/volumes. // Force the generation of solid shells between adjacent materials/volumes.
ConfigOptionBool interface_shells; ConfigOptionBool interface_shells;
ConfigOptionFloat layer_height; ConfigOptionFloat layer_height;
ConfigOptionPercent raft_first_layer_density;
ConfigOptionFloat raft_first_layer_expansion;
ConfigOptionInt raft_layers; ConfigOptionInt raft_layers;
ConfigOptionEnum<SeamPosition> seam_position; ConfigOptionEnum<SeamPosition> seam_position;
// ConfigOptionFloat seam_preferred_direction; // ConfigOptionFloat seam_preferred_direction;
@ -520,6 +522,8 @@ protected:
OPT_PTR(infill_only_where_needed); OPT_PTR(infill_only_where_needed);
OPT_PTR(interface_shells); OPT_PTR(interface_shells);
OPT_PTR(layer_height); OPT_PTR(layer_height);
OPT_PTR(raft_first_layer_density);
OPT_PTR(raft_first_layer_expansion);
OPT_PTR(raft_layers); OPT_PTR(raft_layers);
OPT_PTR(seam_position); OPT_PTR(seam_position);
OPT_PTR(slice_closing_radius); OPT_PTR(slice_closing_radius);

View file

@ -576,6 +576,8 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "support_material_synchronize_layers" || opt_key == "support_material_synchronize_layers"
|| opt_key == "support_material_threshold" || opt_key == "support_material_threshold"
|| opt_key == "support_material_with_sheath" || opt_key == "support_material_with_sheath"
|| opt_key == "raft_first_layer_density"
|| opt_key == "raft_first_layer_expansion"
|| opt_key == "dont_support_bridges" || opt_key == "dont_support_bridges"
|| opt_key == "first_layer_extrusion_width") { || opt_key == "first_layer_extrusion_width") {
steps.emplace_back(posSupportMaterial); steps.emplace_back(posSupportMaterial);

View file

@ -2536,7 +2536,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_raf
// How much to inflate the support columns to be stable. This also applies to the 1st layer, if no raft layers are to be printed. // How much to inflate the support columns to be stable. This also applies to the 1st layer, if no raft layers are to be printed.
const float inflate_factor_fine = float(scale_((m_slicing_params.raft_layers() > 1) ? 0.5 : EPSILON)); const float inflate_factor_fine = float(scale_((m_slicing_params.raft_layers() > 1) ? 0.5 : EPSILON));
const float inflate_factor_1st_layer = float(scale_(3.)) - inflate_factor_fine; const float inflate_factor_1st_layer = std::max(0.f, float(scale_(object.config().raft_first_layer_expansion)) - inflate_factor_fine);
MyLayer *contacts = top_contacts .empty() ? nullptr : top_contacts .front(); MyLayer *contacts = top_contacts .empty() ? nullptr : top_contacts .front();
MyLayer *interfaces = interface_layers.empty() ? nullptr : interface_layers.front(); MyLayer *interfaces = interface_layers.empty() ? nullptr : interface_layers.front();
MyLayer *columns_base = base_layers .empty() ? nullptr : base_layers .front(); MyLayer *columns_base = base_layers .empty() ? nullptr : base_layers .front();
@ -2581,7 +2581,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_raf
new_layer.print_z = m_slicing_params.first_print_layer_height; new_layer.print_z = m_slicing_params.first_print_layer_height;
new_layer.height = m_slicing_params.first_print_layer_height; new_layer.height = m_slicing_params.first_print_layer_height;
new_layer.bottom_z = 0.; new_layer.bottom_z = 0.;
new_layer.polygons = offset(base, inflate_factor_1st_layer); new_layer.polygons = inflate_factor_1st_layer > 0 ? offset(base, inflate_factor_1st_layer) : base;
} }
// Insert the base layers. // Insert the base layers.
for (size_t i = 1; i < m_slicing_params.base_raft_layers; ++ i) { for (size_t i = 1; i < m_slicing_params.base_raft_layers; ++ i) {
@ -2608,7 +2608,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_raf
} else if (columns_base != nullptr) { } else if (columns_base != nullptr) {
// Expand the bases of the support columns in the 1st layer. // Expand the bases of the support columns in the 1st layer.
columns_base->polygons = diff( columns_base->polygons = diff(
offset(columns_base->polygons, inflate_factor_1st_layer), inflate_factor_1st_layer > 0 ? offset(columns_base->polygons, inflate_factor_1st_layer) : columns_base->polygons,
offset(m_object->layers().front()->lslices, (float)scale_(m_gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS)); offset(m_object->layers().front()->lslices, (float)scale_(m_gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS));
if (contacts != nullptr) if (contacts != nullptr)
columns_base->polygons = diff(columns_base->polygons, interface_polygons); columns_base->polygons = diff(columns_base->polygons, interface_polygons);
@ -2754,6 +2754,41 @@ std::pair<PrintObjectSupportMaterial::MyLayersPtr, PrintObjectSupportMaterial::M
return base_and_interface_layers; return base_and_interface_layers;
} }
static inline void fill_expolygon_generate_paths(
ExtrusionEntitiesPtr &dst,
ExPolygon &&expolygon,
Fill *filler,
const FillParams &fill_params,
float density,
ExtrusionRole role,
const Flow &flow)
{
Surface surface(stInternal, std::move(expolygon));
Polylines polylines;
try {
polylines = filler->fill_surface(&surface, fill_params);
} catch (InfillFailedException &) {
}
extrusion_entities_append_paths(
dst,
std::move(polylines),
role,
flow.mm3_per_mm(), flow.width, flow.height);
}
static inline void fill_expolygons_generate_paths(
ExtrusionEntitiesPtr &dst,
ExPolygons &&expolygons,
Fill *filler,
const FillParams &fill_params,
float density,
ExtrusionRole role,
const Flow &flow)
{
for (ExPolygon &expoly : expolygons)
fill_expolygon_generate_paths(dst, std::move(expoly), filler, fill_params, density, role, flow);
}
static inline void fill_expolygons_generate_paths( static inline void fill_expolygons_generate_paths(
ExtrusionEntitiesPtr &dst, ExtrusionEntitiesPtr &dst,
ExPolygons &&expolygons, ExPolygons &&expolygons,
@ -2763,20 +2798,53 @@ static inline void fill_expolygons_generate_paths(
const Flow &flow) const Flow &flow)
{ {
FillParams fill_params; FillParams fill_params;
fill_params.density = density; fill_params.density = density;
fill_params.dont_adjust = true; fill_params.dont_adjust = true;
for (ExPolygon &expoly : expolygons) { fill_expolygons_generate_paths(dst, std::move(expolygons), filler, fill_params, density, role, flow);
Surface surface(stInternal, std::move(expoly)); }
static inline void fill_expolygons_with_sheath_generate_paths(
ExtrusionEntitiesPtr &dst,
const Polygons &polygons,
Fill *filler,
float density,
ExtrusionRole role,
const Flow &flow,
bool with_sheath)
{
if (polygons.empty())
return;
if (! with_sheath) {
fill_expolygons_generate_paths(dst, offset2_ex(polygons, float(SCALED_EPSILON), float(- SCALED_EPSILON)), filler, density, role, flow);
return;
}
FillParams fill_params;
fill_params.density = density;
fill_params.dont_adjust = true;
double spacing = flow.scaled_spacing();
// Clip the sheath path to avoid the extruder to get exactly on the first point of the loop.
double clip_length = spacing * 0.15;
for (ExPolygon &expoly : offset2_ex(polygons, float(SCALED_EPSILON), float(- SCALED_EPSILON - 0.5*flow.scaled_width()))) {
// Don't reorder the skirt and its infills.
auto eec = std::make_unique<ExtrusionEntityCollection>();
eec->no_sort = true;
// Draw the perimeters.
Polylines polylines; Polylines polylines;
try { polylines.reserve(expoly.holes.size() + 1);
polylines = filler->fill_surface(&surface, fill_params); for (size_t i = 0; i <= expoly.holes.size(); ++ i) {
} catch (InfillFailedException &) { Polyline pl(i == 0 ? expoly.contour.points : expoly.holes[i - 1].points);
} pl.points.emplace_back(pl.points.front());
extrusion_entities_append_paths( pl.clip_end(clip_length);
dst, polylines.emplace_back(std::move(pl));
std::move(polylines), }
role, extrusion_entities_append_paths(eec->entities, polylines, erSupportMaterial, flow.mm3_per_mm(), flow.width, flow.height);
flow.mm3_per_mm(), flow.width, flow.height); // Fill in the rest.
fill_expolygons_generate_paths(eec->entities, offset_ex(expoly, float(-0.4 * spacing)), filler, fill_params, density, role, flow);
dst.emplace_back(eec.release());
} }
} }
@ -3430,45 +3498,26 @@ void PrintObjectSupportMaterial::generate_toolpaths(
// Print the support base below the support columns, or the support base for the support columns plus the contacts. // Print the support base below the support columns, or the support base for the support columns plus the contacts.
if (support_layer_id > 0) { if (support_layer_id > 0) {
Polygons to_infill_polygons = (support_layer_id < m_slicing_params.base_raft_layers) ? const Polygons &to_infill_polygons = (support_layer_id < m_slicing_params.base_raft_layers) ?
raft_layer.polygons : raft_layer.polygons :
//FIXME misusing contact_polygons for support columns. //FIXME misusing contact_polygons for support columns.
((raft_layer.contact_polygons == nullptr) ? Polygons() : *raft_layer.contact_polygons); ((raft_layer.contact_polygons == nullptr) ? Polygons() : *raft_layer.contact_polygons);
if (! to_infill_polygons.empty()) { if (! to_infill_polygons.empty()) {
Flow flow(float(m_support_material_flow.width), float(raft_layer.height), m_support_material_flow.nozzle_diameter, raft_layer.bridging); Flow flow(float(m_support_material_flow.width), float(raft_layer.height), m_support_material_flow.nozzle_diameter, raft_layer.bridging);
// find centerline of the external loop/extrusions Fill * filler = filler_support.get();
ExPolygons to_infill = (support_layer_id == 0 || ! with_sheath) ? filler->angle = raft_angle_base;
// union_ex(base_polygons, true) : filler->spacing = m_support_material_flow.spacing();
offset2_ex(to_infill_polygons, float(SCALED_EPSILON), float(- SCALED_EPSILON)) : filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_density));
offset2_ex(to_infill_polygons, float(SCALED_EPSILON), float(- SCALED_EPSILON - 0.5*flow.scaled_width())); fill_expolygons_with_sheath_generate_paths(
if (! to_infill.empty() && with_sheath) { // Destination
// Draw a perimeter all around the support infill. This makes the support stable, but difficult to remove. support_layer.support_fills.entities,
// TODO: use brim ordering algorithm // Regions to fill
to_infill_polygons = to_polygons(to_infill); to_infill_polygons,
// TODO: use offset2_ex() // Filler and its parameters
to_infill = offset_ex(to_infill, float(- 0.4 * flow.scaled_spacing())); filler, float(support_density),
extrusion_entities_append_paths( // Extrusion parameters
support_layer.support_fills.entities, erSupportMaterial, flow,
to_polylines(std::move(to_infill_polygons)), with_sheath);
erSupportMaterial, flow.mm3_per_mm(), flow.width, flow.height);
}
if (! to_infill.empty()) {
// We don't use $base_flow->spacing because we need a constant spacing
// value that guarantees that all layers are correctly aligned.
Fill *filler = filler_support.get();
filler->angle = raft_angle_base;
filler->spacing = m_support_material_flow.spacing();
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_density));
fill_expolygons_generate_paths(
// Destination
support_layer.support_fills.entities,
// Regions to fill
std::move(to_infill),
// Filler and its parameters
filler, float(support_density),
// Extrusion parameters
erSupportMaterial, flow);
}
} }
} }
@ -3526,12 +3575,21 @@ void PrintObjectSupportMaterial::generate_toolpaths(
size_t idx_layer_bottom_contact = size_t(-1); size_t idx_layer_bottom_contact = size_t(-1);
size_t idx_layer_top_contact = size_t(-1); size_t idx_layer_top_contact = size_t(-1);
size_t idx_layer_intermediate = size_t(-1); size_t idx_layer_intermediate = size_t(-1);
size_t idx_layer_interface = size_t(-1); size_t idx_layer_interface = size_t(-1);
size_t idx_layer_base_interface = size_t(-1); size_t idx_layer_base_interface = size_t(-1);
auto filler_interface = std::unique_ptr<Fill>(Fill::new_from_type(m_slicing_params.soluble_interface ? ipConcentric : ipRectilinear)); const auto fill_type_interface = m_slicing_params.soluble_interface ? ipConcentric : ipRectilinear;
const auto fill_type_first_layer = ipRectilinear;
auto filler_interface = std::unique_ptr<Fill>(Fill::new_from_type(fill_type_interface));
// Filler for the 1st layer interface, if different from filler_interface.
auto filler_first_layer_ptr = std::unique_ptr<Fill>(range.begin() == 0 && fill_type_interface != fill_type_first_layer ? Fill::new_from_type(fill_type_first_layer) : nullptr);
// Pointer to the 1st layer interface filler.
auto filler_first_layer = filler_first_layer_ptr ? filler_first_layer_ptr.get() : filler_interface.get();
// Filler for the base interface (to be used for soluble interface / non soluble base, to produce non soluble interface layer below soluble interface layer).
auto filler_base_interface = std::unique_ptr<Fill>(base_interface_layers.empty() ? nullptr : Fill::new_from_type(ipRectilinear)); auto filler_base_interface = std::unique_ptr<Fill>(base_interface_layers.empty() ? nullptr : Fill::new_from_type(ipRectilinear));
auto filler_support = std::unique_ptr<Fill>(Fill::new_from_type(infill_pattern)); auto filler_support = std::unique_ptr<Fill>(Fill::new_from_type(infill_pattern));
filler_interface->set_bounding_box(bbox_object); filler_interface->set_bounding_box(bbox_object);
if (filler_first_layer_ptr)
filler_first_layer_ptr->set_bounding_box(bbox_object);
if (filler_base_interface) if (filler_base_interface)
filler_base_interface->set_bounding_box(bbox_object); filler_base_interface->set_bounding_box(bbox_object);
filler_support->set_bounding_box(bbox_object); filler_support->set_bounding_box(bbox_object);
@ -3656,7 +3714,6 @@ void PrintObjectSupportMaterial::generate_toolpaths(
// Base support or flange. // Base support or flange.
if (! base_layer.empty() && ! base_layer.polygons_to_extrude().empty()) { if (! base_layer.empty() && ! base_layer.polygons_to_extrude().empty()) {
//FIXME When paralellizing, each thread shall have its own copy of the fillers.
Fill *filler = filler_support.get(); Fill *filler = filler_support.get();
filler->angle = angles[support_layer_id % angles.size()]; filler->angle = angles[support_layer_id % 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
@ -3669,42 +3726,31 @@ void PrintObjectSupportMaterial::generate_toolpaths(
filler->spacing = m_support_material_flow.spacing(); filler->spacing = m_support_material_flow.spacing();
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_density)); filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_density));
float density = float(support_density); float density = float(support_density);
// find centerline of the external loop/extrusions bool sheath = with_sheath;
ExPolygons to_infill = (support_layer_id == 0 || ! with_sheath) ?
// union_ex(base_polygons, true) :
offset2_ex(base_layer.polygons_to_extrude(), float(SCALED_EPSILON), float(- SCALED_EPSILON)) :
offset2_ex(base_layer.polygons_to_extrude(), float(SCALED_EPSILON), float(- SCALED_EPSILON - 0.5*flow.scaled_width()));
if (base_layer.layer->bottom_z < EPSILON) { if (base_layer.layer->bottom_z < EPSILON) {
// Base flange (the 1st layer). // Base flange (the 1st layer).
filler = filler_interface.get(); filler = filler_first_layer;
filler->angle = Geometry::deg2rad(float(m_object_config->support_material_angle.value + 90.)); filler->angle = Geometry::deg2rad(float(m_object_config->support_material_angle.value + 90.));
density = 0.5f; density = float(m_object_config->raft_first_layer_density.value * 0.01);
flow = m_first_layer_flow; flow = m_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
//FIXME When paralellizing, each thread shall have its own copy of the fillers. //FIXME When paralellizing, each thread shall have its own copy of the fillers.
filler->spacing = flow.spacing(); filler->spacing = flow.spacing();
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density)); filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density));
} else if (with_sheath) { sheath = true;
// Draw a perimeter all around the support infill. This makes the support stable, but difficult to remove.
// TODO: use brim ordering algorithm
Polygons to_infill_polygons = to_polygons(to_infill);
// TODO: use offset2_ex()
to_infill = offset_ex(to_infill, - 0.4f * float(flow.scaled_spacing()));
extrusion_entities_append_paths(
base_layer.extrusions,
to_polylines(std::move(to_infill_polygons)),
erSupportMaterial, flow.mm3_per_mm(), flow.width, flow.height);
} }
fill_expolygons_generate_paths( fill_expolygons_with_sheath_generate_paths(
// Destination // Destination
base_layer.extrusions, base_layer.extrusions,
// Regions to fill // Regions to fill
std::move(to_infill), base_layer.polygons_to_extrude(),
// Filler and its parameters // Filler and its parameters
filler, density, filler, density,
// Extrusion parameters // Extrusion parameters
erSupportMaterial, flow); erSupportMaterial, flow,
sheath);
} }
// Merge base_interface_layers to base_layers to avoid unneccessary retractions // Merge base_interface_layers to base_layers to avoid unneccessary retractions

View file

@ -1499,6 +1499,8 @@ void TabPrint::build()
optgroup = page->new_optgroup(L("Raft")); optgroup = page->new_optgroup(L("Raft"));
optgroup->append_single_option_line("raft_layers", category_path + "raft-layers"); optgroup->append_single_option_line("raft_layers", category_path + "raft-layers");
optgroup->append_single_option_line("raft_first_layer_density", category_path + "raft-first-layer-density");
optgroup->append_single_option_line("raft_first_layer_expansion", category_path + "raft-first-layer-expansion");
// # optgroup->append_single_option_line(get_option_("raft_contact_distance"); // # optgroup->append_single_option_line(get_option_("raft_contact_distance");
optgroup = page->new_optgroup(L("Options for support material and raft")); optgroup = page->new_optgroup(L("Options for support material and raft"));