Merge branch 'dev' of https://github.com/prusa3d/PrusaSlicer into et_reload_from_disk
This commit is contained in:
commit
b383d9581a
25 changed files with 244 additions and 149 deletions
|
@ -350,6 +350,12 @@ public:
|
|||
m_pck.configure(m_pconf);
|
||||
}
|
||||
|
||||
AutoArranger(const TBin & bin,
|
||||
std::function<void(unsigned)> progressind,
|
||||
std::function<bool(void)> stopcond)
|
||||
: AutoArranger{bin, 0 /* no min distance */, progressind, stopcond}
|
||||
{}
|
||||
|
||||
template<class It> inline void operator()(It from, It to) {
|
||||
m_rtree.clear();
|
||||
m_item_count += size_t(to - from);
|
||||
|
@ -553,13 +559,21 @@ BedShapeHint &BedShapeHint::operator=(const BedShapeHint &cpy)
|
|||
return *this;
|
||||
}
|
||||
|
||||
template<class Bin> void remove_large_items(std::vector<Item> &items, Bin &&bin)
|
||||
{
|
||||
auto it = items.begin();
|
||||
while (it != items.end())
|
||||
sl::isInside(it->transformedShape(), bin) ?
|
||||
++it : it = items.erase(it);
|
||||
}
|
||||
|
||||
template<class BinT> // Arrange for arbitrary bin type
|
||||
void _arrange(
|
||||
std::vector<Item> & shapes,
|
||||
std::vector<Item> & excludes,
|
||||
const BinT & bin,
|
||||
coord_t minobjd,
|
||||
std::function<void(unsigned)> prind,
|
||||
std::function<void(unsigned)> progressfn,
|
||||
std::function<bool()> stopfn)
|
||||
{
|
||||
// Integer ceiling the min distance from the bed perimeters
|
||||
|
@ -569,16 +583,13 @@ void _arrange(
|
|||
auto corrected_bin = bin;
|
||||
sl::offset(corrected_bin, md);
|
||||
|
||||
AutoArranger<BinT> arranger{corrected_bin, 0, prind, stopfn};
|
||||
AutoArranger<BinT> arranger{corrected_bin, progressfn, stopfn};
|
||||
|
||||
auto infl = coord_t(std::ceil(minobjd / 2.0));
|
||||
for (Item& itm : shapes) itm.inflate(infl);
|
||||
for (Item& itm : excludes) itm.inflate(infl);
|
||||
|
||||
auto it = excludes.begin();
|
||||
while (it != excludes.end())
|
||||
sl::isInside(it->transformedShape(), corrected_bin) ?
|
||||
++it : it = excludes.erase(it);
|
||||
remove_large_items(excludes, corrected_bin);
|
||||
|
||||
// If there is something on the plate
|
||||
if (!excludes.empty()) arranger.preload(excludes);
|
||||
|
@ -674,7 +685,7 @@ void arrange(ArrangePolygons & arrangables,
|
|||
_arrange(items, fixeditems, Box::infinite(), min_obj_dist, pri, cfn);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < items.size(); ++i) {
|
||||
clppr::IntPoint tr = items[i].translation();
|
||||
|
|
|
@ -116,7 +116,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
|||
has_internal_voids = true;
|
||||
else {
|
||||
FlowRole extrusion_role = (surface.surface_type == stTop) ? frTopSolidInfill : (surface.is_solid() ? frSolidInfill : frInfill);
|
||||
bool is_bridge = layerm.layer()->id() > 0 && surface.is_bridge();
|
||||
bool is_bridge = layer.id() > 0 && surface.is_bridge();
|
||||
params.extruder = layerm.region()->extruder(extrusion_role);
|
||||
params.pattern = layerm.region()->config().fill_pattern.value;
|
||||
params.density = float(layerm.region()->config().fill_density);
|
||||
|
@ -141,11 +141,11 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
|||
// calculate the actual flow we'll be using for this infill
|
||||
params.flow = layerm.region()->flow(
|
||||
extrusion_role,
|
||||
(surface.thickness == -1) ? layerm.layer()->height : surface.thickness, // extrusion height
|
||||
is_bridge || Fill::use_bridge_flow(params.pattern), // bridge flow?
|
||||
layerm.layer()->id() == 0, // first layer?
|
||||
-1, // auto width
|
||||
*layerm.layer()->object()
|
||||
(surface.thickness == -1) ? layer.height : surface.thickness, // extrusion height
|
||||
is_bridge || Fill::use_bridge_flow(params.pattern), // bridge flow?
|
||||
layer.id() == 0, // first layer?
|
||||
-1, // auto width
|
||||
*layer.object()
|
||||
);
|
||||
|
||||
// Calculate flow spacing for infill pattern generation.
|
||||
|
@ -156,7 +156,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
|||
// layer height
|
||||
params.spacing = layerm.region()->flow(
|
||||
frInfill,
|
||||
layerm.layer()->object()->config().layer_height.value, // TODO: handle infill_every_layers?
|
||||
layer.object()->config().layer_height.value, // TODO: handle infill_every_layers?
|
||||
false, // no bridge
|
||||
false, // no first layer
|
||||
-1, // auto width
|
||||
|
@ -199,12 +199,14 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
|||
Polygons all_polygons;
|
||||
for (SurfaceFill &fill : surface_fills)
|
||||
if (! fill.expolygons.empty()) {
|
||||
Polygons polys = to_polygons(std::move(fill.expolygons));
|
||||
if (fill.expolygons.size() > 1 || ! all_polygons.empty())
|
||||
if (fill.expolygons.size() > 1 || ! all_polygons.empty()) {
|
||||
Polygons polys = to_polygons(std::move(fill.expolygons));
|
||||
// Make a union of polygons, use a safety offset, subtract the preceding polygons.
|
||||
// Bridges are processed first (see SurfaceFill::operator<())
|
||||
fill.expolygons = all_polygons.empty() ? union_ex(polys, true) : diff_ex(polys, all_polygons, true);
|
||||
append(all_polygons, std::move(polys));
|
||||
append(all_polygons, std::move(polys));
|
||||
} else if (&fill != &surface_fills.back())
|
||||
append(all_polygons, to_polygons(fill.expolygons));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -259,7 +261,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
|||
region_id = region_some_infill;
|
||||
const LayerRegion& layerm = *layer.regions()[region_id];
|
||||
for (SurfaceFill &surface_fill : surface_fills)
|
||||
if (surface_fill.surface.surface_type == stInternalSolid && std::abs(layerm.layer()->height - surface_fill.params.flow.height) < EPSILON) {
|
||||
if (surface_fill.surface.surface_type == stInternalSolid && std::abs(layer.height - surface_fill.params.flow.height) < EPSILON) {
|
||||
internal_solid_fill = &surface_fill;
|
||||
break;
|
||||
}
|
||||
|
@ -273,10 +275,10 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
|||
// calculate the actual flow we'll be using for this infill
|
||||
params.flow = layerm.region()->flow(
|
||||
frSolidInfill,
|
||||
layerm.layer()->height, // extrusion height
|
||||
false, // bridge flow?
|
||||
layerm.layer()->id() == 0, // first layer?
|
||||
-1, // auto width
|
||||
layer.height, // extrusion height
|
||||
false, // bridge flow?
|
||||
layer.id() == 0, // first layer?
|
||||
-1, // auto width
|
||||
*layer.object()
|
||||
);
|
||||
params.spacing = params.flow.spacing();
|
||||
|
@ -294,15 +296,48 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
|||
return surface_fills;
|
||||
}
|
||||
|
||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||
void export_group_fills_to_svg(const char *path, const std::vector<SurfaceFill> &fills)
|
||||
{
|
||||
BoundingBox bbox;
|
||||
for (const auto &fill : fills)
|
||||
for (const auto &expoly : fill.expolygons)
|
||||
bbox.merge(get_extents(expoly));
|
||||
Point legend_size = export_surface_type_legend_to_svg_box_size();
|
||||
Point legend_pos(bbox.min(0), bbox.max(1));
|
||||
bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1)));
|
||||
|
||||
SVG svg(path, bbox);
|
||||
const float transparency = 0.5f;
|
||||
for (const auto &fill : fills)
|
||||
for (const auto &expoly : fill.expolygons)
|
||||
svg.draw(expoly, surface_type_to_color_name(fill.surface.surface_type), transparency);
|
||||
export_surface_type_legend_to_svg(svg, legend_pos);
|
||||
svg.Close();
|
||||
}
|
||||
#endif
|
||||
|
||||
// friend to Layer
|
||||
void Layer::make_fills()
|
||||
{
|
||||
for (LayerRegion *layerm : m_regions)
|
||||
layerm->fills.clear();
|
||||
|
||||
|
||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||
// this->export_region_fill_surfaces_to_svg_debug("10_fill-initial");
|
||||
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||
|
||||
std::vector<SurfaceFill> surface_fills = group_fills(*this);
|
||||
const Slic3r::BoundingBox bbox = this->object()->bounding_box();
|
||||
|
||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||
{
|
||||
static int iRun = 0;
|
||||
export_group_fills_to_svg(debug_out_path("Layer-fill_surfaces-10_fill-final-%d.svg", iRun ++).c_str(), surface_fills);
|
||||
}
|
||||
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||
|
||||
for (SurfaceFill &surface_fill : surface_fills) {
|
||||
// Create the filler object.
|
||||
std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(surface_fill.params.pattern));
|
||||
|
|
|
@ -329,6 +329,28 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_
|
|||
}
|
||||
}
|
||||
|
||||
// If the model contains empty layers (such as https://github.com/prusa3d/Slic3r/issues/1266), there might be layers
|
||||
// that were not marked as has_wipe_tower, even when they should have been. This produces a crash with soluble supports
|
||||
// and maybe other problems. We will therefore go through layer_tools and detect and fix this.
|
||||
// So, if there is a non-object layer starting with different extruder than the last one ended with (or containing more than one extruder),
|
||||
// we'll mark it with has_wipe tower.
|
||||
for (unsigned int i=0; i+1<m_layer_tools.size(); ++i) {
|
||||
LayerTools& lt = m_layer_tools[i];
|
||||
LayerTools& lt_next = m_layer_tools[i+1];
|
||||
if (lt.extruders.empty() || lt_next.extruders.empty())
|
||||
break;
|
||||
if (!lt_next.has_wipe_tower && (lt_next.extruders.front() != lt.extruders.back() || lt_next.extruders.size() > 1))
|
||||
lt_next.has_wipe_tower = true;
|
||||
// We should also check that the next wipe tower layer is no further than max_layer_height:
|
||||
unsigned int j = i+1;
|
||||
double last_wipe_tower_print_z = lt_next.print_z;
|
||||
while (++j < m_layer_tools.size()-1 && !m_layer_tools[j].has_wipe_tower)
|
||||
if (m_layer_tools[j+1].print_z - last_wipe_tower_print_z > max_layer_height) {
|
||||
m_layer_tools[j].has_wipe_tower = true;
|
||||
last_wipe_tower_print_z = m_layer_tools[j].print_z;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the wipe_tower_layer_height values.
|
||||
coordf_t wipe_tower_print_z_last = 0.;
|
||||
for (LayerTools < : m_layer_tools)
|
||||
|
|
|
@ -82,7 +82,7 @@ public:
|
|||
}
|
||||
|
||||
WipeTowerWriter& change_analyzer_mm3_per_mm(float len, float e) {
|
||||
static const float area = M_PI * 1.75f * 1.75f / 4.f;
|
||||
static const float area = float(M_PI) * 1.75f * 1.75f / 4.f;
|
||||
float mm3_per_mm = (len == 0.f ? 0.f : area * e / len);
|
||||
// adds tag for analyzer:
|
||||
char buf[64];
|
||||
|
@ -100,7 +100,7 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
WipeTowerWriter& set_initial_tool(const unsigned int tool) { m_current_tool = tool; return *this; }
|
||||
WipeTowerWriter& set_initial_tool(size_t tool) { m_current_tool = tool; return *this; }
|
||||
|
||||
WipeTowerWriter& set_z(float z)
|
||||
{ m_current_z = z; return *this; }
|
||||
|
@ -311,7 +311,7 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
WipeTowerWriter& set_tool(unsigned tool)
|
||||
WipeTowerWriter& set_tool(size_t tool)
|
||||
{
|
||||
m_current_tool = tool;
|
||||
return *this;
|
||||
|
@ -406,7 +406,7 @@ private:
|
|||
Vec2f m_current_pos;
|
||||
float m_current_z;
|
||||
float m_current_feedrate;
|
||||
unsigned int m_current_tool;
|
||||
size_t m_current_tool;
|
||||
float m_layer_height;
|
||||
float m_extrusion_flow;
|
||||
bool m_preview_suppressed;
|
||||
|
@ -417,7 +417,7 @@ private:
|
|||
float m_y_shift = 0.f;
|
||||
float m_wipe_tower_width = 0.f;
|
||||
float m_wipe_tower_depth = 0.f;
|
||||
unsigned m_last_fan_speed = 0.f;
|
||||
unsigned m_last_fan_speed = 0;
|
||||
int current_temp = -1;
|
||||
const float m_default_analyzer_line_width;
|
||||
float m_used_filament_length = 0.f;
|
||||
|
@ -568,7 +568,7 @@ std::vector<WipeTower::ToolChangeResult> WipeTower::prime(
|
|||
|
||||
// Iterate over all priming toolchanges and push respective ToolChangeResults into results vector.
|
||||
for (size_t idx_tool = 0; idx_tool < tools.size(); ++ idx_tool) {
|
||||
int old_tool = m_current_tool;
|
||||
size_t old_tool = m_current_tool;
|
||||
|
||||
WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar);
|
||||
writer.set_extrusion_flow(m_extrusion_flow)
|
||||
|
@ -617,8 +617,8 @@ std::vector<WipeTower::ToolChangeResult> WipeTower::prime(
|
|||
|
||||
ToolChangeResult result;
|
||||
result.priming = true;
|
||||
result.initial_tool = old_tool;
|
||||
result.new_tool = m_current_tool;
|
||||
result.initial_tool = int(old_tool);
|
||||
result.new_tool = int(m_current_tool);
|
||||
result.print_z = this->m_z_pos;
|
||||
result.layer_height = this->m_layer_height;
|
||||
result.gcode = writer.gcode();
|
||||
|
@ -653,12 +653,12 @@ std::vector<WipeTower::ToolChangeResult> WipeTower::prime(
|
|||
return results;
|
||||
}
|
||||
|
||||
WipeTower::ToolChangeResult WipeTower::tool_change(unsigned int tool, bool last_in_layer)
|
||||
WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool last_in_layer)
|
||||
{
|
||||
if ( m_print_brim )
|
||||
return toolchange_Brim();
|
||||
|
||||
int old_tool = m_current_tool;
|
||||
size_t old_tool = m_current_tool;
|
||||
|
||||
float wipe_area = 0.f;
|
||||
bool last_change_in_layer = false;
|
||||
|
@ -751,8 +751,8 @@ WipeTower::ToolChangeResult WipeTower::tool_change(unsigned int tool, bool last_
|
|||
|
||||
ToolChangeResult result;
|
||||
result.priming = false;
|
||||
result.initial_tool = old_tool;
|
||||
result.new_tool = m_current_tool;
|
||||
result.initial_tool = int(old_tool);
|
||||
result.new_tool = int(m_current_tool);
|
||||
result.print_z = this->m_z_pos;
|
||||
result.layer_height = this->m_layer_height;
|
||||
result.gcode = writer.gcode();
|
||||
|
@ -765,7 +765,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(unsigned int tool, bool last_
|
|||
|
||||
WipeTower::ToolChangeResult WipeTower::toolchange_Brim(bool sideOnly, float y_offset)
|
||||
{
|
||||
int old_tool = m_current_tool;
|
||||
size_t old_tool = m_current_tool;
|
||||
|
||||
const box_coordinates wipeTower_box(
|
||||
Vec2f::Zero(),
|
||||
|
@ -809,8 +809,8 @@ WipeTower::ToolChangeResult WipeTower::toolchange_Brim(bool sideOnly, float y_of
|
|||
|
||||
ToolChangeResult result;
|
||||
result.priming = false;
|
||||
result.initial_tool = old_tool;
|
||||
result.new_tool = m_current_tool;
|
||||
result.initial_tool = int(old_tool);
|
||||
result.new_tool = int(m_current_tool);
|
||||
result.print_z = this->m_z_pos;
|
||||
result.layer_height = this->m_layer_height;
|
||||
result.gcode = writer.gcode();
|
||||
|
@ -1115,7 +1115,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer()
|
|||
// Otherwise the caller would likely travel to the wipe tower in vain.
|
||||
assert(! this->layer_finished());
|
||||
|
||||
int old_tool = m_current_tool;
|
||||
size_t old_tool = m_current_tool;
|
||||
|
||||
WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar);
|
||||
writer.set_extrusion_flow(m_extrusion_flow)
|
||||
|
@ -1198,8 +1198,8 @@ WipeTower::ToolChangeResult WipeTower::finish_layer()
|
|||
|
||||
ToolChangeResult result;
|
||||
result.priming = false;
|
||||
result.initial_tool = old_tool;
|
||||
result.new_tool = m_current_tool;
|
||||
result.initial_tool = int(old_tool);
|
||||
result.new_tool = int(m_current_tool);
|
||||
result.print_z = this->m_z_pos;
|
||||
result.layer_height = this->m_layer_height;
|
||||
result.gcode = writer.gcode();
|
||||
|
|
|
@ -148,7 +148,7 @@ public:
|
|||
|
||||
// Returns gcode for a toolchange and a final print head position.
|
||||
// On the first layer, extrude a brim around the future wipe tower first.
|
||||
ToolChangeResult tool_change(unsigned int new_tool, bool last_in_layer);
|
||||
ToolChangeResult tool_change(size_t new_tool, bool last_in_layer);
|
||||
|
||||
// Fill the unfilled space with a sparse infill.
|
||||
// Call this method only if layer_finished() is false.
|
||||
|
@ -194,7 +194,7 @@ private:
|
|||
const bool m_peters_wipe_tower = false; // sparse wipe tower inspired by Peter's post processor - not finished yet
|
||||
const float Width_To_Nozzle_Ratio = 1.25f; // desired line width (oval) in multiples of nozzle diameter - may not be actually neccessary to adjust
|
||||
const float WT_EPSILON = 1e-3f;
|
||||
const float filament_area() const {
|
||||
float filament_area() const {
|
||||
return m_filpar[0].filament_area; // all extruders are assumed to have the same filament diameter at this point
|
||||
}
|
||||
|
||||
|
|
|
@ -121,7 +121,6 @@ void Layer::make_perimeters()
|
|||
for (LayerRegionPtrs::const_iterator it = layerm + 1; it != m_regions.end(); ++it) {
|
||||
LayerRegion* other_layerm = *it;
|
||||
const PrintRegionConfig &other_config = other_layerm->region()->config();
|
||||
|
||||
if (config.perimeter_extruder == other_config.perimeter_extruder
|
||||
&& config.perimeters == other_config.perimeters
|
||||
&& config.perimeter_speed == other_config.perimeter_speed
|
||||
|
@ -130,7 +129,8 @@ void Layer::make_perimeters()
|
|||
&& config.overhangs == other_config.overhangs
|
||||
&& config.opt_serialize("perimeter_extrusion_width") == other_config.opt_serialize("perimeter_extrusion_width")
|
||||
&& config.thin_walls == other_config.thin_walls
|
||||
&& config.external_perimeters_first == other_config.external_perimeters_first) {
|
||||
&& config.external_perimeters_first == other_config.external_perimeters_first
|
||||
&& config.infill_overlap == other_config.infill_overlap) {
|
||||
layerms.push_back(other_layerm);
|
||||
done[it - m_regions.begin()] = true;
|
||||
}
|
||||
|
@ -142,12 +142,17 @@ void Layer::make_perimeters()
|
|||
(*layerm)->fill_expolygons = to_expolygons((*layerm)->fill_surfaces.surfaces);
|
||||
} else {
|
||||
SurfaceCollection new_slices;
|
||||
// Use the region with highest infill rate, as the make_perimeters() function below decides on the gap fill based on the infill existence.
|
||||
LayerRegion *layerm_config = layerms.front();
|
||||
{
|
||||
// group slices (surfaces) according to number of extra perimeters
|
||||
std::map<unsigned short, Surfaces> slices; // extra_perimeters => [ surface, surface... ]
|
||||
for (LayerRegion *layerm : layerms)
|
||||
for (LayerRegion *layerm : layerms) {
|
||||
for (Surface &surface : layerm->slices.surfaces)
|
||||
slices[surface.extra_perimeters].emplace_back(surface);
|
||||
if (layerm->region()->config().fill_density > layerm_config->region()->config().fill_density)
|
||||
layerm_config = layerm;
|
||||
}
|
||||
// merge the surfaces assigned to each group
|
||||
for (std::pair<const unsigned short,Surfaces> &surfaces_with_extra_perimeters : slices)
|
||||
new_slices.append(union_ex(surfaces_with_extra_perimeters.second, true), surfaces_with_extra_perimeters.second.front());
|
||||
|
@ -155,7 +160,7 @@ void Layer::make_perimeters()
|
|||
|
||||
// make perimeters
|
||||
SurfaceCollection fill_surfaces;
|
||||
(*layerm)->make_perimeters(new_slices, &fill_surfaces);
|
||||
layerm_config->make_perimeters(new_slices, &fill_surfaces);
|
||||
|
||||
// assign fill_surfaces to each layer
|
||||
if (!fill_surfaces.surfaces.empty()) {
|
||||
|
|
|
@ -365,26 +365,23 @@ void LayerRegion::prepare_fill_surfaces()
|
|||
|
||||
// if no solid layers are requested, turn top/bottom surfaces to internal
|
||||
if (this->region()->config().top_solid_layers == 0) {
|
||||
for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface)
|
||||
if (surface->surface_type == stTop)
|
||||
surface->surface_type = (this->layer()->object()->config().infill_only_where_needed) ?
|
||||
stInternalVoid : stInternal;
|
||||
for (Surface &surface : this->fill_surfaces.surfaces)
|
||||
if (surface.is_top())
|
||||
surface.surface_type = this->layer()->object()->config().infill_only_where_needed ? stInternalVoid : stInternal;
|
||||
}
|
||||
if (this->region()->config().bottom_solid_layers == 0) {
|
||||
for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) {
|
||||
if (surface->surface_type == stBottom || surface->surface_type == stBottomBridge)
|
||||
surface->surface_type = stInternal;
|
||||
}
|
||||
for (Surface &surface : this->fill_surfaces.surfaces)
|
||||
if (surface.is_bottom()) // (surface.surface_type == stBottom)
|
||||
surface.surface_type = stInternal;
|
||||
}
|
||||
|
||||
|
||||
// turn too small internal regions into solid regions according to the user setting
|
||||
if (this->region()->config().fill_density.value > 0) {
|
||||
// scaling an area requires two calls!
|
||||
double min_area = scale_(scale_(this->region()->config().solid_infill_below_area.value));
|
||||
for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) {
|
||||
if (surface->surface_type == stInternal && surface->area() <= min_area)
|
||||
surface->surface_type = stInternalSolid;
|
||||
}
|
||||
for (Surface &surface : this->fill_surfaces.surfaces)
|
||||
if (surface.surface_type == stInternal && surface.area() <= min_area)
|
||||
surface.surface_type = stInternalSolid;
|
||||
}
|
||||
|
||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||
|
|
|
@ -37,7 +37,8 @@ void PerimeterGenerator::process()
|
|||
// internal flow which is unrelated.
|
||||
coord_t min_spacing = perimeter_spacing * (1 - INSET_OVERLAP_TOLERANCE);
|
||||
coord_t ext_min_spacing = ext_perimeter_spacing * (1 - INSET_OVERLAP_TOLERANCE);
|
||||
|
||||
bool has_gap_fill = this->config->gap_fill_speed.value > 0;
|
||||
|
||||
// prepare grown lower layer slices for overhang detection
|
||||
if (this->lower_slices != NULL && this->config->overhangs) {
|
||||
// We consider overhang any part where the entire nozzle diameter is not supported by the
|
||||
|
@ -105,7 +106,7 @@ void PerimeterGenerator::process()
|
|||
// leads to overflows, as in prusa3d/Slic3r GH #32
|
||||
offset_ex(last, - distance);
|
||||
// look for gaps
|
||||
if (this->config->gap_fill_speed.value > 0 && this->config->fill_density.value > 0)
|
||||
if (has_gap_fill)
|
||||
// not using safety offset here would "detect" very narrow gaps
|
||||
// (but still long enough to escape the area threshold) that gap fill
|
||||
// won't be able to fill but we'd still remove from infill area
|
||||
|
@ -132,6 +133,11 @@ void PerimeterGenerator::process()
|
|||
}
|
||||
}
|
||||
last = std::move(offsets);
|
||||
if (i == loop_number && (! has_gap_fill || this->config->fill_density.value == 0)) {
|
||||
// The last run of this loop is executed to collect gaps for gap fill.
|
||||
// As the gap fill is either disabled or not
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// nest loops: holes first
|
||||
|
|
|
@ -2894,7 +2894,7 @@ void DynamicPrintConfig::normalize()
|
|||
{
|
||||
this->opt<ConfigOptionInt>("perimeters", true)->value = 1;
|
||||
this->opt<ConfigOptionInt>("top_solid_layers", true)->value = 0;
|
||||
this->opt<ConfigOptionPercent>("fill_density", true)->value = 0;
|
||||
this->opt<ConfigOptionPercent>("fill_density", true)->value = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue