Port "Extend sparse infill" from Prusa (#2134)

* Remove BambuLab's implementation of solid infill bridging enhancement
, will use Prusa's instead

* Port "Extend sparse infill" from Prusa

* Improve anchoring by shifting the lines half-spacing

* Add missing fill patterns

* Improve anchoring by keeping fine details

* Make sure the opposite directions do not cancel each other

---------

Co-authored-by: Pavel Mikus <pavel.mikus.mail@seznam.cz>
This commit is contained in:
Noisyfox 2023-09-29 23:39:12 +08:00 committed by GitHub
parent 0e785c05e5
commit ee0e6a7227
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 1017 additions and 506 deletions

View file

@ -178,8 +178,6 @@ set(lisbslic3r_sources
Geometry/VoronoiUtilsCgal.hpp Geometry/VoronoiUtilsCgal.hpp
Geometry/VoronoiVisualUtils.hpp Geometry/VoronoiVisualUtils.hpp
Int128.hpp Int128.hpp
InternalBridgeDetector.cpp
InternalBridgeDetector.hpp
KDTreeIndirect.hpp KDTreeIndirect.hpp
Layer.cpp Layer.cpp
Layer.hpp Layer.hpp

View file

@ -1,3 +1,12 @@
///|/ Copyright (c) Prusa Research 2016 - 2023 Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv, Pavel Mikuš @Godrak, Lukáš Hejl @hejllukas
///|/ Copyright (c) SuperSlicer 2023 Remi Durand @supermerill
///|/ Copyright (c) 2016 Sakari Kapanen @Flannelhead
///|/ Copyright (c) Slic3r 2011 - 2015 Alessandro Ranellucci @alranel
///|/ Copyright (c) 2013 Mark Hindess
///|/ Copyright (c) 2011 Michael Moon
///|/
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
///|/
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <memory> #include <memory>
@ -46,8 +55,6 @@ struct SurfaceFillParams
// 1000mm is roughly the maximum length line that fits into a 32bit coord_t. // 1000mm is roughly the maximum length line that fits into a 32bit coord_t.
float anchor_length = 1000.f; float anchor_length = 1000.f;
float anchor_length_max = 1000.f; float anchor_length_max = 1000.f;
//BBS
bool with_loop = false;
// width, height of extrusion, nozzle diameter, is bridge // width, height of extrusion, nozzle diameter, is bridge
// For the output, for fill generator. // For the output, for fill generator.
@ -79,7 +86,6 @@ struct SurfaceFillParams
// RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_adjust); // RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_adjust);
RETURN_COMPARE_NON_EQUAL(anchor_length); RETURN_COMPARE_NON_EQUAL(anchor_length);
RETURN_COMPARE_NON_EQUAL(anchor_length_max); RETURN_COMPARE_NON_EQUAL(anchor_length_max);
RETURN_COMPARE_NON_EQUAL(with_loop);
RETURN_COMPARE_NON_EQUAL(flow.width()); RETURN_COMPARE_NON_EQUAL(flow.width());
RETURN_COMPARE_NON_EQUAL(flow.height()); RETURN_COMPARE_NON_EQUAL(flow.height());
RETURN_COMPARE_NON_EQUAL(flow.nozzle_diameter()); RETURN_COMPARE_NON_EQUAL(flow.nozzle_diameter());
@ -100,7 +106,6 @@ struct SurfaceFillParams
// this->dont_adjust == rhs.dont_adjust && // this->dont_adjust == rhs.dont_adjust &&
this->anchor_length == rhs.anchor_length && this->anchor_length == rhs.anchor_length &&
this->anchor_length_max == rhs.anchor_length_max && this->anchor_length_max == rhs.anchor_length_max &&
this->with_loop == rhs.with_loop &&
this->flow == rhs.flow && this->flow == rhs.flow &&
this->extrusion_role == rhs.extrusion_role; this->extrusion_role == rhs.extrusion_role;
} }
@ -151,8 +156,6 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
params.extruder = layerm.region().extruder(extrusion_role); params.extruder = layerm.region().extruder(extrusion_role);
params.pattern = region_config.sparse_infill_pattern.value; params.pattern = region_config.sparse_infill_pattern.value;
params.density = float(region_config.sparse_infill_density); params.density = float(region_config.sparse_infill_density);
//BBS
params.with_loop = surface.surface_type == stInternalWithLoop;
if (surface.is_solid()) { if (surface.is_solid()) {
params.density = 100.f; params.density = 100.f;
@ -501,7 +504,6 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
params.extrusion_role = surface_fill.params.extrusion_role; params.extrusion_role = surface_fill.params.extrusion_role;
params.using_internal_flow = using_internal_flow; params.using_internal_flow = using_internal_flow;
params.no_extrusion_overlap = surface_fill.params.overlap; params.no_extrusion_overlap = surface_fill.params.overlap;
params.with_loop = surface_fill.params.with_loop;
params.config = &layerm->region().config(); params.config = &layerm->region().config();
if (surface_fill.params.pattern == ipGrid) if (surface_fill.params.pattern == ipGrid)
params.can_reverse = false; params.can_reverse = false;
@ -540,6 +542,101 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
#endif #endif
} }
Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive::Octree* support_fill_octree, FillLightning::Generator* lightning_generator) const
{
std::vector<SurfaceFill> surface_fills = group_fills(*this);
const Slic3r::BoundingBox bbox = this->object()->bounding_box();
const auto resolution = this->object()->print()->config().resolution.value;
Polylines sparse_infill_polylines{};
for (SurfaceFill &surface_fill : surface_fills) {
if (surface_fill.surface.surface_type != stInternal) {
continue;
}
switch (surface_fill.params.pattern) {
case ipCount: continue; break;
case ipSupportBase: continue; break;
//TODO: case ipEnsuring: continue; break;
case ipLightning:
case ipAdaptiveCubic:
case ipSupportCubic:
case ipRectilinear:
case ipMonotonic:
case ipMonotonicLine:
case ipAlignedRectilinear:
case ipGrid:
case ipTriangles:
case ipStars:
case ipCubic:
case ipLine:
case ipConcentric:
case ipConcentricInternal:
case ipHoneycomb:
case ip3DHoneycomb:
case ipGyroid:
case ipHilbertCurve:
case ipArchimedeanChords:
case ipOctagramSpiral: break;
}
// Create the filler object.
std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(surface_fill.params.pattern));
f->set_bounding_box(bbox);
f->layer_id = this->id() - this->object()->get_layer(0)->id(); // We need to subtract raft layers.
f->z = this->print_z;
f->angle = surface_fill.params.angle;
// f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree;
// TODO: f->print_config = &this->object()->print()->config();
// TODO: f->print_object_config = &this->object()->config();
if (surface_fill.params.pattern == ipLightning)
dynamic_cast<FillLightning::Filler *>(f.get())->generator = lightning_generator;
// calculate flow spacing for infill pattern generation
double link_max_length = 0.;
if (!surface_fill.params.bridge) {
#if 0
link_max_length = layerm.region()->config().get_abs_value(surface.is_external() ? "external_fill_link_max_length" : "fill_link_max_length", flow.spacing());
// printf("flow spacing: %f, is_external: %d, link_max_length: %lf\n", flow.spacing(), int(surface.is_external()), link_max_length);
#else
if (surface_fill.params.density > 80.) // 80%
link_max_length = 3. * f->spacing;
#endif
}
LayerRegion &layerm = *m_regions[surface_fill.region_id];
// Maximum length of the perimeter segment linking two infill lines.
f->link_max_length = (coord_t) scale_(link_max_length);
// Used by the concentric infill pattern to clip the loops to create extrusion paths.
f->loop_clipping = coord_t(scale_(layerm.region().config().seam_gap.get_abs_value(surface_fill.params.flow.nozzle_diameter())));
// apply half spacing using this flow's own spacing and generate infill
FillParams params;
params.density = float(0.01 * surface_fill.params.density);
params.dont_adjust = false; // surface_fill.params.dont_adjust;
params.anchor_length = surface_fill.params.anchor_length;
params.anchor_length_max = surface_fill.params.anchor_length_max;
params.resolution = resolution;
params.use_arachne = false;
params.layer_height = layerm.layer()->height;
for (ExPolygon &expoly : surface_fill.expolygons) {
// Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon.
f->spacing = surface_fill.params.spacing;
surface_fill.surface.expolygon = std::move(expoly);
try {
Polylines polylines = f->fill_surface(&surface_fill.surface, params);
sparse_infill_polylines.insert(sparse_infill_polylines.end(), polylines.begin(), polylines.end());
} catch (InfillFailedException &) {}
}
}
return sparse_infill_polylines;
}
// Create ironing extrusions over top surfaces. // Create ironing extrusions over top surfaces.
void Layer::make_ironing() void Layer::make_ironing()
{ {

View file

@ -120,57 +120,13 @@ void Fill::fill_surface_extrusion(const Surface* surface, const FillParams& para
{ {
Polylines polylines; Polylines polylines;
ThickPolylines thick_polylines; ThickPolylines thick_polylines;
if (!params.with_loop) { try {
try { if (params.use_arachne)
if (params.use_arachne) thick_polylines = this->fill_surface_arachne(surface, params);
thick_polylines = this->fill_surface_arachne(surface, params); else
else polylines = this->fill_surface(surface, params);
polylines = this->fill_surface(surface, params);
}
catch (InfillFailedException&) {}
}
//BBS: add handling for infill pattern with loop
else {
Slic3r::ExPolygons expp = offset_ex(surface->expolygon, float(scale_(this->overlap - 0.5 * this->spacing)));
Polylines loop_polylines = to_polylines(expp);
{
//BBS: clip the loop
size_t j = 0;
for (size_t i = 0; i < loop_polylines.size(); ++i) {
loop_polylines[i].clip_end(this->loop_clipping);
if (loop_polylines[i].is_valid()) {
if (j < i)
loop_polylines[j] = std::move(loop_polylines[i]);
++j;
}
}
if (j < loop_polylines.size())
loop_polylines.erase(loop_polylines.begin() + int(j), loop_polylines.end());
}
if (!loop_polylines.empty()) {
if (params.use_arachne)
append(thick_polylines, to_thick_polylines(std::move(loop_polylines), scaled<coord_t>(this->spacing)));
else
append(polylines, std::move(loop_polylines));
expp = offset_ex(expp, float(scale_(0 - 0.5 * this->spacing)));
} else {
//BBS: the area is too narrow to place a loop, return to original expolygon
expp = { surface->expolygon };
}
Surface temp_surface = *surface;
for (ExPolygon& ex : expp) {
temp_surface.expolygon = ex;
try {
if (params.use_arachne)
append(thick_polylines, std::move(this->fill_surface_arachne(&temp_surface, params)));
else
append(polylines, std::move(this->fill_surface(&temp_surface, params)));
}
catch (InfillFailedException&) {}
}
} }
catch (InfillFailedException&) {}
if (!polylines.empty() || !thick_polylines.empty()) { if (!polylines.empty() || !thick_polylines.empty()) {
// calculate actual flow from spacing (which might have been adjusted by the infill // calculate actual flow from spacing (which might have been adjusted by the infill

View file

@ -67,8 +67,6 @@ struct FillParams
bool use_arachne{ false }; bool use_arachne{ false };
// Layer height for Concentric infill with Arachne. // Layer height for Concentric infill with Arachne.
coordf_t layer_height { 0.f }; coordf_t layer_height { 0.f };
//BBS
bool with_loop { false };
// BBS // BBS
Flow flow; Flow flow;

View file

@ -1,144 +0,0 @@
#include "InternalBridgeDetector.hpp"
#include "ClipperUtils.hpp"
#include "Geometry.hpp"
#include <algorithm>
namespace Slic3r {
InternalBridgeDetector::InternalBridgeDetector(
ExPolygon _internal_bridge, const ExPolygons& _fill_no_overlap, coord_t _spacing) :
fill_no_overlap(_fill_no_overlap),
spacing(_spacing)
{
this->internal_bridge_infill.push_back(std::move(_internal_bridge));
initialize();
}
//#define INTERNAL_BRIDGE_DETECTOR_DEBUG_TO_SVG
void InternalBridgeDetector::initialize()
{
Polygons grown = offset(this->internal_bridge_infill, float(this->spacing));
this->m_anchor_regions = diff_ex(grown, offset(this->fill_no_overlap, 10.f));
#ifdef INTERNAL_BRIDGE_DETECTOR_DEBUG_TO_SVG
static int irun = 0;
BoundingBox bbox_svg;
bbox_svg.merge(get_extents(this->internal_bridge_infill));
bbox_svg.merge(get_extents(this->fill_no_overlap));
bbox_svg.merge(get_extents(this->m_anchor_regions));
{
std::stringstream stri;
stri << "InternalBridgeDetector_" << irun << ".svg";
SVG svg(stri.str(), bbox_svg);
svg.draw(to_polylines(this->internal_bridge_infill), "blue");
svg.draw(to_polylines(this->fill_no_overlap), "yellow");
svg.draw(to_polylines(m_anchor_regions), "red");
svg.Close();
}
++ irun;
#endif
}
bool InternalBridgeDetector::detect_angle()
{
if (this->m_anchor_regions.empty())
return false;
std::vector<InternalBridgeDirection> candidates;
std::vector<double> angles = bridge_direction_candidates();
candidates.reserve(angles.size());
for (size_t i = 0; i < angles.size(); ++ i)
candidates.emplace_back(InternalBridgeDirection(angles[i]));
Polygons clip_area = offset(this->internal_bridge_infill, 0.5f * float(this->spacing));
bool have_coverage = false;
for (size_t i_angle = 0; i_angle < candidates.size(); ++ i_angle)
{
const double angle = candidates[i_angle].angle;
Lines lines;
{
BoundingBox bbox = get_extents_rotated(this->m_anchor_regions, - angle);
// Cover the region with line segments.
lines.reserve((bbox.max(1) - bbox.min(1) + this->spacing) / this->spacing);
double s = sin(angle);
double c = cos(angle);
for (coord_t y = bbox.min(1); y <= bbox.max(1); y += this->spacing)
lines.push_back(Line(
Point((coord_t)round(c * bbox.min(0) - s * y), (coord_t)round(c * y + s * bbox.min(0))),
Point((coord_t)round(c * bbox.max(0) - s * y), (coord_t)round(c * y + s * bbox.max(0)))));
}
double total_length = 0;
double anchored_length = 0;
double max_length = 0;
{
Lines clipped_lines = intersection_ln(lines, clip_area);
for (size_t i = 0; i < clipped_lines.size(); ++i) {
const Line &line = clipped_lines[i];
double len = line.length();
total_length += len;
if (expolygons_contain(this->m_anchor_regions, line.a) && expolygons_contain(this->m_anchor_regions, line.b)) {
// This line could be anchored.
anchored_length += len;
max_length = std::max(max_length, len);
}
}
}
if (anchored_length == 0.)
continue;
have_coverage = true;
candidates[i_angle].coverage = anchored_length/total_length;
candidates[i_angle].max_length = max_length;
}
if (! have_coverage)
return false;
std::sort(candidates.begin(), candidates.end());
size_t i_best = 0;
this->angle = candidates[i_best].angle;
if (this->angle >= PI)
this->angle -= PI;
return true;
}
std::vector<double> InternalBridgeDetector::bridge_direction_candidates() const
{
std::vector<double> angles;
for (int i = 0; i <= PI/this->resolution; ++i)
angles.push_back(i * this->resolution);
// we also test angles of each bridge contour
{
Lines lines = to_lines(this->internal_bridge_infill);
for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line)
angles.push_back(line->direction());
}
// remove duplicates
double min_resolution = PI/180.0;
std::sort(angles.begin(), angles.end());
for (size_t i = 1; i < angles.size(); ++i) {
if (Slic3r::Geometry::directions_parallel(angles[i], angles[i-1], min_resolution)) {
angles.erase(angles.begin() + i);
--i;
}
}
if (Slic3r::Geometry::directions_parallel(angles.front(), angles.back(), min_resolution))
angles.pop_back();
return angles;
}
}

View file

@ -1,54 +0,0 @@
#ifndef slic3r_InternalBridgeDetector_hpp_
#define slic3r_InternalBridgeDetector_hpp_
#include "libslic3r.h"
#include "ExPolygon.hpp"
#include <string>
namespace Slic3r {
// BBS: InternalBridgeDetector is used to detect bridge angle for internal bridge.
// this step may enlarge internal bridge area for a little(only occupy sparse infill area) for better anchoring
class InternalBridgeDetector {
public:
// input: all fill area in LayerRegion without overlap with perimeter.
ExPolygons fill_no_overlap;
// input: internal bridge infill area.
ExPolygons internal_bridge_infill;
// input: scaled extrusion width of the infill.
coord_t spacing;
// output: the final optimal angle.
double angle = -1.;
InternalBridgeDetector(ExPolygon _internal_bridge, const ExPolygons &_fill_no_overlap, coord_t _spacing);
bool detect_angle();
private:
void initialize();
std::vector<double> bridge_direction_candidates() const;
struct InternalBridgeDirection {
InternalBridgeDirection(double a = -1.) : angle(a), coverage(0.), max_length(0.) {}
// the best direction is the one causing most lines to be bridged and the span is short
bool operator<(const InternalBridgeDirection &other) const {
double delta = this->coverage - other.coverage;
if (delta > 0.001)
return true;
else if (delta < -0.001)
return false;
else
// coverage is almost same, then compare span
return this->max_length < other.max_length;
};
double angle;
double coverage;
double max_length;
};
double resolution = PI/36.0;
ExPolygons m_anchor_regions;
};
}
#endif

View file

@ -182,6 +182,9 @@ public:
// Phony version of make_fills() without parameters for Perl integration only. // Phony version of make_fills() without parameters for Perl integration only.
void make_fills() { this->make_fills(nullptr, nullptr); } void make_fills() { this->make_fills(nullptr, nullptr); }
void make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive::Octree* support_fill_octree, FillLightning::Generator* lightning_generator = nullptr); void make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive::Octree* support_fill_octree, FillLightning::Generator* lightning_generator = nullptr);
Polylines generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Octree *adaptive_fill_octree,
FillAdaptive::Octree *support_fill_octree,
FillLightning::Generator* lightning_generator) const;
void make_ironing(); void make_ironing();
void export_region_slices_to_svg(const char *path) const; void export_region_slices_to_svg(const char *path) const;

View file

@ -752,7 +752,7 @@ static std::vector<std::string> s_Preset_print_options {
"gcode_add_line_number", "enable_arc_fitting", "infill_combination", /*"adaptive_layer_height",*/ "gcode_add_line_number", "enable_arc_fitting", "infill_combination", /*"adaptive_layer_height",*/
"support_bottom_interface_spacing", "enable_overhang_speed", "slowdown_for_curled_perimeters", "overhang_1_4_speed", "overhang_2_4_speed", "overhang_3_4_speed", "overhang_4_4_speed", "support_bottom_interface_spacing", "enable_overhang_speed", "slowdown_for_curled_perimeters", "overhang_1_4_speed", "overhang_2_4_speed", "overhang_3_4_speed", "overhang_4_4_speed",
"initial_layer_infill_speed", "only_one_wall_top", "initial_layer_infill_speed", "only_one_wall_top",
"timelapse_type", "internal_bridge_support_thickness", "timelapse_type",
"wall_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle", "wall_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle",
"wall_distribution_count", "min_feature_size", "min_bead_width", "post_process", "wall_distribution_count", "min_feature_size", "min_bead_width", "post_process",
"small_perimeter_speed", "small_perimeter_threshold","bridge_angle", "filter_out_gap_fill", "travel_acceleration","inner_wall_acceleration", "min_width_top_surface", "small_perimeter_speed", "small_perimeter_threshold","bridge_angle", "filter_out_gap_fill", "travel_acceleration","inner_wall_acceleration", "min_width_top_surface",

View file

@ -1,6 +1,8 @@
#ifndef slic3r_Print_hpp_ #ifndef slic3r_Print_hpp_
#define slic3r_Print_hpp_ #define slic3r_Print_hpp_
#include "Fill/FillAdaptive.hpp"
#include "Fill/FillLightning.hpp"
#include "PrintBase.hpp" #include "PrintBase.hpp"
#include "BoundingBox.hpp" #include "BoundingBox.hpp"
@ -487,7 +489,8 @@ private:
void discover_horizontal_shells(); void discover_horizontal_shells();
void combine_infill(); void combine_infill();
void _generate_support_material(); void _generate_support_material();
std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> prepare_adaptive_infill_data(); std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> prepare_adaptive_infill_data(
const std::vector<std::pair<const Surface*, float>>& surfaces_w_bottom_z) const;
FillLightning::GeneratorPtr prepare_lightning_infill_data(); FillLightning::GeneratorPtr prepare_lightning_infill_data();
// BBS // BBS
@ -517,6 +520,10 @@ private:
// this is set to true when LayerRegion->slices is split in top/internal/bottom // this is set to true when LayerRegion->slices is split in top/internal/bottom
// so that next call to make_perimeters() performs a union() before computing loops // so that next call to make_perimeters() performs a union() before computing loops
bool m_typed_slices = false; bool m_typed_slices = false;
std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> m_adaptive_fill_octrees;
FillLightning::GeneratorPtr m_lightning_generator;
std::vector < VolumeSlices > firstLayerObjSliceByVolume; std::vector < VolumeSlices > firstLayerObjSliceByVolume;
std::vector<groupedVolumeSlices> firstLayerObjSliceByGroups; std::vector<groupedVolumeSlices> firstLayerObjSliceByGroups;
// BBS: per object skirt // BBS: per object skirt

View file

@ -1097,18 +1097,6 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(true)); def->set_default_value(new ConfigOptionBool(true));
def = this->add("internal_bridge_support_thickness", coFloat);
def->label = L("Internal bridge support thickness");
def->category = L("Strength");
def->tooltip = L("If enabled, support loops will be generated under the contours of internal bridges."
"These support loops could prevent internal bridges from extruding over the air and improve the top surface quality, especially when the sparse infill density is low."
"This value determines the thickness of the support loops. 0 means disable this feature");
def->sidetext = L("mm");
def->min = 0;
def->max = 2;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0));
auto def_top_fill_pattern = def = this->add("top_surface_pattern", coEnum); auto def_top_fill_pattern = def = this->add("top_surface_pattern", coEnum);
def->label = L("Top surface pattern"); def->label = L("Top surface pattern");
def->category = L("Strength"); def->category = L("Strength");

View file

@ -711,7 +711,6 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionBool, detect_narrow_internal_solid_infill)) ((ConfigOptionBool, detect_narrow_internal_solid_infill))
// ((ConfigOptionBool, adaptive_layer_height)) // ((ConfigOptionBool, adaptive_layer_height))
((ConfigOptionFloat, support_bottom_interface_spacing)) ((ConfigOptionFloat, support_bottom_interface_spacing))
((ConfigOptionFloat, internal_bridge_support_thickness))
((ConfigOptionEnum<PerimeterGeneratorType>, wall_generator)) ((ConfigOptionEnum<PerimeterGeneratorType>, wall_generator))
((ConfigOptionPercent, wall_transition_length)) ((ConfigOptionPercent, wall_transition_length))
((ConfigOptionPercent, wall_transition_filter_deviation)) ((ConfigOptionPercent, wall_transition_filter_deviation))

File diff suppressed because it is too large Load diff

View file

@ -15,8 +15,6 @@ enum SurfaceType {
stBottomBridge, stBottomBridge,
// Normal sparse infill. // Normal sparse infill.
stInternal, stInternal,
// Normal sparse infill.
stInternalWithLoop,
// Full infill, supporting the top surfaces and/or defining the verticall wall thickness. // Full infill, supporting the top surfaces and/or defining the verticall wall thickness.
stInternalSolid, stInternalSolid,
// 1st layer of dense infill over sparse infill, printed with a bridging extrusion flow. // 1st layer of dense infill over sparse infill, printed with a bridging extrusion flow.
@ -112,7 +110,7 @@ public:
}; };
typedef std::vector<Surface> Surfaces; typedef std::vector<Surface> Surfaces;
typedef std::vector<Surface*> SurfacesPtr; typedef std::vector<const Surface*> SurfacesPtr;
inline Polygons to_polygons(const Surface &surface) inline Polygons to_polygons(const Surface &surface)
{ {
@ -229,6 +227,7 @@ inline void polygons_append(Polygons &dst, const SurfacesPtr &src)
} }
} }
/*
inline void polygons_append(Polygons &dst, SurfacesPtr &&src) inline void polygons_append(Polygons &dst, SurfacesPtr &&src)
{ {
dst.reserve(dst.size() + number_polygons(src)); dst.reserve(dst.size() + number_polygons(src));
@ -238,6 +237,7 @@ inline void polygons_append(Polygons &dst, SurfacesPtr &&src)
(*it)->expolygon.holes.clear(); (*it)->expolygon.holes.clear();
} }
} }
*/
// Append a vector of Surfaces at the end of another vector of polygons. // Append a vector of Surfaces at the end of another vector of polygons.
inline void surfaces_append(Surfaces &dst, const ExPolygons &src, SurfaceType surfaceType) inline void surfaces_append(Surfaces &dst, const ExPolygons &src, SurfaceType surfaceType)

View file

@ -42,26 +42,21 @@ void SurfaceCollection::group(std::vector<SurfacesPtr> *retval)
} }
} }
SurfacesPtr SurfaceCollection::filter_by_type(const SurfaceType type) SurfacesPtr SurfaceCollection::filter_by_type(const SurfaceType type) const
{ {
SurfacesPtr ss; SurfacesPtr ss;
for (Surfaces::iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) { for (const Surface &surface : this->surfaces)
if (surface->surface_type == type) ss.push_back(&*surface); if (surface.surface_type == type)
} ss.push_back(&surface);
return ss; return ss;
} }
SurfacesPtr SurfaceCollection::filter_by_types(const SurfaceType *types, int ntypes) SurfacesPtr SurfaceCollection::filter_by_types(std::initializer_list<SurfaceType> types) const
{ {
SurfacesPtr ss; SurfacesPtr ss;
for (Surfaces::iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) { for (const Surface &surface : this->surfaces)
for (int i = 0; i < ntypes; ++ i) { if (std::find(types.begin(), types.end(), surface.surface_type) != types.end())
if (surface->surface_type == types[i]) { ss.push_back(&surface);
ss.push_back(&*surface);
break;
}
}
}
return ss; return ss;
} }
@ -86,23 +81,15 @@ void SurfaceCollection::keep_type(const SurfaceType type)
surfaces.erase(surfaces.begin() + j, surfaces.end()); surfaces.erase(surfaces.begin() + j, surfaces.end());
} }
void SurfaceCollection::keep_types(const SurfaceType *types, int ntypes) void SurfaceCollection::keep_types(std::initializer_list<SurfaceType> types)
{ {
size_t j = 0; size_t j = 0;
for (size_t i = 0; i < surfaces.size(); ++ i) { for (size_t i = 0; i < surfaces.size(); ++ i)
bool keep = false; if (std::find(types.begin(), types.end(), surfaces[i].surface_type) != types.end()) {
for (int k = 0; k < ntypes; ++ k) {
if (surfaces[i].surface_type == types[k]) {
keep = true;
break;
}
}
if (keep) {
if (j < i) if (j < i)
std::swap(surfaces[i], surfaces[j]); std::swap(surfaces[i], surfaces[j]);
++ j; ++ j;
} }
}
if (j < surfaces.size()) if (j < surfaces.size())
surfaces.erase(surfaces.begin() + j, surfaces.end()); surfaces.erase(surfaces.begin() + j, surfaces.end());
} }
@ -137,23 +124,15 @@ void SurfaceCollection::remove_type(const SurfaceType type, ExPolygons *polygons
surfaces.erase(surfaces.begin() + j, surfaces.end()); surfaces.erase(surfaces.begin() + j, surfaces.end());
} }
void SurfaceCollection::remove_types(const SurfaceType *types, int ntypes) void SurfaceCollection::remove_types(std::initializer_list<SurfaceType> types)
{ {
size_t j = 0; size_t j = 0;
for (size_t i = 0; i < surfaces.size(); ++ i) { for (size_t i = 0; i < surfaces.size(); ++ i)
bool remove = false; if (std::find(types.begin(), types.end(), surfaces[i].surface_type) == types.end()) {
for (int k = 0; k < ntypes; ++ k) {
if (surfaces[i].surface_type == types[k]) {
remove = true;
break;
}
}
if (! remove) {
if (j < i) if (j < i)
std::swap(surfaces[i], surfaces[j]); std::swap(surfaces[i], surfaces[j]);
++ j; ++ j;
} }
}
if (j < surfaces.size()) if (j < surfaces.size())
surfaces.erase(surfaces.begin() + j, surfaces.end()); surfaces.erase(surfaces.begin() + j, surfaces.end());
} }

View file

@ -3,6 +3,7 @@
#include "libslic3r.h" #include "libslic3r.h"
#include "Surface.hpp" #include "Surface.hpp"
#include <initializer_list>
#include <vector> #include <vector>
namespace Slic3r { namespace Slic3r {
@ -26,12 +27,12 @@ public:
for (const Surface &surface : this->surfaces) if (surface.is_bottom() && surface.expolygon.contains(item)) return true; for (const Surface &surface : this->surfaces) if (surface.is_bottom() && surface.expolygon.contains(item)) return true;
return false; return false;
} }
SurfacesPtr filter_by_type(const SurfaceType type); SurfacesPtr filter_by_type(const SurfaceType type) const;
SurfacesPtr filter_by_types(const SurfaceType *types, int ntypes); SurfacesPtr filter_by_types(std::initializer_list<SurfaceType> types) const;
void keep_type(const SurfaceType type); void keep_type(const SurfaceType type);
void keep_types(const SurfaceType *types, int ntypes); void keep_types(std::initializer_list<SurfaceType> types);
void remove_type(const SurfaceType type); void remove_type(const SurfaceType type);
void remove_types(const SurfaceType *types, int ntypes); void remove_types(std::initializer_list<SurfaceType> types);
void filter_by_type(SurfaceType type, Polygons* polygons) const; void filter_by_type(SurfaceType type, Polygons* polygons) const;
void remove_type(const SurfaceType type, ExPolygons *polygons); void remove_type(const SurfaceType type, ExPolygons *polygons);
void set_type(SurfaceType type) { void set_type(SurfaceType type) {
@ -54,6 +55,13 @@ public:
return false; return false;
} }
Surfaces::const_iterator cbegin() const { return this->surfaces.cbegin(); }
Surfaces::const_iterator cend() const { return this->surfaces.cend(); }
Surfaces::const_iterator begin() const { return this->surfaces.cbegin(); }
Surfaces::const_iterator end() const { return this->surfaces.cend(); }
Surfaces::iterator begin() { return this->surfaces.begin(); }
Surfaces::iterator end() { return this->surfaces.end(); }
void set(const SurfaceCollection &coll) { surfaces = coll.surfaces; } void set(const SurfaceCollection &coll) { surfaces = coll.surfaces; }
void set(SurfaceCollection &&coll) { surfaces = std::move(coll.surfaces); } void set(SurfaceCollection &&coll) { surfaces = std::move(coll.surfaces); }
void set(const ExPolygons &src, SurfaceType surfaceType) { clear(); this->append(src, surfaceType); } void set(const ExPolygons &src, SurfaceType surfaceType) { clear(); this->append(src, surfaceType); }

View file

@ -1935,7 +1935,6 @@ void TabPrint::build()
optgroup->append_single_option_line("infill_combination"); optgroup->append_single_option_line("infill_combination");
optgroup->append_single_option_line("detect_narrow_internal_solid_infill"); optgroup->append_single_option_line("detect_narrow_internal_solid_infill");
optgroup->append_single_option_line("ensure_vertical_shell_thickness"); optgroup->append_single_option_line("ensure_vertical_shell_thickness");
optgroup->append_single_option_line("internal_bridge_support_thickness");
page = add_options_page(L("Speed"), "empty"); page = add_options_page(L("Speed"), "empty");
optgroup = page->new_optgroup(L("Initial layer speed"), L"param_speed_first", 15); optgroup = page->new_optgroup(L("Initial layer speed"), L"param_speed_first", 15);