mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-12 23:19:00 +08:00
Refactoring: make_fills() is now a LayerRegion method, and we move the base Fill class to Fill.hpp, no need for FillBase.hpp anymore
This commit is contained in:
parent
a9609a6dd5
commit
3e04877571
@ -47,7 +47,6 @@ add_library(libslic3r STATIC
|
||||
${LIBDIR}/libslic3r/ExtrusionEntityCollection.cpp
|
||||
${LIBDIR}/libslic3r/Fill/Fill.cpp
|
||||
${LIBDIR}/libslic3r/Fill/Fill3DHoneycomb.cpp
|
||||
${LIBDIR}/libslic3r/Fill/FillBase.cpp
|
||||
${LIBDIR}/libslic3r/Fill/FillConcentric.cpp
|
||||
${LIBDIR}/libslic3r/Fill/FillHoneycomb.cpp
|
||||
${LIBDIR}/libslic3r/Fill/FillPlanePath.cpp
|
||||
@ -61,6 +60,7 @@ add_library(libslic3r STATIC
|
||||
${LIBDIR}/libslic3r/IO.cpp
|
||||
${LIBDIR}/libslic3r/Layer.cpp
|
||||
${LIBDIR}/libslic3r/LayerRegion.cpp
|
||||
${LIBDIR}/libslic3r/LayerRegionFill.cpp
|
||||
${LIBDIR}/libslic3r/Line.cpp
|
||||
${LIBDIR}/libslic3r/Model.cpp
|
||||
${LIBDIR}/libslic3r/MotionPlanner.cpp
|
||||
|
@ -30,8 +30,6 @@ src/libslic3r/ExtrusionEntityCollection.cpp
|
||||
src/libslic3r/ExtrusionEntityCollection.hpp
|
||||
src/libslic3r/Fill/Fill.cpp
|
||||
src/libslic3r/Fill/Fill.hpp
|
||||
src/libslic3r/Fill/FillBase.cpp
|
||||
src/libslic3r/Fill/FillBase.hpp
|
||||
src/libslic3r/Fill/FillConcentric.cpp
|
||||
src/libslic3r/Fill/FillConcentric.hpp
|
||||
src/libslic3r/Fill/FillHoneycomb.cpp
|
||||
|
@ -1,290 +1,138 @@
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <memory>
|
||||
|
||||
#include "../ClipperUtils.hpp"
|
||||
#include "../Geometry.hpp"
|
||||
#include "../Layer.hpp"
|
||||
#include "../Print.hpp"
|
||||
#include "../PrintConfig.hpp"
|
||||
#include "../Surface.hpp"
|
||||
#include "../SurfaceCollection.hpp"
|
||||
#include "../PrintConfig.hpp"
|
||||
|
||||
#include "FillBase.hpp"
|
||||
#include "Fill.hpp"
|
||||
#include "FillConcentric.hpp"
|
||||
#include "FillHoneycomb.hpp"
|
||||
#include "Fill3DHoneycomb.hpp"
|
||||
#include "FillPlanePath.hpp"
|
||||
#include "FillRectilinear.hpp"
|
||||
#include "FillRectilinear2.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
struct SurfaceGroupAttrib
|
||||
Fill*
|
||||
Fill::new_from_type(const InfillPattern type)
|
||||
{
|
||||
SurfaceGroupAttrib() : is_solid(false), fw(0.f), pattern(-1) {}
|
||||
bool operator==(const SurfaceGroupAttrib &other) const
|
||||
{ return is_solid == other.is_solid && fw == other.fw && pattern == other.pattern; }
|
||||
bool is_solid;
|
||||
float fw;
|
||||
// pattern is of type InfillPattern, -1 for an unset pattern.
|
||||
int pattern;
|
||||
};
|
||||
|
||||
// Generate infills for a LayerRegion.
|
||||
// The LayerRegion at this point of time may contain
|
||||
// surfaces of various types (internal/bridge/top/bottom/solid).
|
||||
// The infills are generated on the groups of surfaces with a compatible type.
|
||||
// Returns an array of ExtrusionPathCollection objects containing the infills generated now
|
||||
// and the thin fills generated by generate_perimeters().
|
||||
void make_fill(const LayerRegion &layerm, ExtrusionEntityCollection* out)
|
||||
{
|
||||
// Slic3r::debugf "Filling layer %d:\n", $layerm->layer->id;
|
||||
|
||||
double fill_density = layerm.region()->config.fill_density;
|
||||
const Flow infill_flow = layerm.flow(frInfill);
|
||||
const Flow solid_infill_flow = layerm.flow(frSolidInfill);
|
||||
const Flow top_solid_infill_flow = layerm.flow(frTopSolidInfill);
|
||||
|
||||
SurfaceCollection surfaces;
|
||||
|
||||
// merge adjacent surfaces
|
||||
// in case of bridge surfaces, the ones with defined angle will be attached to the ones
|
||||
// without any angle (shouldn't this logic be moved to process_external_surfaces()?)
|
||||
{
|
||||
Polygons polygons_bridged;
|
||||
polygons_bridged.reserve(layerm.fill_surfaces.surfaces.size());
|
||||
for (Surfaces::const_iterator it = layerm.fill_surfaces.surfaces.begin(); it != layerm.fill_surfaces.surfaces.end(); ++it)
|
||||
if (it->bridge_angle >= 0)
|
||||
append_to(polygons_bridged, (Polygons)*it);
|
||||
switch (type) {
|
||||
case ipConcentric: return new FillConcentric();
|
||||
case ipHoneycomb: return new FillHoneycomb();
|
||||
case ip3DHoneycomb: return new Fill3DHoneycomb();
|
||||
|
||||
// group surfaces by distinct properties (equal surface_type, thickness, thickness_layers, bridge_angle)
|
||||
// group is of type SurfaceCollection
|
||||
// FIXME: Use some smart heuristics to merge similar surfaces to eliminate tiny regions.
|
||||
std::vector<SurfacesConstPtr> groups;
|
||||
layerm.fill_surfaces.group(&groups);
|
||||
case ipRectilinear: return new FillRectilinear();
|
||||
case ipLine: return new FillLine();
|
||||
case ipGrid: return new FillGrid();
|
||||
case ipAlignedRectilinear: return new FillAlignedRectilinear();
|
||||
|
||||
// merge compatible groups (we can generate continuous infill for them)
|
||||
{
|
||||
// cache flow widths and patterns used for all solid groups
|
||||
// (we'll use them for comparing compatible groups)
|
||||
std::vector<SurfaceGroupAttrib> group_attrib(groups.size());
|
||||
for (size_t i = 0; i < groups.size(); ++i) {
|
||||
// we can only merge solid non-bridge surfaces, so discard
|
||||
// non-solid surfaces
|
||||
const Surface &surface = *groups[i].front();
|
||||
if (surface.is_solid() && (!surface.is_bridge() || layerm.layer()->id() == 0)) {
|
||||
group_attrib[i].is_solid = true;
|
||||
group_attrib[i].fw = (surface.surface_type == stTop) ? top_solid_infill_flow.width : solid_infill_flow.width;
|
||||
group_attrib[i].pattern = surface.is_external() ? layerm.region()->config.external_fill_pattern.value : ipRectilinear;
|
||||
}
|
||||
}
|
||||
// Loop through solid groups, find compatible groups and append them to this one.
|
||||
for (size_t i = 0; i < groups.size(); ++i) {
|
||||
if (!group_attrib[i].is_solid)
|
||||
continue;
|
||||
for (size_t j = i + 1; j < groups.size();) {
|
||||
if (group_attrib[i] == group_attrib[j]) {
|
||||
// groups are compatible, merge them
|
||||
append_to(groups[i], groups[j]);
|
||||
groups.erase(groups.begin() + j);
|
||||
group_attrib.erase(group_attrib.begin() + j);
|
||||
} else {
|
||||
++j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case ipRectilinear2: return new FillRectilinear2();
|
||||
case ipGrid2: return new FillGrid2();
|
||||
case ipTriangles: return new FillTriangles();
|
||||
case ipStars: return new FillStars();
|
||||
case ipCubic: return new FillCubic();
|
||||
|
||||
// Give priority to bridges. Process the bridges in the first round, the rest of the surfaces in the 2nd round.
|
||||
for (size_t round = 0; round < 2; ++ round) {
|
||||
for (std::vector<SurfacesConstPtr>::const_iterator it_group = groups.begin(); it_group != groups.end(); ++ it_group) {
|
||||
const SurfacesConstPtr &group = *it_group;
|
||||
bool is_bridge = group.front()->bridge_angle >= 0;
|
||||
if (is_bridge != (round == 0))
|
||||
continue;
|
||||
|
||||
// Make a union of polygons defining the infiill regions of a group, use a safety offset.
|
||||
Polygons union_p = union_(to_polygons(group), true);
|
||||
|
||||
// Subtract surfaces having a defined bridge_angle from any other, use a safety offset.
|
||||
if (!polygons_bridged.empty() && !is_bridge)
|
||||
union_p = diff(union_p, polygons_bridged, true);
|
||||
|
||||
// subtract any other surface already processed
|
||||
//FIXME Vojtech: Because the bridge surfaces came first, they are subtracted twice!
|
||||
surfaces.append(
|
||||
diff_ex(union_p, to_polygons(surfaces), true),
|
||||
*group.front() // template
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we need to detect any narrow surfaces that might collapse
|
||||
// when adding spacing below
|
||||
// such narrow surfaces are often generated in sloping walls
|
||||
// by bridge_over_infill() and combine_infill() as a result of the
|
||||
// subtraction of the combinable area from the layer infill area,
|
||||
// which leaves small areas near the perimeters
|
||||
// we are going to grow such regions by overlapping them with the void (if any)
|
||||
// TODO: detect and investigate whether there could be narrow regions without
|
||||
// any void neighbors
|
||||
{
|
||||
coord_t distance_between_surfaces = std::max(
|
||||
std::max(infill_flow.scaled_spacing(), solid_infill_flow.scaled_spacing()),
|
||||
top_solid_infill_flow.scaled_spacing()
|
||||
);
|
||||
case ipArchimedeanChords: return new FillArchimedeanChords();
|
||||
case ipHilbertCurve: return new FillHilbertCurve();
|
||||
case ipOctagramSpiral: return new FillOctagramSpiral();
|
||||
|
||||
Polygons surfaces_polygons = (Polygons)surfaces;
|
||||
Polygons collapsed = diff(
|
||||
surfaces_polygons,
|
||||
offset2(surfaces_polygons, -distance_between_surfaces/2, +distance_between_surfaces/2),
|
||||
true
|
||||
);
|
||||
|
||||
Polygons to_subtract;
|
||||
surfaces.filter_by_type(stInternalVoid, &to_subtract);
|
||||
|
||||
append_to(to_subtract, collapsed);
|
||||
surfaces.append(
|
||||
intersection_ex(
|
||||
offset(collapsed, distance_between_surfaces),
|
||||
to_subtract,
|
||||
true
|
||||
),
|
||||
stInternalSolid
|
||||
);
|
||||
}
|
||||
|
||||
if (false) {
|
||||
// require "Slic3r/SVG.pm";
|
||||
// Slic3r::SVG::output("fill_" . $layerm->print_z . ".svg",
|
||||
// expolygons => [ map $_->expolygon, grep !$_->is_solid, @surfaces ],
|
||||
// red_expolygons => [ map $_->expolygon, grep $_->is_solid, @surfaces ],
|
||||
// );
|
||||
}
|
||||
|
||||
for (Surfaces::const_iterator surface_it = surfaces.surfaces.begin();
|
||||
surface_it != surfaces.surfaces.end(); ++surface_it) {
|
||||
|
||||
const Surface &surface = *surface_it;
|
||||
if (surface.surface_type == stInternalVoid)
|
||||
continue;
|
||||
|
||||
InfillPattern fill_pattern = layerm.region()->config.fill_pattern.value;
|
||||
double density = fill_density;
|
||||
FlowRole role = (surface.surface_type == stTop) ? frTopSolidInfill
|
||||
: surface.is_solid() ? frSolidInfill
|
||||
: frInfill;
|
||||
const bool is_bridge = layerm.layer()->id() > 0 && surface.is_bridge();
|
||||
|
||||
if (surface.is_solid()) {
|
||||
density = 100.;
|
||||
fill_pattern = (surface.is_external() && !is_bridge)
|
||||
? layerm.region()->config.external_fill_pattern.value
|
||||
: ipRectilinear;
|
||||
} else if (density <= 0)
|
||||
continue;
|
||||
|
||||
// get filler object
|
||||
#if SLIC3R_CPPVER >= 11
|
||||
std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(fill_pattern));
|
||||
#else
|
||||
std::auto_ptr<Fill> f = std::auto_ptr<Fill>(Fill::new_from_type(fill_pattern));
|
||||
#endif
|
||||
f->set_bounding_box(layerm.layer()->object()->bounding_box());
|
||||
|
||||
// calculate the actual flow we'll be using for this infill
|
||||
coordf_t h = (surface.thickness == -1) ? layerm.layer()->height : surface.thickness;
|
||||
Flow flow = layerm.region()->flow(
|
||||
role,
|
||||
h,
|
||||
is_bridge || f->use_bridge_flow(), // bridge flow?
|
||||
layerm.layer()->id() == 0, // first layer?
|
||||
-1, // auto width
|
||||
*layerm.layer()->object()
|
||||
);
|
||||
|
||||
// calculate flow spacing for infill pattern generation
|
||||
bool using_internal_flow = false;
|
||||
if (!surface.is_solid() && !is_bridge) {
|
||||
// it's internal infill, so we can calculate a generic flow spacing
|
||||
// for all layers, for avoiding the ugly effect of
|
||||
// misaligned infill on first layer because of different extrusion width and
|
||||
// layer height
|
||||
Flow internal_flow = layerm.region()->flow(
|
||||
frInfill,
|
||||
layerm.layer()->object()->config.layer_height.value, // TODO: handle infill_every_layers?
|
||||
false, // no bridge
|
||||
false, // no first layer
|
||||
-1, // auto width
|
||||
*layerm.layer()->object()
|
||||
);
|
||||
f->spacing = internal_flow.spacing();
|
||||
using_internal_flow = true;
|
||||
} else {
|
||||
f->spacing = flow.spacing();
|
||||
}
|
||||
|
||||
f->layer_id = layerm.layer()->id();
|
||||
f->z = layerm.layer()->print_z;
|
||||
f->angle = Geometry::deg2rad(layerm.region()->config.fill_angle.value);
|
||||
|
||||
// Maximum length of the perimeter segment linking two infill lines.
|
||||
f->link_max_length = (!is_bridge && density > 80)
|
||||
? scale_(3 * f->spacing)
|
||||
: 0;
|
||||
|
||||
// Used by the concentric infill pattern to clip the loops to create extrusion paths.
|
||||
f->loop_clipping = scale_(flow.nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER;
|
||||
|
||||
// apply half spacing using this flow's own spacing and generate infill
|
||||
FillParams params;
|
||||
params.density = density/100;
|
||||
params.dont_adjust = false;
|
||||
Polylines polylines = f->fill_surface(surface, params);
|
||||
if (polylines.empty())
|
||||
continue;
|
||||
|
||||
// calculate actual flow from spacing (which might have been adjusted by the infill
|
||||
// pattern generator)
|
||||
if (using_internal_flow) {
|
||||
// if we used the internal flow we're not doing a solid infill
|
||||
// so we can safely ignore the slight variation that might have
|
||||
// been applied to f->spacing
|
||||
} else {
|
||||
flow = Flow::new_from_spacing(f->spacing, flow.nozzle_diameter, h, is_bridge || f->use_bridge_flow());
|
||||
}
|
||||
|
||||
// Save into layer.
|
||||
ExtrusionEntityCollection* coll = new ExtrusionEntityCollection();
|
||||
coll->no_sort = f->no_sort();
|
||||
out->entities.push_back(coll);
|
||||
|
||||
{
|
||||
ExtrusionRole role;
|
||||
if (is_bridge) {
|
||||
role = erBridgeInfill;
|
||||
} else if (surface.is_solid()) {
|
||||
role = (surface.surface_type == stTop) ? erTopSolidInfill : erSolidInfill;
|
||||
} else {
|
||||
role = erInternalInfill;
|
||||
}
|
||||
|
||||
ExtrusionPath templ(role);
|
||||
templ.mm3_per_mm = flow.mm3_per_mm();
|
||||
templ.width = flow.width;
|
||||
templ.height = flow.height;
|
||||
|
||||
coll->append(STDMOVE(polylines), templ);
|
||||
}
|
||||
}
|
||||
|
||||
// add thin fill regions
|
||||
// thin_fills are of C++ Slic3r::ExtrusionEntityCollection, perl type Slic3r::ExtrusionPath::Collection
|
||||
// Unpacks the collection, creates multiple collections per path so that they will
|
||||
// be individually included in the nearest neighbor search.
|
||||
// The path type could be ExtrusionPath, ExtrusionLoop or ExtrusionEntityCollection.
|
||||
for (ExtrusionEntitiesPtr::const_iterator thin_fill = layerm.thin_fills.entities.begin(); thin_fill != layerm.thin_fills.entities.end(); ++ thin_fill) {
|
||||
ExtrusionEntityCollection* coll = new ExtrusionEntityCollection();
|
||||
out->entities.push_back(coll);
|
||||
coll->entities.push_back((*thin_fill)->clone());
|
||||
default: CONFESS("unknown type"); return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Fill*
|
||||
Fill::new_from_type(const std::string &type)
|
||||
{
|
||||
static t_config_enum_values enum_keys_map = ConfigOptionEnum<InfillPattern>::get_enum_values();
|
||||
t_config_enum_values::const_iterator it = enum_keys_map.find(type);
|
||||
return (it == enum_keys_map.end()) ? NULL : new_from_type(InfillPattern(it->second));
|
||||
}
|
||||
|
||||
Polylines
|
||||
Fill::fill_surface(const Surface &surface, const FillParams ¶ms)
|
||||
{
|
||||
// Perform offset.
|
||||
ExPolygons expp = offset_ex(surface.expolygon, -scale_(this->spacing)/2);
|
||||
|
||||
// Create the infills for each of the regions.
|
||||
Polylines polylines_out;
|
||||
for (size_t i = 0; i < expp.size(); ++i)
|
||||
this->_fill_surface_single(
|
||||
params,
|
||||
surface.thickness_layers,
|
||||
this->_infill_direction(surface),
|
||||
expp[i],
|
||||
&polylines_out
|
||||
);
|
||||
return polylines_out;
|
||||
}
|
||||
|
||||
// Calculate a new spacing to fill width with possibly integer number of lines,
|
||||
// the first and last line being centered at the interval ends.
|
||||
// This function possibly increases the spacing, never decreases,
|
||||
// and for a narrow width the increase in spacing may become severe,
|
||||
// therefore the adjustment is limited to 20% increase.
|
||||
coord_t
|
||||
Fill::adjust_solid_spacing(const coord_t width, const coord_t distance)
|
||||
{
|
||||
assert(width >= 0);
|
||||
assert(distance > 0);
|
||||
// floor(width / distance)
|
||||
coord_t number_of_intervals = floor(width / distance);
|
||||
coord_t distance_new = (number_of_intervals == 0)
|
||||
? distance
|
||||
: (width / number_of_intervals);
|
||||
|
||||
const coordf_t factor = coordf_t(distance_new) / coordf_t(distance);
|
||||
assert(factor > 1. - 1e-5);
|
||||
|
||||
// How much could the extrusion width be increased? By 20%.
|
||||
const coordf_t factor_max = 1.2;
|
||||
if (factor > factor_max)
|
||||
distance_new = floor((double)distance * factor_max + 0.5);
|
||||
|
||||
return distance_new;
|
||||
}
|
||||
|
||||
// Returns orientation of the infill and the reference point of the infill pattern.
|
||||
// For a normal print, the reference point is the center of a bounding box of the STL.
|
||||
std::pair<float, Point>
|
||||
Fill::_infill_direction(const Surface &surface) const
|
||||
{
|
||||
// set infill angle
|
||||
float out_angle = this->angle;
|
||||
|
||||
// Bounding box is the bounding box of a Slic3r::PrintObject
|
||||
// The bounding box is only undefined in unit tests.
|
||||
Point out_shift = this->bounding_box.defined
|
||||
? this->bounding_box.center()
|
||||
: surface.expolygon.contour.bounding_box().center();
|
||||
|
||||
#if 0
|
||||
if (!this->bounding_box.defined) {
|
||||
printf("Fill::_infill_direction: empty bounding box!");
|
||||
} else {
|
||||
printf("Fill::_infill_direction: reference point %d, %d\n", out_shift.x, out_shift.y);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (surface.bridge_angle >= 0) {
|
||||
// use bridge angle
|
||||
//FIXME Vojtech: Add a debugf?
|
||||
// Slic3r::debugf "Filling bridge with angle %d\n", rad2deg($surface->bridge_angle);
|
||||
#ifdef SLIC3R_DEBUG
|
||||
printf("Filling bridge with angle %f\n", surface.bridge_angle);
|
||||
#endif
|
||||
out_angle = surface.bridge_angle;
|
||||
} else if (this->layer_id != size_t(-1)) {
|
||||
// alternate fill direction
|
||||
out_angle += this->_layer_angle(this->layer_id / surface.thickness_layers);
|
||||
}
|
||||
|
||||
out_angle += float(M_PI/2.);
|
||||
return std::pair<float, Point>(out_angle, out_shift);
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -1,22 +1,110 @@
|
||||
#ifndef slic3r_Fill_hpp_
|
||||
#define slic3r_Fill_hpp_
|
||||
|
||||
#include <assert.h>
|
||||
#include <memory.h>
|
||||
#include <float.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../libslic3r.h"
|
||||
#include "../BoundingBox.hpp"
|
||||
#include "../ExPolygon.hpp"
|
||||
#include "../Polyline.hpp"
|
||||
#include "../PrintConfig.hpp"
|
||||
|
||||
#include "FillBase.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class ExtrusionEntityCollection;
|
||||
class LayerRegion;
|
||||
class Surface;
|
||||
|
||||
void make_fill(const LayerRegion &layerm, ExtrusionEntityCollection* out);
|
||||
struct FillParams
|
||||
{
|
||||
public:
|
||||
FillParams() : density(0), dont_connect(false), dont_adjust(false), complete(false) {};
|
||||
|
||||
// Fill density, fraction in <0, 1>
|
||||
float density;
|
||||
|
||||
// Don't connect the fill lines around the inner perimeter.
|
||||
bool dont_connect;
|
||||
|
||||
// Don't adjust spacing to fill the space evenly.
|
||||
bool dont_adjust;
|
||||
|
||||
// For Honeycomb.
|
||||
// we were requested to complete each loop;
|
||||
// in this case we don't try to make more continuous paths
|
||||
bool complete;
|
||||
};
|
||||
|
||||
class Fill
|
||||
{
|
||||
public:
|
||||
// Index of the layer.
|
||||
size_t layer_id;
|
||||
|
||||
// Z coordinate of the top print surface, in unscaled coordinates
|
||||
coordf_t z;
|
||||
|
||||
// in unscaled coordinates
|
||||
coordf_t spacing;
|
||||
|
||||
// in radians, ccw, 0 = East
|
||||
float angle;
|
||||
|
||||
// In scaled coordinates. Maximum lenght of a perimeter segment connecting two infill lines.
|
||||
// Used by the FillRectilinear2, FillGrid2, FillTriangles, FillStars and FillCubic.
|
||||
// If left to zero, the links will not be limited.
|
||||
coord_t link_max_length;
|
||||
|
||||
// In scaled coordinates. Used by the concentric infill pattern to clip the loops to create extrusion paths.
|
||||
coord_t loop_clipping;
|
||||
|
||||
// In scaled coordinates. Bounding box of the 2D projection of the object.
|
||||
BoundingBox bounding_box;
|
||||
|
||||
public:
|
||||
virtual ~Fill() {}
|
||||
|
||||
static Fill* new_from_type(const InfillPattern type);
|
||||
static Fill* new_from_type(const std::string &type);
|
||||
|
||||
void set_bounding_box(const BoundingBox &bb) { this->bounding_box = bb; }
|
||||
|
||||
// Use bridge flow for the fill?
|
||||
virtual bool use_bridge_flow() const { return false; }
|
||||
|
||||
// Do not sort the fill lines to optimize the print head path?
|
||||
virtual bool no_sort() const { return false; }
|
||||
|
||||
// Perform the fill.
|
||||
virtual Polylines fill_surface(const Surface &surface, const FillParams ¶ms);
|
||||
|
||||
static coord_t adjust_solid_spacing(const coord_t width, const coord_t distance);
|
||||
|
||||
protected:
|
||||
Fill() :
|
||||
layer_id(size_t(-1)),
|
||||
z(0.f),
|
||||
spacing(0.f),
|
||||
angle(0),
|
||||
link_max_length(0),
|
||||
loop_clipping(0)
|
||||
{};
|
||||
|
||||
// The expolygon may be modified by the method to avoid a copy.
|
||||
virtual void _fill_surface_single(
|
||||
const FillParams ¶ms,
|
||||
unsigned int thickness_layers,
|
||||
const std::pair<float, Point> &direction,
|
||||
ExPolygon &expolygon,
|
||||
Polylines* polylines_out) {};
|
||||
|
||||
virtual float _layer_angle(size_t idx) const {
|
||||
return (idx % 2) == 0 ? (M_PI/2.) : 0;
|
||||
}
|
||||
|
||||
std::pair<float, Point> _infill_direction(const Surface &surface) const;
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include "../libslic3r.h"
|
||||
|
||||
#include "FillBase.hpp"
|
||||
#include "Fill.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
@ -1,138 +0,0 @@
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../ClipperUtils.hpp"
|
||||
#include "../Surface.hpp"
|
||||
#include "../PrintConfig.hpp"
|
||||
|
||||
#include "FillBase.hpp"
|
||||
#include "FillConcentric.hpp"
|
||||
#include "FillHoneycomb.hpp"
|
||||
#include "Fill3DHoneycomb.hpp"
|
||||
#include "FillPlanePath.hpp"
|
||||
#include "FillRectilinear.hpp"
|
||||
#include "FillRectilinear2.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
Fill*
|
||||
Fill::new_from_type(const InfillPattern type)
|
||||
{
|
||||
switch (type) {
|
||||
case ipConcentric: return new FillConcentric();
|
||||
case ipHoneycomb: return new FillHoneycomb();
|
||||
case ip3DHoneycomb: return new Fill3DHoneycomb();
|
||||
|
||||
case ipRectilinear: return new FillRectilinear();
|
||||
case ipLine: return new FillLine();
|
||||
case ipGrid: return new FillGrid();
|
||||
case ipAlignedRectilinear: return new FillAlignedRectilinear();
|
||||
|
||||
case ipRectilinear2: return new FillRectilinear2();
|
||||
case ipGrid2: return new FillGrid2();
|
||||
case ipTriangles: return new FillTriangles();
|
||||
case ipStars: return new FillStars();
|
||||
case ipCubic: return new FillCubic();
|
||||
|
||||
case ipArchimedeanChords: return new FillArchimedeanChords();
|
||||
case ipHilbertCurve: return new FillHilbertCurve();
|
||||
case ipOctagramSpiral: return new FillOctagramSpiral();
|
||||
|
||||
default: CONFESS("unknown type"); return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Fill*
|
||||
Fill::new_from_type(const std::string &type)
|
||||
{
|
||||
static t_config_enum_values enum_keys_map = ConfigOptionEnum<InfillPattern>::get_enum_values();
|
||||
t_config_enum_values::const_iterator it = enum_keys_map.find(type);
|
||||
return (it == enum_keys_map.end()) ? NULL : new_from_type(InfillPattern(it->second));
|
||||
}
|
||||
|
||||
Polylines
|
||||
Fill::fill_surface(const Surface &surface, const FillParams ¶ms)
|
||||
{
|
||||
// Perform offset.
|
||||
ExPolygons expp = offset_ex(surface.expolygon, -scale_(this->spacing)/2);
|
||||
|
||||
// Create the infills for each of the regions.
|
||||
Polylines polylines_out;
|
||||
for (size_t i = 0; i < expp.size(); ++i)
|
||||
this->_fill_surface_single(
|
||||
params,
|
||||
surface.thickness_layers,
|
||||
this->_infill_direction(surface),
|
||||
expp[i],
|
||||
&polylines_out
|
||||
);
|
||||
return polylines_out;
|
||||
}
|
||||
|
||||
// Calculate a new spacing to fill width with possibly integer number of lines,
|
||||
// the first and last line being centered at the interval ends.
|
||||
// This function possibly increases the spacing, never decreases,
|
||||
// and for a narrow width the increase in spacing may become severe,
|
||||
// therefore the adjustment is limited to 20% increase.
|
||||
coord_t
|
||||
Fill::adjust_solid_spacing(const coord_t width, const coord_t distance)
|
||||
{
|
||||
assert(width >= 0);
|
||||
assert(distance > 0);
|
||||
// floor(width / distance)
|
||||
coord_t number_of_intervals = floor(width / distance);
|
||||
coord_t distance_new = (number_of_intervals == 0)
|
||||
? distance
|
||||
: (width / number_of_intervals);
|
||||
|
||||
const coordf_t factor = coordf_t(distance_new) / coordf_t(distance);
|
||||
assert(factor > 1. - 1e-5);
|
||||
|
||||
// How much could the extrusion width be increased? By 20%.
|
||||
const coordf_t factor_max = 1.2;
|
||||
if (factor > factor_max)
|
||||
distance_new = floor((double)distance * factor_max + 0.5);
|
||||
|
||||
return distance_new;
|
||||
}
|
||||
|
||||
// Returns orientation of the infill and the reference point of the infill pattern.
|
||||
// For a normal print, the reference point is the center of a bounding box of the STL.
|
||||
std::pair<float, Point>
|
||||
Fill::_infill_direction(const Surface &surface) const
|
||||
{
|
||||
// set infill angle
|
||||
float out_angle = this->angle;
|
||||
|
||||
// Bounding box is the bounding box of a Slic3r::PrintObject
|
||||
// The bounding box is only undefined in unit tests.
|
||||
Point out_shift = this->bounding_box.defined
|
||||
? this->bounding_box.center()
|
||||
: surface.expolygon.contour.bounding_box().center();
|
||||
|
||||
#if 0
|
||||
if (!this->bounding_box.defined) {
|
||||
printf("Fill::_infill_direction: empty bounding box!");
|
||||
} else {
|
||||
printf("Fill::_infill_direction: reference point %d, %d\n", out_shift.x, out_shift.y);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (surface.bridge_angle >= 0) {
|
||||
// use bridge angle
|
||||
//FIXME Vojtech: Add a debugf?
|
||||
// Slic3r::debugf "Filling bridge with angle %d\n", rad2deg($surface->bridge_angle);
|
||||
#ifdef SLIC3R_DEBUG
|
||||
printf("Filling bridge with angle %f\n", surface.bridge_angle);
|
||||
#endif
|
||||
out_angle = surface.bridge_angle;
|
||||
} else if (this->layer_id != size_t(-1)) {
|
||||
// alternate fill direction
|
||||
out_angle += this->_layer_angle(this->layer_id / surface.thickness_layers);
|
||||
}
|
||||
|
||||
out_angle += float(M_PI/2.);
|
||||
return std::pair<float, Point>(out_angle, out_shift);
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
@ -1,111 +0,0 @@
|
||||
#ifndef slic3r_FillBase_hpp_
|
||||
#define slic3r_FillBase_hpp_
|
||||
|
||||
#include <assert.h>
|
||||
#include <memory.h>
|
||||
#include <float.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../libslic3r.h"
|
||||
#include "../BoundingBox.hpp"
|
||||
#include "../ExPolygon.hpp"
|
||||
#include "../Polyline.hpp"
|
||||
#include "../PrintConfig.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class Surface;
|
||||
|
||||
struct FillParams
|
||||
{
|
||||
public:
|
||||
FillParams() : density(0), dont_connect(false), dont_adjust(false), complete(false) {};
|
||||
|
||||
// Fill density, fraction in <0, 1>
|
||||
float density;
|
||||
|
||||
// Don't connect the fill lines around the inner perimeter.
|
||||
bool dont_connect;
|
||||
|
||||
// Don't adjust spacing to fill the space evenly.
|
||||
bool dont_adjust;
|
||||
|
||||
// For Honeycomb.
|
||||
// we were requested to complete each loop;
|
||||
// in this case we don't try to make more continuous paths
|
||||
bool complete;
|
||||
};
|
||||
|
||||
class Fill
|
||||
{
|
||||
public:
|
||||
// Index of the layer.
|
||||
size_t layer_id;
|
||||
|
||||
// Z coordinate of the top print surface, in unscaled coordinates
|
||||
coordf_t z;
|
||||
|
||||
// in unscaled coordinates
|
||||
coordf_t spacing;
|
||||
|
||||
// in radians, ccw, 0 = East
|
||||
float angle;
|
||||
|
||||
// In scaled coordinates. Maximum lenght of a perimeter segment connecting two infill lines.
|
||||
// Used by the FillRectilinear2, FillGrid2, FillTriangles, FillStars and FillCubic.
|
||||
// If left to zero, the links will not be limited.
|
||||
coord_t link_max_length;
|
||||
|
||||
// In scaled coordinates. Used by the concentric infill pattern to clip the loops to create extrusion paths.
|
||||
coord_t loop_clipping;
|
||||
|
||||
// In scaled coordinates. Bounding box of the 2D projection of the object.
|
||||
BoundingBox bounding_box;
|
||||
|
||||
public:
|
||||
virtual ~Fill() {}
|
||||
|
||||
static Fill* new_from_type(const InfillPattern type);
|
||||
static Fill* new_from_type(const std::string &type);
|
||||
|
||||
void set_bounding_box(const BoundingBox &bb) { this->bounding_box = bb; }
|
||||
|
||||
// Use bridge flow for the fill?
|
||||
virtual bool use_bridge_flow() const { return false; }
|
||||
|
||||
// Do not sort the fill lines to optimize the print head path?
|
||||
virtual bool no_sort() const { return false; }
|
||||
|
||||
// Perform the fill.
|
||||
virtual Polylines fill_surface(const Surface &surface, const FillParams ¶ms);
|
||||
|
||||
static coord_t adjust_solid_spacing(const coord_t width, const coord_t distance);
|
||||
|
||||
protected:
|
||||
Fill() :
|
||||
layer_id(size_t(-1)),
|
||||
z(0.f),
|
||||
spacing(0.f),
|
||||
angle(0),
|
||||
link_max_length(0),
|
||||
loop_clipping(0)
|
||||
{};
|
||||
|
||||
// The expolygon may be modified by the method to avoid a copy.
|
||||
virtual void _fill_surface_single(
|
||||
const FillParams ¶ms,
|
||||
unsigned int thickness_layers,
|
||||
const std::pair<float, Point> &direction,
|
||||
ExPolygon &expolygon,
|
||||
Polylines* polylines_out) {};
|
||||
|
||||
virtual float _layer_angle(size_t idx) const {
|
||||
return (idx % 2) == 0 ? (M_PI/2.) : 0;
|
||||
}
|
||||
|
||||
std::pair<float, Point> _infill_direction(const Surface &surface) const;
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // slic3r_FillBase_hpp_
|
@ -1,7 +1,7 @@
|
||||
#ifndef slic3r_FillConcentric_hpp_
|
||||
#define slic3r_FillConcentric_hpp_
|
||||
|
||||
#include "FillBase.hpp"
|
||||
#include "Fill.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include "../libslic3r.h"
|
||||
|
||||
#include "FillBase.hpp"
|
||||
#include "Fill.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include "../libslic3r.h"
|
||||
|
||||
#include "FillBase.hpp"
|
||||
#include "Fill.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include "../libslic3r.h"
|
||||
|
||||
#include "FillBase.hpp"
|
||||
#include "Fill.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include "../libslic3r.h"
|
||||
|
||||
#include "FillBase.hpp"
|
||||
#include "Fill.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "Geometry.hpp"
|
||||
#include "Print.hpp"
|
||||
#include "Fill/Fill.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -239,13 +238,11 @@ Layer::make_fills()
|
||||
#endif
|
||||
|
||||
FOREACH_LAYERREGION(this, it_layerm) {
|
||||
LayerRegion &layerm = **it_layerm;
|
||||
layerm.fills.clear();
|
||||
make_fill(layerm, &layerm.fills);
|
||||
(*it_layerm)->make_fill();
|
||||
|
||||
#ifndef NDEBUG
|
||||
for (size_t i = 0; i < layerm.fills.entities.size(); ++i)
|
||||
assert(dynamic_cast<ExtrusionEntityCollection*>(layerm.fills.entities[i]) != NULL);
|
||||
for (size_t i = 0; i < (*it_layerm)->fills.entities.size(); ++i)
|
||||
assert(dynamic_cast<ExtrusionEntityCollection*>((*it_layerm)->fills.entities[i]) != NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ class LayerRegion
|
||||
void merge_slices();
|
||||
void prepare_fill_surfaces();
|
||||
void make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces);
|
||||
void make_fill();
|
||||
void process_external_surfaces(const Layer* lower_layer);
|
||||
double infill_area_threshold() const;
|
||||
|
||||
|
285
xs/src/libslic3r/LayerRegionFill.cpp
Normal file
285
xs/src/libslic3r/LayerRegionFill.cpp
Normal file
@ -0,0 +1,285 @@
|
||||
#include "Layer.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "Fill/Fill.hpp"
|
||||
#include "Geometry.hpp"
|
||||
#include "Print.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
#include "Surface.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
struct SurfaceGroupAttrib
|
||||
{
|
||||
SurfaceGroupAttrib() : is_solid(false), fw(0.f), pattern(-1) {}
|
||||
bool operator==(const SurfaceGroupAttrib &other) const
|
||||
{ return is_solid == other.is_solid && fw == other.fw && pattern == other.pattern; }
|
||||
bool is_solid;
|
||||
float fw;
|
||||
// pattern is of type InfillPattern, -1 for an unset pattern.
|
||||
int pattern;
|
||||
};
|
||||
|
||||
// Generate infills for a LayerRegion.
|
||||
// The LayerRegion at this point of time may contain
|
||||
// surfaces of various types (internal/bridge/top/bottom/solid).
|
||||
// The infills are generated on the groups of surfaces with a compatible type.
|
||||
// Fills an array of ExtrusionPathCollection objects containing the infills generated now
|
||||
// and the thin fills generated by generate_perimeters().
|
||||
void
|
||||
LayerRegion::make_fill()
|
||||
{
|
||||
this->fills.clear();
|
||||
|
||||
const double fill_density = this->region()->config.fill_density;
|
||||
const Flow infill_flow = this->flow(frInfill);
|
||||
const Flow solid_infill_flow = this->flow(frSolidInfill);
|
||||
const Flow top_solid_infill_flow = this->flow(frTopSolidInfill);
|
||||
|
||||
SurfaceCollection surfaces;
|
||||
|
||||
// merge adjacent surfaces
|
||||
// in case of bridge surfaces, the ones with defined angle will be attached to the ones
|
||||
// without any angle (shouldn't this logic be moved to process_external_surfaces()?)
|
||||
{
|
||||
Polygons polygons_bridged;
|
||||
polygons_bridged.reserve(this->fill_surfaces.surfaces.size());
|
||||
for (Surfaces::const_iterator it = this->fill_surfaces.surfaces.begin(); it != this->fill_surfaces.surfaces.end(); ++it)
|
||||
if (it->bridge_angle >= 0)
|
||||
append_to(polygons_bridged, (Polygons)*it);
|
||||
|
||||
// group surfaces by distinct properties (equal surface_type, thickness, thickness_layers, bridge_angle)
|
||||
// group is of type SurfaceCollection
|
||||
// FIXME: Use some smart heuristics to merge similar surfaces to eliminate tiny regions.
|
||||
std::vector<SurfacesConstPtr> groups;
|
||||
this->fill_surfaces.group(&groups);
|
||||
|
||||
// merge compatible groups (we can generate continuous infill for them)
|
||||
{
|
||||
// cache flow widths and patterns used for all solid groups
|
||||
// (we'll use them for comparing compatible groups)
|
||||
std::vector<SurfaceGroupAttrib> group_attrib(groups.size());
|
||||
for (size_t i = 0; i < groups.size(); ++i) {
|
||||
// we can only merge solid non-bridge surfaces, so discard
|
||||
// non-solid surfaces
|
||||
const Surface &surface = *groups[i].front();
|
||||
if (surface.is_solid() && (!surface.is_bridge() || this->layer()->id() == 0)) {
|
||||
group_attrib[i].is_solid = true;
|
||||
group_attrib[i].fw = (surface.surface_type == stTop) ? top_solid_infill_flow.width : solid_infill_flow.width;
|
||||
group_attrib[i].pattern = surface.is_external() ? this->region()->config.external_fill_pattern.value : ipRectilinear;
|
||||
}
|
||||
}
|
||||
// Loop through solid groups, find compatible groups and append them to this one.
|
||||
for (size_t i = 0; i < groups.size(); ++i) {
|
||||
if (!group_attrib[i].is_solid)
|
||||
continue;
|
||||
for (size_t j = i + 1; j < groups.size();) {
|
||||
if (group_attrib[i] == group_attrib[j]) {
|
||||
// groups are compatible, merge them
|
||||
append_to(groups[i], groups[j]);
|
||||
groups.erase(groups.begin() + j);
|
||||
group_attrib.erase(group_attrib.begin() + j);
|
||||
} else {
|
||||
++j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Give priority to bridges. Process the bridges in the first round, the rest of the surfaces in the 2nd round.
|
||||
for (size_t round = 0; round < 2; ++ round) {
|
||||
for (std::vector<SurfacesConstPtr>::const_iterator it_group = groups.begin(); it_group != groups.end(); ++ it_group) {
|
||||
const SurfacesConstPtr &group = *it_group;
|
||||
bool is_bridge = group.front()->bridge_angle >= 0;
|
||||
if (is_bridge != (round == 0))
|
||||
continue;
|
||||
|
||||
// Make a union of polygons defining the infiill regions of a group, use a safety offset.
|
||||
Polygons union_p = union_(to_polygons(group), true);
|
||||
|
||||
// Subtract surfaces having a defined bridge_angle from any other, use a safety offset.
|
||||
if (!polygons_bridged.empty() && !is_bridge)
|
||||
union_p = diff(union_p, polygons_bridged, true);
|
||||
|
||||
// subtract any other surface already processed
|
||||
//FIXME Vojtech: Because the bridge surfaces came first, they are subtracted twice!
|
||||
surfaces.append(
|
||||
diff_ex(union_p, to_polygons(surfaces), true),
|
||||
*group.front() // template
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we need to detect any narrow surfaces that might collapse
|
||||
// when adding spacing below
|
||||
// such narrow surfaces are often generated in sloping walls
|
||||
// by bridge_over_infill() and combine_infill() as a result of the
|
||||
// subtraction of the combinable area from the layer infill area,
|
||||
// which leaves small areas near the perimeters
|
||||
// we are going to grow such regions by overlapping them with the void (if any)
|
||||
// TODO: detect and investigate whether there could be narrow regions without
|
||||
// any void neighbors
|
||||
{
|
||||
coord_t distance_between_surfaces = std::max(
|
||||
std::max(infill_flow.scaled_spacing(), solid_infill_flow.scaled_spacing()),
|
||||
top_solid_infill_flow.scaled_spacing()
|
||||
);
|
||||
|
||||
Polygons surfaces_polygons = (Polygons)surfaces;
|
||||
Polygons collapsed = diff(
|
||||
surfaces_polygons,
|
||||
offset2(surfaces_polygons, -distance_between_surfaces/2, +distance_between_surfaces/2),
|
||||
true
|
||||
);
|
||||
|
||||
Polygons to_subtract;
|
||||
surfaces.filter_by_type(stInternalVoid, &to_subtract);
|
||||
|
||||
append_to(to_subtract, collapsed);
|
||||
surfaces.append(
|
||||
intersection_ex(
|
||||
offset(collapsed, distance_between_surfaces),
|
||||
to_subtract,
|
||||
true
|
||||
),
|
||||
stInternalSolid
|
||||
);
|
||||
}
|
||||
|
||||
if (false) {
|
||||
// require "Slic3r/SVG.pm";
|
||||
// Slic3r::SVG::output("fill_" . $layerm->print_z . ".svg",
|
||||
// expolygons => [ map $_->expolygon, grep !$_->is_solid, @surfaces ],
|
||||
// red_expolygons => [ map $_->expolygon, grep $_->is_solid, @surfaces ],
|
||||
// );
|
||||
}
|
||||
|
||||
for (Surfaces::const_iterator surface_it = surfaces.surfaces.begin();
|
||||
surface_it != surfaces.surfaces.end(); ++surface_it) {
|
||||
|
||||
const Surface &surface = *surface_it;
|
||||
if (surface.surface_type == stInternalVoid)
|
||||
continue;
|
||||
|
||||
InfillPattern fill_pattern = this->region()->config.fill_pattern.value;
|
||||
double density = fill_density;
|
||||
FlowRole role = (surface.surface_type == stTop) ? frTopSolidInfill
|
||||
: surface.is_solid() ? frSolidInfill
|
||||
: frInfill;
|
||||
const bool is_bridge = this->layer()->id() > 0 && surface.is_bridge();
|
||||
|
||||
if (surface.is_solid()) {
|
||||
density = 100.;
|
||||
fill_pattern = (surface.is_external() && !is_bridge)
|
||||
? this->region()->config.external_fill_pattern.value
|
||||
: ipRectilinear;
|
||||
} else if (density <= 0)
|
||||
continue;
|
||||
|
||||
// get filler object
|
||||
#if SLIC3R_CPPVER >= 11
|
||||
std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(fill_pattern));
|
||||
#else
|
||||
std::auto_ptr<Fill> f = std::auto_ptr<Fill>(Fill::new_from_type(fill_pattern));
|
||||
#endif
|
||||
f->set_bounding_box(this->layer()->object()->bounding_box());
|
||||
|
||||
// calculate the actual flow we'll be using for this infill
|
||||
coordf_t h = (surface.thickness == -1) ? this->layer()->height : surface.thickness;
|
||||
Flow flow = this->region()->flow(
|
||||
role,
|
||||
h,
|
||||
is_bridge || f->use_bridge_flow(), // bridge flow?
|
||||
this->layer()->id() == 0, // first layer?
|
||||
-1, // auto width
|
||||
*this->layer()->object()
|
||||
);
|
||||
|
||||
// calculate flow spacing for infill pattern generation
|
||||
bool using_internal_flow = false;
|
||||
if (!surface.is_solid() && !is_bridge) {
|
||||
// it's internal infill, so we can calculate a generic flow spacing
|
||||
// for all layers, for avoiding the ugly effect of
|
||||
// misaligned infill on first layer because of different extrusion width and
|
||||
// layer height
|
||||
Flow internal_flow = this->region()->flow(
|
||||
frInfill,
|
||||
this->layer()->object()->config.layer_height.value, // TODO: handle infill_every_layers?
|
||||
false, // no bridge
|
||||
false, // no first layer
|
||||
-1, // auto width
|
||||
*this->layer()->object()
|
||||
);
|
||||
f->spacing = internal_flow.spacing();
|
||||
using_internal_flow = true;
|
||||
} else {
|
||||
f->spacing = flow.spacing();
|
||||
}
|
||||
|
||||
f->layer_id = this->layer()->id();
|
||||
f->z = this->layer()->print_z;
|
||||
f->angle = Geometry::deg2rad(this->region()->config.fill_angle.value);
|
||||
|
||||
// Maximum length of the perimeter segment linking two infill lines.
|
||||
f->link_max_length = (!is_bridge && density > 80)
|
||||
? scale_(3 * f->spacing)
|
||||
: 0;
|
||||
|
||||
// Used by the concentric infill pattern to clip the loops to create extrusion paths.
|
||||
f->loop_clipping = scale_(flow.nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER;
|
||||
|
||||
// apply half spacing using this flow's own spacing and generate infill
|
||||
FillParams params;
|
||||
params.density = density/100;
|
||||
params.dont_adjust = false;
|
||||
Polylines polylines = f->fill_surface(surface, params);
|
||||
if (polylines.empty())
|
||||
continue;
|
||||
|
||||
// calculate actual flow from spacing (which might have been adjusted by the infill
|
||||
// pattern generator)
|
||||
if (using_internal_flow) {
|
||||
// if we used the internal flow we're not doing a solid infill
|
||||
// so we can safely ignore the slight variation that might have
|
||||
// been applied to f->spacing
|
||||
} else {
|
||||
flow = Flow::new_from_spacing(f->spacing, flow.nozzle_diameter, h, is_bridge || f->use_bridge_flow());
|
||||
}
|
||||
|
||||
// Save into layer.
|
||||
ExtrusionEntityCollection* coll = new ExtrusionEntityCollection();
|
||||
coll->no_sort = f->no_sort();
|
||||
this->fills.entities.push_back(coll);
|
||||
|
||||
{
|
||||
ExtrusionRole role;
|
||||
if (is_bridge) {
|
||||
role = erBridgeInfill;
|
||||
} else if (surface.is_solid()) {
|
||||
role = (surface.surface_type == stTop) ? erTopSolidInfill : erSolidInfill;
|
||||
} else {
|
||||
role = erInternalInfill;
|
||||
}
|
||||
|
||||
ExtrusionPath templ(role);
|
||||
templ.mm3_per_mm = flow.mm3_per_mm();
|
||||
templ.width = flow.width;
|
||||
templ.height = flow.height;
|
||||
|
||||
coll->append(STDMOVE(polylines), templ);
|
||||
}
|
||||
}
|
||||
|
||||
// add thin fill regions
|
||||
// thin_fills are of C++ Slic3r::ExtrusionEntityCollection, perl type Slic3r::ExtrusionPath::Collection
|
||||
// Unpacks the collection, creates multiple collections per path so that they will
|
||||
// be individually included in the nearest neighbor search.
|
||||
// The path type could be ExtrusionPath, ExtrusionLoop or ExtrusionEntityCollection.
|
||||
for (ExtrusionEntitiesPtr::const_iterator thin_fill = this->thin_fills.entities.begin(); thin_fill != this->thin_fills.entities.end(); ++ thin_fill) {
|
||||
ExtrusionEntityCollection* coll = new ExtrusionEntityCollection();
|
||||
this->fills.entities.push_back(coll);
|
||||
coll->append(**thin_fill);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
@ -1,7 +1,7 @@
|
||||
#include "SLAPrint.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "ExtrusionEntity.hpp"
|
||||
#include "Fill/FillBase.hpp"
|
||||
#include "Fill/Fill.hpp"
|
||||
#include "Geometry.hpp"
|
||||
#include "Surface.hpp"
|
||||
#include <iostream>
|
||||
|
@ -54,7 +54,7 @@ extern "C" {
|
||||
#include <ClipperUtils.hpp>
|
||||
#include <Config.hpp>
|
||||
#include <ExPolygon.hpp>
|
||||
#include <Fill/FillBase.hpp>
|
||||
#include <Fill/Fill.hpp>
|
||||
#include <MultiPoint.hpp>
|
||||
#include <Point.hpp>
|
||||
#include <Polygon.hpp>
|
||||
|
@ -71,8 +71,5 @@ new_from_type(CLASS, type)
|
||||
|
||||
%package{Slic3r::Filler};
|
||||
|
||||
void make_fill(LayerRegion* layerm, ExtrusionEntityCollection* out)
|
||||
%code{% make_fill(*layerm, out); %};
|
||||
|
||||
coord_t adjust_solid_spacing(coord_t width, coord_t distance)
|
||||
%code{% RETVAL = Fill::adjust_solid_spacing(width, distance); %};
|
||||
|
Loading…
x
Reference in New Issue
Block a user