mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-07 23:17:35 -06:00
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:
parent
0e785c05e5
commit
ee0e6a7227
16 changed files with 1017 additions and 506 deletions
|
@ -178,8 +178,6 @@ set(lisbslic3r_sources
|
|||
Geometry/VoronoiUtilsCgal.hpp
|
||||
Geometry/VoronoiVisualUtils.hpp
|
||||
Int128.hpp
|
||||
InternalBridgeDetector.cpp
|
||||
InternalBridgeDetector.hpp
|
||||
KDTreeIndirect.hpp
|
||||
Layer.cpp
|
||||
Layer.hpp
|
||||
|
|
|
@ -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 <stdio.h>
|
||||
#include <memory>
|
||||
|
@ -46,8 +55,6 @@ struct SurfaceFillParams
|
|||
// 1000mm is roughly the maximum length line that fits into a 32bit coord_t.
|
||||
float anchor_length = 1000.f;
|
||||
float anchor_length_max = 1000.f;
|
||||
//BBS
|
||||
bool with_loop = false;
|
||||
|
||||
// width, height of extrusion, nozzle diameter, is bridge
|
||||
// For the output, for fill generator.
|
||||
|
@ -79,7 +86,6 @@ struct SurfaceFillParams
|
|||
// RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_adjust);
|
||||
RETURN_COMPARE_NON_EQUAL(anchor_length);
|
||||
RETURN_COMPARE_NON_EQUAL(anchor_length_max);
|
||||
RETURN_COMPARE_NON_EQUAL(with_loop);
|
||||
RETURN_COMPARE_NON_EQUAL(flow.width());
|
||||
RETURN_COMPARE_NON_EQUAL(flow.height());
|
||||
RETURN_COMPARE_NON_EQUAL(flow.nozzle_diameter());
|
||||
|
@ -100,7 +106,6 @@ struct SurfaceFillParams
|
|||
// this->dont_adjust == rhs.dont_adjust &&
|
||||
this->anchor_length == rhs.anchor_length &&
|
||||
this->anchor_length_max == rhs.anchor_length_max &&
|
||||
this->with_loop == rhs.with_loop &&
|
||||
this->flow == rhs.flow &&
|
||||
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.pattern = region_config.sparse_infill_pattern.value;
|
||||
params.density = float(region_config.sparse_infill_density);
|
||||
//BBS
|
||||
params.with_loop = surface.surface_type == stInternalWithLoop;
|
||||
|
||||
if (surface.is_solid()) {
|
||||
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.using_internal_flow = using_internal_flow;
|
||||
params.no_extrusion_overlap = surface_fill.params.overlap;
|
||||
params.with_loop = surface_fill.params.with_loop;
|
||||
params.config = &layerm->region().config();
|
||||
if (surface_fill.params.pattern == ipGrid)
|
||||
params.can_reverse = false;
|
||||
|
@ -540,6 +542,101 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
|
|||
#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.
|
||||
void Layer::make_ironing()
|
||||
{
|
||||
|
|
|
@ -120,7 +120,6 @@ void Fill::fill_surface_extrusion(const Surface* surface, const FillParams& para
|
|||
{
|
||||
Polylines polylines;
|
||||
ThickPolylines thick_polylines;
|
||||
if (!params.with_loop) {
|
||||
try {
|
||||
if (params.use_arachne)
|
||||
thick_polylines = this->fill_surface_arachne(surface, params);
|
||||
|
@ -128,49 +127,6 @@ void Fill::fill_surface_extrusion(const Surface* surface, const FillParams& para
|
|||
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&) {}
|
||||
}
|
||||
}
|
||||
|
||||
if (!polylines.empty() || !thick_polylines.empty()) {
|
||||
// calculate actual flow from spacing (which might have been adjusted by the infill
|
||||
|
|
|
@ -67,8 +67,6 @@ struct FillParams
|
|||
bool use_arachne{ false };
|
||||
// Layer height for Concentric infill with Arachne.
|
||||
coordf_t layer_height { 0.f };
|
||||
//BBS
|
||||
bool with_loop { false };
|
||||
|
||||
// BBS
|
||||
Flow flow;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -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
|
|
@ -182,6 +182,9 @@ public:
|
|||
// Phony version of make_fills() without parameters for Perl integration only.
|
||||
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);
|
||||
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 export_region_slices_to_svg(const char *path) const;
|
||||
|
|
|
@ -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",*/
|
||||
"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",
|
||||
"timelapse_type", "internal_bridge_support_thickness",
|
||||
"timelapse_type",
|
||||
"wall_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle",
|
||||
"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",
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef slic3r_Print_hpp_
|
||||
#define slic3r_Print_hpp_
|
||||
|
||||
#include "Fill/FillAdaptive.hpp"
|
||||
#include "Fill/FillLightning.hpp"
|
||||
#include "PrintBase.hpp"
|
||||
|
||||
#include "BoundingBox.hpp"
|
||||
|
@ -487,7 +489,8 @@ private:
|
|||
void discover_horizontal_shells();
|
||||
void combine_infill();
|
||||
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();
|
||||
|
||||
// BBS
|
||||
|
@ -517,6 +520,10 @@ private:
|
|||
// 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
|
||||
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<groupedVolumeSlices> firstLayerObjSliceByGroups;
|
||||
// BBS: per object skirt
|
||||
|
|
|
@ -1097,18 +1097,6 @@ void PrintConfigDef::init_fff_params()
|
|||
def->mode = comAdvanced;
|
||||
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);
|
||||
def->label = L("Top surface pattern");
|
||||
def->category = L("Strength");
|
||||
|
|
|
@ -711,7 +711,6 @@ PRINT_CONFIG_CLASS_DEFINE(
|
|||
((ConfigOptionBool, detect_narrow_internal_solid_infill))
|
||||
// ((ConfigOptionBool, adaptive_layer_height))
|
||||
((ConfigOptionFloat, support_bottom_interface_spacing))
|
||||
((ConfigOptionFloat, internal_bridge_support_thickness))
|
||||
((ConfigOptionEnum<PerimeterGeneratorType>, wall_generator))
|
||||
((ConfigOptionPercent, wall_transition_length))
|
||||
((ConfigOptionPercent, wall_transition_filter_deviation))
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -15,8 +15,6 @@ enum SurfaceType {
|
|||
stBottomBridge,
|
||||
// Normal sparse infill.
|
||||
stInternal,
|
||||
// Normal sparse infill.
|
||||
stInternalWithLoop,
|
||||
// Full infill, supporting the top surfaces and/or defining the verticall wall thickness.
|
||||
stInternalSolid,
|
||||
// 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*> SurfacesPtr;
|
||||
typedef std::vector<const Surface*> SurfacesPtr;
|
||||
|
||||
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)
|
||||
{
|
||||
dst.reserve(dst.size() + number_polygons(src));
|
||||
|
@ -238,6 +237,7 @@ inline void polygons_append(Polygons &dst, SurfacesPtr &&src)
|
|||
(*it)->expolygon.holes.clear();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Append a vector of Surfaces at the end of another vector of polygons.
|
||||
inline void surfaces_append(Surfaces &dst, const ExPolygons &src, SurfaceType surfaceType)
|
||||
|
|
|
@ -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;
|
||||
for (Surfaces::iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) {
|
||||
if (surface->surface_type == type) ss.push_back(&*surface);
|
||||
}
|
||||
for (const Surface &surface : this->surfaces)
|
||||
if (surface.surface_type == type)
|
||||
ss.push_back(&surface);
|
||||
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;
|
||||
for (Surfaces::iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) {
|
||||
for (int i = 0; i < ntypes; ++ i) {
|
||||
if (surface->surface_type == types[i]) {
|
||||
ss.push_back(&*surface);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const Surface &surface : this->surfaces)
|
||||
if (std::find(types.begin(), types.end(), surface.surface_type) != types.end())
|
||||
ss.push_back(&surface);
|
||||
return ss;
|
||||
}
|
||||
|
||||
|
@ -86,23 +81,15 @@ void SurfaceCollection::keep_type(const SurfaceType type)
|
|||
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;
|
||||
for (size_t i = 0; i < surfaces.size(); ++ i) {
|
||||
bool keep = false;
|
||||
for (int k = 0; k < ntypes; ++ k) {
|
||||
if (surfaces[i].surface_type == types[k]) {
|
||||
keep = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (keep) {
|
||||
for (size_t i = 0; i < surfaces.size(); ++ i)
|
||||
if (std::find(types.begin(), types.end(), surfaces[i].surface_type) != types.end()) {
|
||||
if (j < i)
|
||||
std::swap(surfaces[i], surfaces[j]);
|
||||
++ j;
|
||||
}
|
||||
}
|
||||
if (j < surfaces.size())
|
||||
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());
|
||||
}
|
||||
|
||||
void SurfaceCollection::remove_types(const SurfaceType *types, int ntypes)
|
||||
void SurfaceCollection::remove_types(std::initializer_list<SurfaceType> types)
|
||||
{
|
||||
size_t j = 0;
|
||||
for (size_t i = 0; i < surfaces.size(); ++ i) {
|
||||
bool remove = false;
|
||||
for (int k = 0; k < ntypes; ++ k) {
|
||||
if (surfaces[i].surface_type == types[k]) {
|
||||
remove = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (! remove) {
|
||||
for (size_t i = 0; i < surfaces.size(); ++ i)
|
||||
if (std::find(types.begin(), types.end(), surfaces[i].surface_type) == types.end()) {
|
||||
if (j < i)
|
||||
std::swap(surfaces[i], surfaces[j]);
|
||||
++ j;
|
||||
}
|
||||
}
|
||||
if (j < surfaces.size())
|
||||
surfaces.erase(surfaces.begin() + j, surfaces.end());
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "libslic3r.h"
|
||||
#include "Surface.hpp"
|
||||
#include <initializer_list>
|
||||
#include <vector>
|
||||
|
||||
namespace Slic3r {
|
||||
|
@ -26,12 +27,12 @@ public:
|
|||
for (const Surface &surface : this->surfaces) if (surface.is_bottom() && surface.expolygon.contains(item)) return true;
|
||||
return false;
|
||||
}
|
||||
SurfacesPtr filter_by_type(const SurfaceType type);
|
||||
SurfacesPtr filter_by_types(const SurfaceType *types, int ntypes);
|
||||
SurfacesPtr filter_by_type(const SurfaceType type) const;
|
||||
SurfacesPtr filter_by_types(std::initializer_list<SurfaceType> types) const;
|
||||
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_types(const SurfaceType *types, int ntypes);
|
||||
void remove_types(std::initializer_list<SurfaceType> types);
|
||||
void filter_by_type(SurfaceType type, Polygons* polygons) const;
|
||||
void remove_type(const SurfaceType type, ExPolygons *polygons);
|
||||
void set_type(SurfaceType type) {
|
||||
|
@ -54,6 +55,13 @@ public:
|
|||
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(SurfaceCollection &&coll) { surfaces = std::move(coll.surfaces); }
|
||||
void set(const ExPolygons &src, SurfaceType surfaceType) { clear(); this->append(src, surfaceType); }
|
||||
|
|
|
@ -1935,7 +1935,6 @@ void TabPrint::build()
|
|||
optgroup->append_single_option_line("infill_combination");
|
||||
optgroup->append_single_option_line("detect_narrow_internal_solid_infill");
|
||||
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");
|
||||
optgroup = page->new_optgroup(L("Initial layer speed"), L"param_speed_first", 15);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue