mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-29 22:41:59 +08:00
Fixes of recent RegionExpansion implementation.
Enabled thick internal bridges even if external thick bridges are disabled. Fixed compilation of conditionally compiled debugging code.
This commit is contained in:
parent
479a39ce0e
commit
1a91d85e7e
@ -76,12 +76,11 @@ RegionExpansionParameters RegionExpansionParameters::build(
|
||||
// similar to expolygons_to_zpaths(), but each contour is expanded before converted to zpath.
|
||||
// The expanded contours are then opened (the first point is repeated at the end).
|
||||
static ClipperLib_Z::Paths expolygons_to_zpaths_expanded_opened(
|
||||
const ExPolygons &src, const float expansion, coord_t base_idx)
|
||||
const ExPolygons &src, const float expansion, coord_t &base_idx)
|
||||
{
|
||||
ClipperLib_Z::Paths out;
|
||||
out.reserve(2 * std::accumulate(src.begin(), src.end(), size_t(0),
|
||||
[](const size_t acc, const ExPolygon &expoly) { return acc + expoly.num_contours(); }));
|
||||
coord_t z = base_idx;
|
||||
ClipperLib::ClipperOffset offsetter;
|
||||
offsetter.ShortestEdgeLength = expansion * ClipperOffsetShortestEdgeFactor;
|
||||
ClipperLib::Paths expansion_cache;
|
||||
@ -94,9 +93,9 @@ static ClipperLib_Z::Paths expolygons_to_zpaths_expanded_opened(
|
||||
offsetter.AddPath(expoly.contour_or_hole(icontour).points, ClipperLib::jtSquare, ClipperLib::etClosedPolygon);
|
||||
expansion_cache.clear();
|
||||
offsetter.Execute(expansion_cache, icontour == 0 ? expansion : -expansion);
|
||||
append(out, ClipperZUtils::to_zpaths<true>(expansion_cache, z));
|
||||
append(out, ClipperZUtils::to_zpaths<true>(expansion_cache, base_idx));
|
||||
}
|
||||
++ z;
|
||||
++ base_idx;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@ -217,7 +216,7 @@ std::vector<WaveSeed> wave_seeds(
|
||||
Intersections intersections;
|
||||
|
||||
coord_t idx_boundary_begin = 1;
|
||||
coord_t idx_boundary_end;
|
||||
coord_t idx_boundary_end = idx_boundary_begin;
|
||||
coord_t idx_src_end;
|
||||
|
||||
{
|
||||
@ -225,17 +224,13 @@ std::vector<WaveSeed> wave_seeds(
|
||||
ClipperZUtils::ClipperZIntersectionVisitor visitor(intersections);
|
||||
zclipper.ZFillFunction(visitor.clipper_callback());
|
||||
// as closed contours
|
||||
{
|
||||
ClipperLib_Z::Paths zboundary = ClipperZUtils::expolygons_to_zpaths(boundary, idx_boundary_begin);
|
||||
idx_boundary_end = idx_boundary_begin + coord_t(zboundary.size());
|
||||
zclipper.AddPaths(zboundary, ClipperLib_Z::ptClip, true);
|
||||
}
|
||||
zclipper.AddPaths(ClipperZUtils::expolygons_to_zpaths(boundary, idx_boundary_end), ClipperLib_Z::ptClip, true);
|
||||
// as open contours
|
||||
std::vector<std::pair<ClipperLib_Z::IntPoint, int>> zsrc_splits;
|
||||
{
|
||||
ClipperLib_Z::Paths zsrc = expolygons_to_zpaths_expanded_opened(src, tiny_expansion, idx_boundary_end);
|
||||
idx_src_end = idx_boundary_end;
|
||||
ClipperLib_Z::Paths zsrc = expolygons_to_zpaths_expanded_opened(src, tiny_expansion, idx_src_end);
|
||||
zclipper.AddPaths(zsrc, ClipperLib_Z::ptSubject, false);
|
||||
idx_src_end = idx_boundary_end + coord_t(zsrc.size());
|
||||
zsrc_splits.reserve(zsrc.size());
|
||||
for (const ClipperLib_Z::Path &path : zsrc) {
|
||||
assert(path.size() >= 2);
|
||||
@ -267,7 +262,10 @@ std::vector<WaveSeed> wave_seeds(
|
||||
const ClipperLib_Z::IntPoint &back = path.back();
|
||||
// Both ends of a seed segment are supposed to be inside a single boundary expolygon.
|
||||
// Thus as long as the seed contour is not closed, it should be open at a boundary point.
|
||||
assert((front == back && front.z() >= idx_boundary_end && front.z() < idx_src_end) || (front.z() < 0 && back.z() < 0));
|
||||
assert((front == back && front.z() >= idx_boundary_end && front.z() < idx_src_end) ||
|
||||
//(front.z() < 0 && back.z() < 0));
|
||||
// Hope that at least one end of an open polyline is clipped by the boundary, thus an intersection point is created.
|
||||
(front.z() < 0 || back.z() < 0));
|
||||
const Intersection *intersection = nullptr;
|
||||
auto intersection_point_valid = [idx_boundary_end, idx_src_end](const Intersection &is) {
|
||||
return is.first >= 1 && is.first < idx_boundary_end &&
|
||||
|
@ -53,17 +53,16 @@ inline ZPaths to_zpaths(const std::vector<Points> &paths, coord_t z)
|
||||
// offsetted by base_index.
|
||||
// If Open, then duplicate the first point of each path at its end.
|
||||
template<bool Open = false>
|
||||
inline ZPaths expolygons_to_zpaths(const ExPolygons &src, coord_t base_idx)
|
||||
inline ZPaths expolygons_to_zpaths(const ExPolygons &src, coord_t &base_idx)
|
||||
{
|
||||
ZPaths out;
|
||||
out.reserve(std::accumulate(src.begin(), src.end(), size_t(0),
|
||||
[](const size_t acc, const ExPolygon &expoly) { return acc + expoly.num_contours(); }));
|
||||
coord_t z = base_idx;
|
||||
for (const ExPolygon &expoly : src) {
|
||||
out.emplace_back(to_zpath<Open>(expoly.contour.points, z));
|
||||
out.emplace_back(to_zpath<Open>(expoly.contour.points, base_idx));
|
||||
for (const Polygon &hole : expoly.holes)
|
||||
out.emplace_back(to_zpath<Open>(hole.points, z));
|
||||
++ z;
|
||||
out.emplace_back(to_zpath<Open>(hole.points, base_idx));
|
||||
++ base_idx;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
@ -215,19 +215,19 @@ Surfaces expand_bridges_detect_orientations(
|
||||
// bridge_expansions are sorted by boundary id and source id.
|
||||
for (auto it = bridge_expansions.begin(); it != bridge_expansions.end();) {
|
||||
// For each boundary region:
|
||||
auto it2 = it;
|
||||
for (++ it2; it2 != bridge_expansions.end() && it2->boundary_id == it->boundary_id; ++ it2);
|
||||
auto it_begin = it;
|
||||
auto it_end = std::next(it_begin);
|
||||
for (; it_end != bridge_expansions.end() && it_end->boundary_id == it_begin->boundary_id; ++ it_end) ;
|
||||
bboxes.clear();
|
||||
bboxes.reserve(it2 - it);
|
||||
for (it2 = it; it2 != bridge_expansions.end() && it2->boundary_id == it->boundary_id; ++ it2)
|
||||
bboxes.reserve(it_end - it_begin);
|
||||
for (auto it2 = it_begin; it2 != it_end; ++ it2)
|
||||
bboxes.emplace_back(get_extents(it2->expolygon.contour));
|
||||
auto it_end = it2;
|
||||
// For each bridge anchor of the current source:
|
||||
for (; it != it_end; ++ it) {
|
||||
// A grup id for this bridge.
|
||||
for (it2 = std::next(it); it2 != it_end; ++ it2)
|
||||
for (auto it2 = std::next(it); it2 != it_end; ++ it2)
|
||||
if (it->src_id != it2->src_id &&
|
||||
bboxes[it - bridge_expansions.begin()].overlap(bboxes[it2 - bridge_expansions.begin()]) &&
|
||||
bboxes[it - it_begin].overlap(bboxes[it2 - it_begin]) &&
|
||||
// One may ignore holes, they are irrelevant for intersection test.
|
||||
! intersection(it->expolygon.contour, it2->expolygon.contour).empty()) {
|
||||
// The two bridge regions intersect. Give them the same group id.
|
||||
|
@ -964,9 +964,9 @@ void PrintObject::detect_surfaces_type()
|
||||
{
|
||||
static int iRun = 0;
|
||||
std::vector<std::pair<Slic3r::ExPolygons, SVG::ExPolygonAttributes>> expolygons_with_attributes;
|
||||
expolygons_with_attributes.emplace_back(std::make_pair(union_ex(top), SVG::ExPolygonAttributes("green")));
|
||||
expolygons_with_attributes.emplace_back(std::make_pair(union_ex(bottom), SVG::ExPolygonAttributes("brown")));
|
||||
expolygons_with_attributes.emplace_back(std::make_pair(to_expolygons(layerm->slices.surfaces), SVG::ExPolygonAttributes("black")));
|
||||
expolygons_with_attributes.emplace_back(std::make_pair(union_ex(top), SVG::ExPolygonAttributes("green")));
|
||||
expolygons_with_attributes.emplace_back(std::make_pair(union_ex(bottom), SVG::ExPolygonAttributes("brown")));
|
||||
expolygons_with_attributes.emplace_back(std::make_pair(to_expolygons(layerm->slices().surfaces), SVG::ExPolygonAttributes("black")));
|
||||
SVG::export_expolygons(debug_out_path("1_detect_surfaces_type_%d_region%d-layer_%f.svg", iRun ++, region_id, layer->print_z).c_str(), expolygons_with_attributes);
|
||||
}
|
||||
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||
@ -1399,26 +1399,26 @@ void PrintObject::discover_vertical_shells()
|
||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||
{
|
||||
Slic3r::SVG svg(debug_out_path("discover_vertical_shells-internal-wshell-%d.svg", debug_idx), get_extents(shell));
|
||||
svg.draw(layerm->fill_surfaces.filter_by_type(stInternal), "yellow", 0.5);
|
||||
svg.draw_outline(layerm->fill_surfaces.filter_by_type(stInternal), "black", "blue", scale_(0.05));
|
||||
svg.draw(layerm->fill_surfaces().filter_by_type(stInternal), "yellow", 0.5);
|
||||
svg.draw_outline(layerm->fill_surfaces().filter_by_type(stInternal), "black", "blue", scale_(0.05));
|
||||
svg.draw(shell_ex, "blue", 0.5);
|
||||
svg.draw_outline(shell_ex, "black", "blue", scale_(0.05));
|
||||
svg.Close();
|
||||
}
|
||||
{
|
||||
Slic3r::SVG svg(debug_out_path("discover_vertical_shells-internalvoid-wshell-%d.svg", debug_idx), get_extents(shell));
|
||||
svg.draw(layerm->fill_surfaces.filter_by_type(stInternalVoid), "yellow", 0.5);
|
||||
svg.draw_outline(layerm->fill_surfaces.filter_by_type(stInternalVoid), "black", "blue", scale_(0.05));
|
||||
svg.draw(layerm->fill_surfaces().filter_by_type(stInternalVoid), "yellow", 0.5);
|
||||
svg.draw_outline(layerm->fill_surfaces().filter_by_type(stInternalVoid), "black", "blue", scale_(0.05));
|
||||
svg.draw(shell_ex, "blue", 0.5);
|
||||
svg.draw_outline(shell_ex, "black", "blue", scale_(0.05));
|
||||
svg.Close();
|
||||
}
|
||||
{
|
||||
Slic3r::SVG svg(debug_out_path("discover_vertical_shells-internalvoid-wshell-%d.svg", debug_idx), get_extents(shell));
|
||||
svg.draw(layerm->fill_surfaces.filter_by_type(stInternalVoid), "yellow", 0.5);
|
||||
svg.draw_outline(layerm->fill_surfaces.filter_by_type(stInternalVoid), "black", "blue", scale_(0.05));
|
||||
Slic3r::SVG svg(debug_out_path("discover_vertical_shells-internalsolid-wshell-%d.svg", debug_idx), get_extents(shell));
|
||||
svg.draw(layerm->fill_surfaces().filter_by_type(stInternalSolid), "yellow", 0.5);
|
||||
svg.draw_outline(layerm->fill_surfaces().filter_by_type(stInternalSolid), "black", "blue", scale_(0.05));
|
||||
svg.draw(shell_ex, "blue", 0.5);
|
||||
svg.draw_outline(shell_ex, "black", "blue", scale_(0.05));
|
||||
svg.draw_outline(shell_ex, "black", "blue", scale_(0.05));
|
||||
svg.Close();
|
||||
}
|
||||
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||
@ -1544,7 +1544,7 @@ void PrintObject::bridge_over_infill()
|
||||
internals.reserve(this->layer_count());
|
||||
for (Layer *layer : m_layers) {
|
||||
Polygons sum;
|
||||
for (const LayerRegion *layerm : layer->m_regions)
|
||||
for (const LayerRegion *layerm : layer->regions())
|
||||
layerm->fill_surfaces().filter_by_type(stInternal, &sum);
|
||||
internals.emplace_back(std::move(sum));
|
||||
}
|
||||
@ -1558,7 +1558,7 @@ void PrintObject::bridge_over_infill()
|
||||
const size_t region_id = sparse_infill_regions[task_id % sparse_infill_regions.size()];
|
||||
Layer *layer = this->get_layer(layer_id);
|
||||
LayerRegion *layerm = layer->m_regions[region_id];
|
||||
Flow bridge_flow = layerm->bridging_flow(frSolidInfill);
|
||||
Flow bridge_flow = layerm->bridging_flow(frSolidInfill, true /* Internal bridges are always thick. */);
|
||||
|
||||
// Extract the stInternalSolid surfaces that might be transformed into bridges.
|
||||
ExPolygons internal_solid;
|
||||
@ -1567,32 +1567,27 @@ void PrintObject::bridge_over_infill()
|
||||
// No internal solid -> no new bridges for this layer region.
|
||||
continue;
|
||||
|
||||
// check whether the lower area is deep enough for absorbing the extra flow
|
||||
// (for obvious physical reasons but also for preventing the bridge extrudates
|
||||
// from overflowing in 3D preview)
|
||||
// Check whether the lower area is deep enough for absorbing the extra flow, also filter out
|
||||
// tiny regions from bridging.
|
||||
ExPolygons to_bridge;
|
||||
{
|
||||
Polygons to_bridge_pp = to_polygons(internal_solid);
|
||||
// Iterate through lower layers spanned by bridge_flow.
|
||||
double bottom_z = layer->print_z - bridge_flow.height() - EPSILON;
|
||||
for (auto i = int(layer_id) - 1; i >= 0; -- i) {
|
||||
// Stop iterating if layer is lower than bottom_z.
|
||||
if (m_layers[i]->print_z < bottom_z)
|
||||
break;
|
||||
for (auto i = int(layer_id) - 1; i >= 0 && m_layers[i]->print_z > bottom_z; -- i)
|
||||
// Intersect lower sparse infills with the candidate solid surfaces.
|
||||
to_bridge_pp = intersection(to_bridge_pp, internals[i]);
|
||||
}
|
||||
// there's no point in bridging too thin/short regions
|
||||
//FIXME Vojtech: The offset2 function is not a geometric offset,
|
||||
// therefore it may create 1) gaps, and 2) sharp corners, which are outside the original contour.
|
||||
// The gaps will be filled by a separate region, which makes the infill less stable and it takes longer.
|
||||
{
|
||||
float min_width = float(bridge_flow.scaled_width()) * 3.f;
|
||||
to_bridge_pp = opening(to_bridge_pp, min_width);
|
||||
to_bridge_pp = opening(to_bridge_pp, min_width); //, ClipperLib::jtSquare);
|
||||
}
|
||||
|
||||
if (to_bridge_pp.empty()) {
|
||||
// Restore internal_solid surfaces.
|
||||
// Optimization: Nothing to bridge, restore internal_solid surfaces.
|
||||
for (ExPolygon &ex : internal_solid)
|
||||
layerm->m_fill_surfaces.surfaces.push_back(Surface(stInternalSolid, std::move(ex)));
|
||||
continue;
|
||||
@ -1613,39 +1608,6 @@ void PrintObject::bridge_over_infill()
|
||||
layerm->m_fill_surfaces.surfaces.push_back(Surface(stInternalBridge, std::move(ex)));
|
||||
for (ExPolygon &ex : not_to_bridge)
|
||||
layerm->m_fill_surfaces.surfaces.push_back(Surface(stInternalSolid, std::move(ex)));
|
||||
/*
|
||||
# exclude infill from the layers below if needed
|
||||
# see discussion at https://github.com/alexrj/Slic3r/issues/240
|
||||
# Update: do not exclude any infill. Sparse infill is able to absorb the excess material.
|
||||
if (0) {
|
||||
my $excess = $layerm->extruders->{infill}->bridge_flow->width - $layerm->height;
|
||||
for (my $i = $layer_id-1; $excess >= $self->get_layer($i)->height; $i--) {
|
||||
Slic3r::debugf " skipping infill below those areas at layer %d\n", $i;
|
||||
foreach my $lower_layerm (@{$self->get_layer($i)->regions}) {
|
||||
my @new_surfaces = ();
|
||||
# subtract the area from all types of surfaces
|
||||
foreach my $group (@{$lower_layerm->fill_surfaces->group}) {
|
||||
push @new_surfaces, map $group->[0]->clone(expolygon => $_),
|
||||
@{diff_ex(
|
||||
[ map $_->p, @$group ],
|
||||
[ map @$_, @$to_bridge ],
|
||||
)};
|
||||
push @new_surfaces, map Slic3r::Surface->new(
|
||||
expolygon => $_,
|
||||
surface_type => stInternalVoid,
|
||||
), @{intersection_ex(
|
||||
[ map $_->p, @$group ],
|
||||
[ map @$_, @$to_bridge ],
|
||||
)};
|
||||
}
|
||||
$lower_layerm->fill_surfaces->clear;
|
||||
$lower_layerm->fill_surfaces->append($_) for @new_surfaces;
|
||||
}
|
||||
|
||||
$excess -= $self->get_layer($i)->height;
|
||||
}
|
||||
}
|
||||
*/
|
||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||
layerm->export_region_slices_to_svg_debug("7_bridge_over_infill");
|
||||
layerm->export_region_fill_surfaces_to_svg_debug("7_bridge_over_infill");
|
||||
|
@ -1320,7 +1320,7 @@ namespace SupportMaterialInternal {
|
||||
bridges = union_(bridges);
|
||||
}
|
||||
// remove the entire bridges and only support the unsupported edges
|
||||
//FIXME the brided regions are already collected as layerm.bridged. Use it?
|
||||
//FIXME the bridged regions are already collected as layerm.bridged. Use it?
|
||||
for (const Surface &surface : layerm.fill_surfaces())
|
||||
if (surface.surface_type == stBottomBridge && surface.bridge_angle < 0.0)
|
||||
polygons_append(bridges, surface.expolygon);
|
||||
|
@ -62,6 +62,8 @@ public:
|
||||
// Inherits coord_t x, y
|
||||
};
|
||||
|
||||
#define DEBUG_INTERSECTIONLINE (! defined(NDEBUG) || defined(SLIC3R_DEBUG_SLICE_PROCESSING))
|
||||
|
||||
class IntersectionLine : public Line
|
||||
{
|
||||
public:
|
||||
@ -119,14 +121,14 @@ public:
|
||||
};
|
||||
uint32_t flags { 0 };
|
||||
|
||||
#ifndef NDEBUG
|
||||
#if DEBUG_INTERSECTIONLINE
|
||||
enum class Source {
|
||||
BottomPlane,
|
||||
TopPlane,
|
||||
Slab,
|
||||
};
|
||||
Source source { Source::BottomPlane };
|
||||
#endif // NDEBUG
|
||||
#endif
|
||||
};
|
||||
|
||||
using IntersectionLines = std::vector<IntersectionLine>;
|
||||
@ -1440,24 +1442,24 @@ static std::vector<Polygons> make_slab_loops(
|
||||
for (const IntersectionLine &l : lines.at_slice[slice_below])
|
||||
if (l.edge_type != IntersectionLine::FacetEdgeType::Top) {
|
||||
in.emplace_back(l);
|
||||
#ifndef NDEBUG
|
||||
#if DEBUG_INTERSECTIONLINE
|
||||
in.back().source = IntersectionLine::Source::BottomPlane;
|
||||
#endif // NDEBUG
|
||||
#endif // DEBUG_INTERSECTIONLINE
|
||||
}
|
||||
}
|
||||
{
|
||||
// Edges in between slice_below and slice_above.
|
||||
#ifndef NDEBUG
|
||||
#if DEBUG_INTERSECTIONLINE
|
||||
size_t old_size = in.size();
|
||||
#endif // NDEBUG
|
||||
#endif // DEBUG_INTERSECTIONLINE
|
||||
// Edge IDs of end points on in-between lines that touch the layer above are already increased with num_edges.
|
||||
append(in, lines.between_slices[line_idx]);
|
||||
#ifndef NDEBUG
|
||||
#if DEBUG_INTERSECTIONLINE
|
||||
for (auto it = in.begin() + old_size; it != in.end(); ++ it) {
|
||||
assert(it->edge_type == IntersectionLine::FacetEdgeType::Slab);
|
||||
it->source = IntersectionLine::Source::Slab;
|
||||
}
|
||||
#endif // NDEBUG
|
||||
#endif // DEBUG_INTERSECTIONLINE
|
||||
}
|
||||
if (has_slice_above) {
|
||||
for (const IntersectionLine &lsrc : lines.at_slice[slice_above])
|
||||
@ -1470,9 +1472,9 @@ static std::vector<Polygons> make_slab_loops(
|
||||
l.edge_a_id += num_edges;
|
||||
if (l.edge_b_id >= 0)
|
||||
l.edge_b_id += num_edges;
|
||||
#ifndef NDEBUG
|
||||
#if DEBUG_INTERSECTIONLINE
|
||||
l.source = IntersectionLine::Source::TopPlane;
|
||||
#endif // NDEBUG
|
||||
#endif // DEBUG_INTERSECTIONLINE
|
||||
}
|
||||
}
|
||||
if (! in.empty()) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user