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

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

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. 
Fixes raft is larger than necessary 
Fixes Supports on the build plate should have a solid bottom interface for better adhesion 

Changed the 1st layer infill to rectilinear even for soluble materials.
Fixes first layer of support for multi filament support oddly spaced 
Fixes Full Soluble Materials interfacing into Models + Soluble material noise on Bed 
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"));