完善下拉选择界面
This commit is contained in:
parent
150717af1e
commit
f6c2e90254
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Creator: CorelDRAW 2020 (64-Bit 评估版) -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="35.7338mm" height="36.4897mm" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
|
||||||
|
viewBox="0 0 2014.15 2056.75"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:xodm="http://www.corel.com/coreldraw/odm/2003">
|
||||||
|
<defs>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
.fil0 {fill:#332C2B}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g id="图层_x0020_1">
|
||||||
|
<metadata id="CorelCorpID_0Corel-Layer"/>
|
||||||
|
<path class="fil0" d="M1894.43 1937.72l0 -148.83c-10.22,10.3 -21.46,20.03 -33.81,29.11 -114.98,84.54 -255.66,64.93 -358.46,-51.4 -89.28,-100.78 -78.46,-269.18 -75.75,-425.42 3.38,-166.38 5.41,-331.41 8.12,-496.43 2.03,-158.94 31.79,-342.23 -64.25,-434.89 -89.28,-85.9 -252.95,-48.7 -287.45,127.15 -17.59,88.6 2.03,846.11 -4.73,994.9 -4.06,79.81 -35.84,136.62 -66.28,185.99 -68.31,112.95 -236.72,157.59 -352.37,90.63 -210.34,-121.74 -163.67,-367.25 -169.76,-582.33 -4.73,-164.36 -4.06,-334.12 -4.73,-501.17 -0.68,-78.45 4.73,-163 -16.91,-232.66 -47.34,-150.15 -226.57,-175.17 -307.06,-64.93 -23.02,31.69 -35.01,58.61 -41.26,88.96l0 1421.31 1774.72 0zm0 -805.21l0 -46.3 0 -8.79 0 -8.79 0 -8.79 0 -940.79 -1774.72 0 0 178.31c11.22,-9.34 23.37,-18.25 36.52,-26.81 173.14,-112.94 397.69,5.41 430.83,244.84 13.53,94.68 10.15,624.26 11.5,744.65 1.35,155.56 -23,340.2 87.25,416.63 133.91,92.66 273.24,-19.62 283.39,-158.94 8.11,-106.86 -3.38,-369.28 -3.38,-496.43 0.68,-156.91 -2.03,-342.9 10.82,-495.76 5.41,-66.96 41.26,-138.65 71.02,-179.91 80.48,-110.24 234.69,-150.82 351.02,-69.66 188.02,131.21 144.73,376.05 142.03,601.94 -2.71,167.06 -6.76,330.73 -9.47,496.44 -0.68,78.45 -10.15,171.11 14.88,239.42 55.46,151.5 226.58,162.32 302.33,43.96 41.25,-64.93 39.22,-123.1 41.25,-211.7 1.72,-105.29 2.89,-209.22 4.73,-313.51zm119.71 924.24l-2014.15 0 0 -2056.75 2014.15 0 0 2056.75 0 0z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
|
@ -0,0 +1,843 @@
|
||||||
|
#include <assert.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 "FillBase.hpp"
|
||||||
|
#include "FillRectilinear.hpp"
|
||||||
|
#include "FillLightning.hpp"
|
||||||
|
#include "FillConcentricInternal.hpp"
|
||||||
|
#include "FillConcentric.hpp"
|
||||||
|
|
||||||
|
#define NARROW_INFILL_AREA_THRESHOLD 3
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
struct SurfaceFillParams
|
||||||
|
{
|
||||||
|
// Zero based extruder ID.
|
||||||
|
unsigned int extruder = 0;
|
||||||
|
// Infill pattern, adjusted for the density etc.
|
||||||
|
InfillPattern pattern = InfillPattern(0);
|
||||||
|
|
||||||
|
// FillBase
|
||||||
|
// in unscaled coordinates
|
||||||
|
coordf_t spacing = 0.;
|
||||||
|
// infill / perimeter overlap, in unscaled coordinates
|
||||||
|
coordf_t overlap = 0.;
|
||||||
|
// Angle as provided by the region config, in radians.
|
||||||
|
float angle = 0.f;
|
||||||
|
// Is bridging used for this fill? Bridging parameters may be used even if this->flow.bridge() is not set.
|
||||||
|
bool bridge;
|
||||||
|
// Non-negative for a bridge.
|
||||||
|
float bridge_angle = 0.f;
|
||||||
|
|
||||||
|
// FillParams
|
||||||
|
float density = 0.f;
|
||||||
|
// Don't adjust spacing to fill the space evenly.
|
||||||
|
// bool dont_adjust = false;
|
||||||
|
// Length of the infill anchor along the perimeter line.
|
||||||
|
// 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
|
||||||
|
// width, height of extrusion, nozzle diameter, is bridge
|
||||||
|
// For the output, for fill generator.
|
||||||
|
Flow flow;
|
||||||
|
|
||||||
|
// For the output
|
||||||
|
ExtrusionRole extrusion_role = ExtrusionRole(0);
|
||||||
|
|
||||||
|
// Various print settings?
|
||||||
|
|
||||||
|
// Index of this entry in a linear vector.
|
||||||
|
size_t idx = 0;
|
||||||
|
// infill speed settings
|
||||||
|
float sparse_infill_speed = 0;
|
||||||
|
float top_surface_speed = 0;
|
||||||
|
float solid_infill_speed = 0;
|
||||||
|
|
||||||
|
bool operator<(const SurfaceFillParams &rhs) const {
|
||||||
|
#define RETURN_COMPARE_NON_EQUAL(KEY) if (this->KEY < rhs.KEY) return true; if (this->KEY > rhs.KEY) return false;
|
||||||
|
#define RETURN_COMPARE_NON_EQUAL_TYPED(TYPE, KEY) if (TYPE(this->KEY) < TYPE(rhs.KEY)) return true; if (TYPE(this->KEY) > TYPE(rhs.KEY)) return false;
|
||||||
|
|
||||||
|
// Sort first by decreasing bridging angle, so that the bridges are processed with priority when trimming one layer by the other.
|
||||||
|
if (this->bridge_angle > rhs.bridge_angle) return true;
|
||||||
|
if (this->bridge_angle < rhs.bridge_angle) return false;
|
||||||
|
|
||||||
|
RETURN_COMPARE_NON_EQUAL(extruder);
|
||||||
|
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, pattern);
|
||||||
|
RETURN_COMPARE_NON_EQUAL(spacing);
|
||||||
|
RETURN_COMPARE_NON_EQUAL(overlap);
|
||||||
|
RETURN_COMPARE_NON_EQUAL(angle);
|
||||||
|
RETURN_COMPARE_NON_EQUAL(density);
|
||||||
|
// 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(flow.width());
|
||||||
|
RETURN_COMPARE_NON_EQUAL(flow.height());
|
||||||
|
RETURN_COMPARE_NON_EQUAL(flow.nozzle_diameter());
|
||||||
|
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, bridge);
|
||||||
|
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, extrusion_role);
|
||||||
|
RETURN_COMPARE_NON_EQUAL(sparse_infill_speed);
|
||||||
|
RETURN_COMPARE_NON_EQUAL(top_surface_speed);
|
||||||
|
RETURN_COMPARE_NON_EQUAL(solid_infill_speed);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const SurfaceFillParams &rhs) const {
|
||||||
|
return this->extruder == rhs.extruder &&
|
||||||
|
this->pattern == rhs.pattern &&
|
||||||
|
this->spacing == rhs.spacing &&
|
||||||
|
this->overlap == rhs.overlap &&
|
||||||
|
this->angle == rhs.angle &&
|
||||||
|
this->bridge == rhs.bridge &&
|
||||||
|
// this->bridge_angle == rhs.bridge_angle &&
|
||||||
|
this->density == rhs.density &&
|
||||||
|
// this->dont_adjust == rhs.dont_adjust &&
|
||||||
|
this->anchor_length == rhs.anchor_length &&
|
||||||
|
this->anchor_length_max == rhs.anchor_length_max &&
|
||||||
|
this->flow == rhs.flow &&
|
||||||
|
this->extrusion_role == rhs.extrusion_role &&
|
||||||
|
this->sparse_infill_speed == rhs.sparse_infill_speed &&
|
||||||
|
this->top_surface_speed == rhs.top_surface_speed &&
|
||||||
|
this->solid_infill_speed == rhs.solid_infill_speed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SurfaceFill {
|
||||||
|
SurfaceFill(const SurfaceFillParams& params) : region_id(size_t(-1)), surface(stCount, ExPolygon()), params(params) {}
|
||||||
|
|
||||||
|
size_t region_id;
|
||||||
|
Surface surface;
|
||||||
|
ExPolygons expolygons;
|
||||||
|
SurfaceFillParams params;
|
||||||
|
// BBS
|
||||||
|
std::vector<size_t> region_id_group;
|
||||||
|
ExPolygons no_overlap_expolygons;
|
||||||
|
};
|
||||||
|
|
||||||
|
// BBS: used to judge whether the internal solid infill area is narrow
|
||||||
|
static bool is_narrow_infill_area(const ExPolygon& expolygon)
|
||||||
|
{
|
||||||
|
ExPolygons offsets = offset_ex(expolygon, -scale_(NARROW_INFILL_AREA_THRESHOLD));
|
||||||
|
if (offsets.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<SurfaceFill> group_fills(const Layer &layer)
|
||||||
|
{
|
||||||
|
std::vector<SurfaceFill> surface_fills;
|
||||||
|
|
||||||
|
// Fill in a map of a region & surface to SurfaceFillParams.
|
||||||
|
std::set<SurfaceFillParams> set_surface_params;
|
||||||
|
std::vector<std::vector<const SurfaceFillParams*>> region_to_surface_params(layer.regions().size(), std::vector<const SurfaceFillParams*>());
|
||||||
|
SurfaceFillParams params;
|
||||||
|
bool has_internal_voids = false;
|
||||||
|
const PrintObjectConfig& object_config = layer.object()->config();
|
||||||
|
for (size_t region_id = 0; region_id < layer.regions().size(); ++ region_id) {
|
||||||
|
const LayerRegion &layerm = *layer.regions()[region_id];
|
||||||
|
region_to_surface_params[region_id].assign(layerm.fill_surfaces.size(), nullptr);
|
||||||
|
for (const Surface &surface : layerm.fill_surfaces.surfaces)
|
||||||
|
if (surface.surface_type == stInternalVoid)
|
||||||
|
has_internal_voids = true;
|
||||||
|
else {
|
||||||
|
const PrintRegionConfig ®ion_config = layerm.region().config();
|
||||||
|
FlowRole extrusion_role = surface.is_top() ? frTopSolidInfill : (surface.is_solid() ? frSolidInfill : frInfill);
|
||||||
|
bool is_bridge = layer.id() > 0 && surface.is_bridge();
|
||||||
|
params.extruder = layerm.region().extruder(extrusion_role);
|
||||||
|
params.pattern = region_config.sparse_infill_pattern.value;
|
||||||
|
params.density = float(region_config.sparse_infill_density);
|
||||||
|
|
||||||
|
if (surface.is_solid()) {
|
||||||
|
params.density = 100.f;
|
||||||
|
//FIXME for non-thick bridges, shall we allow a bottom surface pattern?
|
||||||
|
if (surface.is_solid_infill())
|
||||||
|
params.pattern = region_config.internal_solid_infill_pattern.value;
|
||||||
|
else if (surface.is_external() && !is_bridge)
|
||||||
|
params.pattern = surface.is_top() ? region_config.top_surface_pattern.value : region_config.bottom_surface_pattern.value;
|
||||||
|
else
|
||||||
|
params.pattern = region_config.top_surface_pattern == ipMonotonic ? ipMonotonic : ipRectilinear;
|
||||||
|
|
||||||
|
} else if (params.density <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
params.extrusion_role =
|
||||||
|
is_bridge ?
|
||||||
|
erBridgeInfill :
|
||||||
|
(surface.is_solid() ?
|
||||||
|
(surface.is_top() ? erTopSolidInfill : (surface.is_bottom()? erBottomSurface : erSolidInfill)) :
|
||||||
|
erInternalInfill);
|
||||||
|
params.bridge_angle = float(surface.bridge_angle);
|
||||||
|
params.angle = float(Geometry::deg2rad(region_config.infill_direction.value));
|
||||||
|
|
||||||
|
// Calculate the actual flow we'll be using for this infill.
|
||||||
|
params.bridge = is_bridge || Fill::use_bridge_flow(params.pattern);
|
||||||
|
params.flow = params.bridge ?
|
||||||
|
//BBS: always enable thick bridge for internal bridge
|
||||||
|
layerm.bridging_flow(extrusion_role, (surface.is_bridge() && !surface.is_external()) || object_config.thick_bridges) :
|
||||||
|
layerm.flow(extrusion_role, (surface.thickness == -1) ? layer.height : surface.thickness);
|
||||||
|
//BBS: record speed params
|
||||||
|
if (!params.bridge) {
|
||||||
|
if (params.extrusion_role == erInternalInfill)
|
||||||
|
params.sparse_infill_speed = region_config.sparse_infill_speed;
|
||||||
|
else if (params.extrusion_role == erTopSolidInfill)
|
||||||
|
params.top_surface_speed = region_config.top_surface_speed;
|
||||||
|
else if (params.extrusion_role == erSolidInfill)
|
||||||
|
params.solid_infill_speed = region_config.internal_solid_infill_speed;
|
||||||
|
}
|
||||||
|
// Calculate flow spacing for infill pattern generation.
|
||||||
|
if (surface.is_solid() || is_bridge) {
|
||||||
|
params.spacing = params.flow.spacing();
|
||||||
|
// Don't limit anchor length for solid or bridging infill.
|
||||||
|
params.anchor_length = 1000.f;
|
||||||
|
params.anchor_length_max = 1000.f;
|
||||||
|
} else {
|
||||||
|
// Internal infill. Calculating infill line spacing independent of the current layer height and 1st layer status,
|
||||||
|
// so that internall infill will be aligned over all layers of the current region.
|
||||||
|
params.spacing = layerm.region().flow(*layer.object(), frInfill, layer.object()->config().layer_height, false).spacing();
|
||||||
|
// Anchor a sparse infill to inner perimeters with the following anchor length:
|
||||||
|
params.anchor_length = float(region_config.sparse_infill_anchor);
|
||||||
|
if (region_config.sparse_infill_anchor.percent)
|
||||||
|
params.anchor_length = float(params.anchor_length * 0.01 * params.spacing);
|
||||||
|
params.anchor_length_max = float(region_config.sparse_infill_anchor_max);
|
||||||
|
if (region_config.sparse_infill_anchor_max.percent)
|
||||||
|
params.anchor_length_max = float(params.anchor_length_max * 0.01 * params.spacing);
|
||||||
|
params.anchor_length = std::min(params.anchor_length, params.anchor_length_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it_params = set_surface_params.find(params);
|
||||||
|
if (it_params == set_surface_params.end())
|
||||||
|
it_params = set_surface_params.insert(it_params, params);
|
||||||
|
region_to_surface_params[region_id][&surface - &layerm.fill_surfaces.surfaces.front()] = &(*it_params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
surface_fills.reserve(set_surface_params.size());
|
||||||
|
for (const SurfaceFillParams ¶ms : set_surface_params) {
|
||||||
|
const_cast<SurfaceFillParams&>(params).idx = surface_fills.size();
|
||||||
|
surface_fills.emplace_back(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t region_id = 0; region_id < layer.regions().size(); ++ region_id) {
|
||||||
|
const LayerRegion &layerm = *layer.regions()[region_id];
|
||||||
|
for (const Surface &surface : layerm.fill_surfaces.surfaces)
|
||||||
|
if (surface.surface_type != stInternalVoid) {
|
||||||
|
const SurfaceFillParams *params = region_to_surface_params[region_id][&surface - &layerm.fill_surfaces.surfaces.front()];
|
||||||
|
if (params != nullptr) {
|
||||||
|
SurfaceFill &fill = surface_fills[params->idx];
|
||||||
|
if (fill.region_id == size_t(-1)) {
|
||||||
|
fill.region_id = region_id;
|
||||||
|
fill.surface = surface;
|
||||||
|
fill.expolygons.emplace_back(std::move(fill.surface.expolygon));
|
||||||
|
//BBS
|
||||||
|
fill.region_id_group.push_back(region_id);
|
||||||
|
fill.no_overlap_expolygons = layerm.fill_no_overlap_expolygons;
|
||||||
|
} else {
|
||||||
|
fill.expolygons.emplace_back(surface.expolygon);
|
||||||
|
//BBS
|
||||||
|
auto t = find(fill.region_id_group.begin(), fill.region_id_group.end(), region_id);
|
||||||
|
if (t == fill.region_id_group.end()) {
|
||||||
|
fill.region_id_group.push_back(region_id);
|
||||||
|
fill.no_overlap_expolygons = union_ex(fill.no_overlap_expolygons, layerm.fill_no_overlap_expolygons);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Polygons all_polygons;
|
||||||
|
for (SurfaceFill &fill : surface_fills)
|
||||||
|
if (! fill.expolygons.empty()) {
|
||||||
|
if (fill.expolygons.size() > 1 || ! all_polygons.empty()) {
|
||||||
|
Polygons polys = to_polygons(std::move(fill.expolygons));
|
||||||
|
// Make a union of polygons, use a safety offset, subtract the preceding polygons.
|
||||||
|
// Bridges are processed first (see SurfaceFill::operator<())
|
||||||
|
fill.expolygons = all_polygons.empty() ? union_safety_offset_ex(polys) : diff_ex(polys, all_polygons, ApplySafetyOffset::Yes);
|
||||||
|
append(all_polygons, std::move(polys));
|
||||||
|
} else if (&fill != &surface_fills.back())
|
||||||
|
append(all_polygons, to_polygons(fill.expolygons));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
if (has_internal_voids) {
|
||||||
|
// Internal voids are generated only if "infill_only_where_needed" or "infill_every_layers" are active.
|
||||||
|
coord_t distance_between_surfaces = 0;
|
||||||
|
Polygons surfaces_polygons;
|
||||||
|
Polygons voids;
|
||||||
|
int region_internal_infill = -1;
|
||||||
|
int region_solid_infill = -1;
|
||||||
|
int region_some_infill = -1;
|
||||||
|
for (SurfaceFill &surface_fill : surface_fills)
|
||||||
|
if (! surface_fill.expolygons.empty()) {
|
||||||
|
distance_between_surfaces = std::max(distance_between_surfaces, surface_fill.params.flow.scaled_spacing());
|
||||||
|
append((surface_fill.surface.surface_type == stInternalVoid) ? voids : surfaces_polygons, to_polygons(surface_fill.expolygons));
|
||||||
|
if (surface_fill.surface.surface_type == stInternalSolid)
|
||||||
|
region_internal_infill = (int)surface_fill.region_id;
|
||||||
|
if (surface_fill.surface.is_solid())
|
||||||
|
region_solid_infill = (int)surface_fill.region_id;
|
||||||
|
if (surface_fill.surface.surface_type != stInternalVoid)
|
||||||
|
region_some_infill = (int)surface_fill.region_id;
|
||||||
|
}
|
||||||
|
if (! voids.empty() && ! surfaces_polygons.empty()) {
|
||||||
|
// First clip voids by the printing polygons, as the voids were ignored by the loop above during mutual clipping.
|
||||||
|
voids = diff(voids, surfaces_polygons);
|
||||||
|
// Corners of infill regions, which would not be filled with an extrusion path with a radius of distance_between_surfaces/2
|
||||||
|
Polygons collapsed = diff(
|
||||||
|
surfaces_polygons,
|
||||||
|
opening(surfaces_polygons, float(distance_between_surfaces /2), float(distance_between_surfaces / 2 + ClipperSafetyOffset)));
|
||||||
|
//FIXME why the voids are added to collapsed here? First it is expensive, second the result may lead to some unwanted regions being
|
||||||
|
// added if two offsetted void regions merge.
|
||||||
|
// polygons_append(voids, collapsed);
|
||||||
|
ExPolygons extensions = intersection_ex(expand(collapsed, float(distance_between_surfaces)), voids, ApplySafetyOffset::Yes);
|
||||||
|
// Now find an internal infill SurfaceFill to add these extrusions to.
|
||||||
|
SurfaceFill *internal_solid_fill = nullptr;
|
||||||
|
unsigned int region_id = 0;
|
||||||
|
if (region_internal_infill != -1)
|
||||||
|
region_id = region_internal_infill;
|
||||||
|
else if (region_solid_infill != -1)
|
||||||
|
region_id = region_solid_infill;
|
||||||
|
else if (region_some_infill != -1)
|
||||||
|
region_id = region_some_infill;
|
||||||
|
const LayerRegion& layerm = *layer.regions()[region_id];
|
||||||
|
for (SurfaceFill &surface_fill : surface_fills)
|
||||||
|
if (surface_fill.surface.surface_type == stInternalSolid && std::abs(layer.height - surface_fill.params.flow.height()) < EPSILON) {
|
||||||
|
internal_solid_fill = &surface_fill;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (internal_solid_fill == nullptr) {
|
||||||
|
// Produce another solid fill.
|
||||||
|
params.extruder = layerm.region().extruder(frSolidInfill);
|
||||||
|
params.pattern = layerm.region().config().top_surface_pattern == ipMonotonic ? ipMonotonic : ipRectilinear;
|
||||||
|
params.density = 100.f;
|
||||||
|
params.extrusion_role = erInternalInfill;
|
||||||
|
params.angle = float(Geometry::deg2rad(layerm.region().config().infill_direction.value));
|
||||||
|
// calculate the actual flow we'll be using for this infill
|
||||||
|
params.flow = layerm.flow(frSolidInfill);
|
||||||
|
params.spacing = params.flow.spacing();
|
||||||
|
surface_fills.emplace_back(params);
|
||||||
|
surface_fills.back().surface.surface_type = stInternalSolid;
|
||||||
|
surface_fills.back().surface.thickness = layer.height;
|
||||||
|
surface_fills.back().expolygons = std::move(extensions);
|
||||||
|
} else {
|
||||||
|
append(extensions, std::move(internal_solid_fill->expolygons));
|
||||||
|
internal_solid_fill->expolygons = union_ex(extensions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BBS: detect narrow internal solid infill area and use ipConcentricInternal pattern instead
|
||||||
|
if (layer.object()->config().detect_narrow_internal_solid_infill) {
|
||||||
|
size_t surface_fills_size = surface_fills.size();
|
||||||
|
for (size_t i = 0; i < surface_fills_size; i++) {
|
||||||
|
if (surface_fills[i].surface.surface_type != stInternalSolid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
size_t expolygons_size = surface_fills[i].expolygons.size();
|
||||||
|
std::vector<size_t> narrow_expolygons_index;
|
||||||
|
narrow_expolygons_index.reserve(expolygons_size);
|
||||||
|
// BBS: get the index list of narrow expolygon
|
||||||
|
for (size_t j = 0; j < expolygons_size; j++)
|
||||||
|
if (is_narrow_infill_area(surface_fills[i].expolygons[j]))
|
||||||
|
narrow_expolygons_index.push_back(j);
|
||||||
|
|
||||||
|
if (narrow_expolygons_index.size() == 0) {
|
||||||
|
// BBS: has no narrow expolygon
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (narrow_expolygons_index.size() == expolygons_size) {
|
||||||
|
// BBS: all expolygons are narrow, directly change the fill pattern
|
||||||
|
surface_fills[i].params.pattern = ipConcentricInternal;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// BBS: some expolygons are narrow, spilit surface_fills[i] and rearrange the expolygons
|
||||||
|
params = surface_fills[i].params;
|
||||||
|
params.pattern = ipConcentricInternal;
|
||||||
|
surface_fills.emplace_back(params);
|
||||||
|
surface_fills.back().region_id = surface_fills[i].region_id;
|
||||||
|
surface_fills.back().surface.surface_type = stInternalSolid;
|
||||||
|
surface_fills.back().surface.thickness = surface_fills[i].surface.thickness;
|
||||||
|
surface_fills.back().region_id_group = surface_fills[i].region_id_group;
|
||||||
|
surface_fills.back().no_overlap_expolygons = surface_fills[i].no_overlap_expolygons;
|
||||||
|
for (size_t j = 0; j < narrow_expolygons_index.size(); j++) {
|
||||||
|
// BBS: move the narrow expolygons to new surface_fills.back();
|
||||||
|
surface_fills.back().expolygons.emplace_back(std::move(surface_fills[i].expolygons[narrow_expolygons_index[j]]));
|
||||||
|
}
|
||||||
|
for (int j = narrow_expolygons_index.size() - 1; j >= 0; j--) {
|
||||||
|
// BBS: delete the narrow expolygons from old surface_fills
|
||||||
|
surface_fills[i].expolygons.erase(surface_fills[i].expolygons.begin() + narrow_expolygons_index[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return surface_fills;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||||
|
void export_group_fills_to_svg(const char *path, const std::vector<SurfaceFill> &fills)
|
||||||
|
{
|
||||||
|
BoundingBox bbox;
|
||||||
|
for (const auto &fill : fills)
|
||||||
|
for (const auto &expoly : fill.expolygons)
|
||||||
|
bbox.merge(get_extents(expoly));
|
||||||
|
Point legend_size = export_surface_type_legend_to_svg_box_size();
|
||||||
|
Point legend_pos(bbox.min(0), bbox.max(1));
|
||||||
|
bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1)));
|
||||||
|
|
||||||
|
SVG svg(path, bbox);
|
||||||
|
const float transparency = 0.5f;
|
||||||
|
for (const auto &fill : fills)
|
||||||
|
for (const auto &expoly : fill.expolygons)
|
||||||
|
svg.draw(expoly, surface_type_to_color_name(fill.surface.surface_type), transparency);
|
||||||
|
export_surface_type_legend_to_svg(svg, legend_pos);
|
||||||
|
svg.Close();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// friend to Layer
|
||||||
|
void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive::Octree* support_fill_octree, FillLightning::Generator* lightning_generator)
|
||||||
|
{
|
||||||
|
for (LayerRegion *layerm : m_regions)
|
||||||
|
layerm->fills.clear();
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||||
|
// this->export_region_fill_surfaces_to_svg_debug("10_fill-initial");
|
||||||
|
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||||
|
|
||||||
|
std::vector<SurfaceFill> surface_fills = group_fills(*this);
|
||||||
|
const Slic3r::BoundingBox bbox = this->object()->bounding_box();
|
||||||
|
const auto resolution = this->object()->print()->config().resolution.value;
|
||||||
|
|
||||||
|
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||||
|
{
|
||||||
|
static int iRun = 0;
|
||||||
|
export_group_fills_to_svg(debug_out_path("Layer-fill_surfaces-10_fill-final-%d.svg", iRun ++).c_str(), surface_fills);
|
||||||
|
}
|
||||||
|
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||||
|
|
||||||
|
for (SurfaceFill &surface_fill : surface_fills) {
|
||||||
|
// Create the filler object.
|
||||||
|
std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(surface_fill.params.pattern));
|
||||||
|
f->set_bounding_box(bbox);
|
||||||
|
f->layer_id = this->id();
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (surface_fill.params.pattern == ipConcentricInternal) {
|
||||||
|
FillConcentricInternal *fill_concentric = dynamic_cast<FillConcentricInternal *>(f.get());
|
||||||
|
assert(fill_concentric != nullptr);
|
||||||
|
fill_concentric->print_config = &this->object()->print()->config();
|
||||||
|
fill_concentric->print_object_config = &this->object()->config();
|
||||||
|
} else if (surface_fill.params.pattern == ipConcentric) {
|
||||||
|
FillConcentric *fill_concentric = dynamic_cast<FillConcentric *>(f.get());
|
||||||
|
assert(fill_concentric != nullptr);
|
||||||
|
fill_concentric->print_config = &this->object()->print()->config();
|
||||||
|
fill_concentric->print_object_config = &this->object()->config();
|
||||||
|
} else if (surface_fill.params.pattern == ipLightning)
|
||||||
|
dynamic_cast<FillLightning::Filler*>(f.get())->generator = lightning_generator;
|
||||||
|
|
||||||
|
// calculate flow spacing for infill pattern generation
|
||||||
|
bool using_internal_flow = ! surface_fill.surface.is_solid() && ! surface_fill.params.bridge;
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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_(surface_fill.params.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 = 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 = surface_fill.params.pattern == ipConcentric;
|
||||||
|
params.layer_height = m_regions[surface_fill.region_id]->layer()->height;
|
||||||
|
|
||||||
|
// BBS
|
||||||
|
params.flow = surface_fill.params.flow;
|
||||||
|
params.extrusion_role = surface_fill.params.extrusion_role;
|
||||||
|
params.using_internal_flow = using_internal_flow;
|
||||||
|
params.no_extrusion_overlap = surface_fill.params.overlap;
|
||||||
|
if (surface_fill.params.pattern == ipGrid)
|
||||||
|
params.can_reverse = false;
|
||||||
|
LayerRegion* layerm = this->m_regions[surface_fill.region_id];
|
||||||
|
for (ExPolygon& expoly : surface_fill.expolygons) {
|
||||||
|
f->no_overlap_expolygons = intersection_ex(surface_fill.no_overlap_expolygons, ExPolygons() = {expoly}, ApplySafetyOffset::Yes);
|
||||||
|
// 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);
|
||||||
|
// BBS: make fill
|
||||||
|
f->fill_surface_extrusion(&surface_fill.surface,
|
||||||
|
params,
|
||||||
|
m_regions[surface_fill.region_id]->fills.entities);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add thin fill regions
|
||||||
|
// Unpacks the collection, creates multiple collections per path.
|
||||||
|
// The path type could be ExtrusionPath, ExtrusionLoop or ExtrusionEntityCollection.
|
||||||
|
// Why the paths are unpacked?
|
||||||
|
for (LayerRegion *layerm : m_regions)
|
||||||
|
for (const ExtrusionEntity *thin_fill : layerm->thin_fills.entities) {
|
||||||
|
ExtrusionEntityCollection &collection = *(new ExtrusionEntityCollection());
|
||||||
|
layerm->fills.entities.push_back(&collection);
|
||||||
|
collection.entities.push_back(thin_fill->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
for (LayerRegion *layerm : m_regions)
|
||||||
|
for (size_t i = 0; i < layerm->fills.entities.size(); ++ i)
|
||||||
|
assert(dynamic_cast<ExtrusionEntityCollection*>(layerm->fills.entities[i]) != nullptr);
|
||||||
|
#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;
|
||||||
|
//case ipEnsuring: continue; break;
|
||||||
|
case ipLightning:
|
||||||
|
case ipAdaptiveCubic:
|
||||||
|
case ipSupportCubic:
|
||||||
|
case ipRectilinear:
|
||||||
|
case ipMonotonic:
|
||||||
|
case ipAlignedRectilinear:
|
||||||
|
case ipGrid:
|
||||||
|
case ipTriangles:
|
||||||
|
case ipStars:
|
||||||
|
case ipCubic:
|
||||||
|
case ipLine:
|
||||||
|
case ipConcentric:
|
||||||
|
case ipHoneycomb:
|
||||||
|
case ip3DHoneycomb:
|
||||||
|
case ipGyroid:
|
||||||
|
case ipHilbertCurve:
|
||||||
|
case ipArchimedeanChords:
|
||||||
|
case ipOctagramSpiral:
|
||||||
|
//xiamian+
|
||||||
|
case ipFiberSpiral:
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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_(surface_fill.params.flow.nozzle_diameter()) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER);
|
||||||
|
|
||||||
|
LayerRegion& layerm = *m_regions[surface_fill.region_id];
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
{
|
||||||
|
// LayerRegion::slices contains surfaces marked with SurfaceType.
|
||||||
|
// Here we want to collect top surfaces extruded with the same extruder.
|
||||||
|
// A surface will be ironed with the same extruder to not contaminate the print with another material leaking from the nozzle.
|
||||||
|
|
||||||
|
// First classify regions based on the extruder used.
|
||||||
|
struct IroningParams {
|
||||||
|
InfillPattern pattern;
|
||||||
|
int extruder = -1;
|
||||||
|
bool just_infill = false;
|
||||||
|
// Spacing of the ironing lines, also to calculate the extrusion flow from.
|
||||||
|
double line_spacing;
|
||||||
|
// Height of the extrusion, to calculate the extrusion flow from.
|
||||||
|
double height;
|
||||||
|
double speed;
|
||||||
|
double angle;
|
||||||
|
|
||||||
|
bool operator<(const IroningParams &rhs) const {
|
||||||
|
if (this->extruder < rhs.extruder)
|
||||||
|
return true;
|
||||||
|
if (this->extruder > rhs.extruder)
|
||||||
|
return false;
|
||||||
|
if (int(this->just_infill) < int(rhs.just_infill))
|
||||||
|
return true;
|
||||||
|
if (int(this->just_infill) > int(rhs.just_infill))
|
||||||
|
return false;
|
||||||
|
if (this->line_spacing < rhs.line_spacing)
|
||||||
|
return true;
|
||||||
|
if (this->line_spacing > rhs.line_spacing)
|
||||||
|
return false;
|
||||||
|
if (this->height < rhs.height)
|
||||||
|
return true;
|
||||||
|
if (this->height > rhs.height)
|
||||||
|
return false;
|
||||||
|
if (this->speed < rhs.speed)
|
||||||
|
return true;
|
||||||
|
if (this->speed > rhs.speed)
|
||||||
|
return false;
|
||||||
|
if (this->angle < rhs.angle)
|
||||||
|
return true;
|
||||||
|
if (this->angle > rhs.angle)
|
||||||
|
return false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const IroningParams &rhs) const {
|
||||||
|
return this->extruder == rhs.extruder && this->just_infill == rhs.just_infill &&
|
||||||
|
this->line_spacing == rhs.line_spacing && this->height == rhs.height && this->speed == rhs.speed && this->angle == rhs.angle && this->pattern == rhs.pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
LayerRegion *layerm = nullptr;
|
||||||
|
|
||||||
|
// IdeaMaker: ironing
|
||||||
|
// ironing flowrate (5% percent)
|
||||||
|
// ironing speed (10 mm/sec)
|
||||||
|
|
||||||
|
// Kisslicer:
|
||||||
|
// iron off, Sweep, Group
|
||||||
|
// ironing speed: 15 mm/sec
|
||||||
|
|
||||||
|
// Cura:
|
||||||
|
// Pattern (zig-zag / concentric)
|
||||||
|
// line spacing (0.1mm)
|
||||||
|
// flow: from normal layer height. 10%
|
||||||
|
// speed: 20 mm/sec
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<IroningParams> by_extruder;
|
||||||
|
double default_layer_height = this->object()->config().layer_height;
|
||||||
|
|
||||||
|
for (LayerRegion *layerm : m_regions)
|
||||||
|
if (! layerm->slices.empty()) {
|
||||||
|
IroningParams ironing_params;
|
||||||
|
const PrintRegionConfig &config = layerm->region().config();
|
||||||
|
if (config.ironing_type != IroningType::NoIroning &&
|
||||||
|
(config.ironing_type == IroningType::AllSolid ||
|
||||||
|
(config.top_shell_layers > 0 &&
|
||||||
|
(config.ironing_type == IroningType::TopSurfaces ||
|
||||||
|
(config.ironing_type == IroningType::TopmostOnly && layerm->layer()->upper_layer == nullptr))))) {
|
||||||
|
if (config.wall_filament == config.solid_infill_filament || config.wall_loops == 0) {
|
||||||
|
// Iron the whole face.
|
||||||
|
ironing_params.extruder = config.solid_infill_filament;
|
||||||
|
} else {
|
||||||
|
// Iron just the infill.
|
||||||
|
ironing_params.extruder = config.solid_infill_filament;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ironing_params.extruder != -1) {
|
||||||
|
//TODO just_infill is currently not used.
|
||||||
|
ironing_params.just_infill = false;
|
||||||
|
ironing_params.line_spacing = config.ironing_spacing;
|
||||||
|
ironing_params.height = default_layer_height * 0.01 * config.ironing_flow;
|
||||||
|
ironing_params.speed = config.ironing_speed;
|
||||||
|
ironing_params.angle = (int(config.ironing_direction.value+layerm->region().config().infill_direction.value)%180) * M_PI / 180.;
|
||||||
|
ironing_params.pattern = config.ironing_pattern;
|
||||||
|
ironing_params.layerm = layerm;
|
||||||
|
by_extruder.emplace_back(ironing_params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::sort(by_extruder.begin(), by_extruder.end());
|
||||||
|
|
||||||
|
FillParams fill_params;
|
||||||
|
fill_params.density = 1.;
|
||||||
|
fill_params.monotonic = true;
|
||||||
|
InfillPattern f_pattern = ipRectilinear;
|
||||||
|
std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(f_pattern));
|
||||||
|
f->set_bounding_box(this->object()->bounding_box());
|
||||||
|
f->layer_id = this->id();
|
||||||
|
f->z = this->print_z;
|
||||||
|
f->overlap = 0;
|
||||||
|
for (size_t i = 0; i < by_extruder.size();) {
|
||||||
|
// Find span of regions equivalent to the ironing operation.
|
||||||
|
IroningParams &ironing_params = by_extruder[i];
|
||||||
|
// Create the filler object.
|
||||||
|
if( f_pattern != ironing_params.pattern )
|
||||||
|
{
|
||||||
|
f_pattern = ironing_params.pattern;
|
||||||
|
f = std::unique_ptr<Fill>(Fill::new_from_type(f_pattern));
|
||||||
|
f->set_bounding_box(this->object()->bounding_box());
|
||||||
|
f->layer_id = this->id();
|
||||||
|
f->z = this->print_z;
|
||||||
|
f->overlap = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t j = i;
|
||||||
|
for (++ j; j < by_extruder.size() && ironing_params == by_extruder[j]; ++ j) ;
|
||||||
|
|
||||||
|
// Create the ironing extrusions for regions <i, j)
|
||||||
|
ExPolygons ironing_areas;
|
||||||
|
double nozzle_dmr = this->object()->print()->config().nozzle_diameter.get_at(ironing_params.extruder - 1);
|
||||||
|
if (ironing_params.just_infill) {
|
||||||
|
//TODO just_infill is currently not used.
|
||||||
|
// Just infill.
|
||||||
|
} else {
|
||||||
|
// Infill and perimeter.
|
||||||
|
// Merge top surfaces with the same ironing parameters.
|
||||||
|
Polygons polys;
|
||||||
|
Polygons infills;
|
||||||
|
for (size_t k = i; k < j; ++ k) {
|
||||||
|
const IroningParams &ironing_params = by_extruder[k];
|
||||||
|
const PrintRegionConfig ®ion_config = ironing_params.layerm->region().config();
|
||||||
|
bool iron_everything = region_config.ironing_type == IroningType::AllSolid;
|
||||||
|
bool iron_completely = iron_everything;
|
||||||
|
if (iron_everything) {
|
||||||
|
// Check whether there is any non-solid hole in the regions.
|
||||||
|
bool internal_infill_solid = region_config.sparse_infill_density.value > 95.;
|
||||||
|
for (const Surface &surface : ironing_params.layerm->fill_surfaces.surfaces)
|
||||||
|
if ((!internal_infill_solid && surface.surface_type == stInternal) || surface.surface_type == stInternalBridge || surface.surface_type == stInternalVoid) {
|
||||||
|
// Some fill region is not quite solid. Don't iron over the whole surface.
|
||||||
|
iron_completely = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (iron_completely) {
|
||||||
|
// Iron everything. This is likely only good for solid transparent objects.
|
||||||
|
for (const Surface &surface : ironing_params.layerm->slices.surfaces)
|
||||||
|
polygons_append(polys, surface.expolygon);
|
||||||
|
} else {
|
||||||
|
for (const Surface &surface : ironing_params.layerm->slices.surfaces)
|
||||||
|
if ((surface.surface_type == stTop && region_config.top_shell_layers > 0) || (iron_everything && surface.surface_type == stBottom && region_config.bottom_shell_layers > 0))
|
||||||
|
// stBottomBridge is not being ironed on purpose, as it would likely destroy the bridges.
|
||||||
|
polygons_append(polys, surface.expolygon);
|
||||||
|
}
|
||||||
|
if (iron_everything && ! iron_completely) {
|
||||||
|
// Add solid fill surfaces. This may not be ideal, as one will not iron perimeters touching these
|
||||||
|
// solid fill surfaces, but it is likely better than nothing.
|
||||||
|
for (const Surface &surface : ironing_params.layerm->fill_surfaces.surfaces)
|
||||||
|
if (surface.surface_type == stInternalSolid)
|
||||||
|
polygons_append(infills, surface.expolygon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! infills.empty() || j > i + 1) {
|
||||||
|
// Ironing over more than a single region or over solid internal infill.
|
||||||
|
if (! infills.empty())
|
||||||
|
// For IroningType::AllSolid only:
|
||||||
|
// Add solid infill areas for layers, that contain some non-ironable infil (sparse infill, bridge infill).
|
||||||
|
append(polys, std::move(infills));
|
||||||
|
polys = union_safety_offset(polys);
|
||||||
|
}
|
||||||
|
// Trim the top surfaces with half the nozzle diameter.
|
||||||
|
ironing_areas = intersection_ex(polys, offset(this->lslices, - float(scale_(0.5 * nozzle_dmr))));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the filler object.
|
||||||
|
f->spacing = ironing_params.line_spacing;
|
||||||
|
f->angle = float(ironing_params.angle);
|
||||||
|
f->link_max_length = (coord_t) scale_(3. * f->spacing);
|
||||||
|
double extrusion_height = ironing_params.height * f->spacing / nozzle_dmr;
|
||||||
|
float extrusion_width = Flow::rounded_rectangle_extrusion_width_from_spacing(float(nozzle_dmr), float(extrusion_height));
|
||||||
|
double flow_mm3_per_mm = nozzle_dmr * extrusion_height;
|
||||||
|
Surface surface_fill(stTop, ExPolygon());
|
||||||
|
for (ExPolygon &expoly : ironing_areas) {
|
||||||
|
surface_fill.expolygon = std::move(expoly);
|
||||||
|
Polylines polylines;
|
||||||
|
try {
|
||||||
|
polylines = f->fill_surface(&surface_fill, fill_params);
|
||||||
|
} catch (InfillFailedException &) {
|
||||||
|
}
|
||||||
|
if (! polylines.empty()) {
|
||||||
|
// Save into layer.
|
||||||
|
ExtrusionEntityCollection *eec = nullptr;
|
||||||
|
ironing_params.layerm->fills.entities.push_back(eec = new ExtrusionEntityCollection());
|
||||||
|
// Don't sort the ironing infill lines as they are monotonicly ordered.
|
||||||
|
eec->no_sort = true;
|
||||||
|
extrusion_entities_append_paths(
|
||||||
|
eec->entities, std::move(polylines),
|
||||||
|
erIroning,
|
||||||
|
flow_mm3_per_mm, extrusion_width, float(extrusion_height));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regions up to j were processed.
|
||||||
|
i = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
File diff suppressed because it is too large
Load Diff
|
@ -135,7 +135,9 @@ static t_config_enum_values s_keys_map_InfillPattern {
|
||||||
{ "octagramspiral", ipOctagramSpiral },
|
{ "octagramspiral", ipOctagramSpiral },
|
||||||
{ "supportcubic", ipSupportCubic },
|
{ "supportcubic", ipSupportCubic },
|
||||||
{ "lightning", ipLightning },
|
{ "lightning", ipLightning },
|
||||||
{ "crosshatch", ipCrossHatch}
|
{ "crosshatch", ipCrossHatch},
|
||||||
|
//xiamian+
|
||||||
|
{ "fiberspiral", ipFiberSpiral }
|
||||||
};
|
};
|
||||||
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(InfillPattern)
|
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(InfillPattern)
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,8 @@ enum InfillPattern : int {
|
||||||
ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipSupportCubic, ipSupportBase, ipConcentricInternal,
|
ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipSupportCubic, ipSupportBase, ipConcentricInternal,
|
||||||
ipLightning, ipCrossHatch,
|
ipLightning, ipCrossHatch,
|
||||||
ipCount,
|
ipCount,
|
||||||
|
//xiamian+
|
||||||
|
ipFiberSpiral
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class IroningType {
|
enum class IroningType {
|
||||||
|
|
Loading…
Reference in New Issue