Skip to content

Commit 9cd62eb

Browse files
vovodroidmjonuschat
authored andcommitted
[FEATURE] Only one top perimeter for Arachne
1 parent 7e16be3 commit 9cd62eb

File tree

6 files changed

+163
-3
lines changed

6 files changed

+163
-3
lines changed

src/libslic3r/ClipperUtils.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,18 @@ namespace ClipperUtils {
183183
out.end());
184184
return out;
185185
}
186+
[[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygons &src, const BoundingBox &bbox)
187+
{
188+
Polygons out;
189+
out.reserve(number_polygons(src));
190+
for (const ExPolygon &p : src) {
191+
Polygons temp = clip_clipper_polygons_with_subject_bbox(p, bbox);
192+
out.insert(out.end(), temp.begin(), temp.end());
193+
}
194+
195+
out.erase(std::remove_if(out.begin(), out.end(), [](const Polygon &polygon) {return polygon.empty(); }), out.end());
196+
return out;
197+
}
186198
}
187199

188200
static ExPolygons PolyTreeToExPolygons(ClipperLib::PolyTree &&polytree)

src/libslic3r/ClipperUtils.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ namespace ClipperUtils {
335335
[[nodiscard]] Polygon clip_clipper_polygon_with_subject_bbox(const Polygon &src, const BoundingBox &bbox);
336336
[[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const Polygons &src, const BoundingBox &bbox);
337337
[[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygon &src, const BoundingBox &bbox);
338+
[[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygons &src, const BoundingBox &bbox);
338339
}
339340

340341
// offset Polygons

src/libslic3r/PerimeterGenerator.cpp

Lines changed: 144 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1121,10 +1121,62 @@ void PerimeterGenerator::process_arachne(
11211121
loop_number = 0;
11221122

11231123
ExPolygons last = offset_ex(surface.expolygon.simplify_p(params.scaled_resolution), - float(ext_perimeter_width / 2. - ext_perimeter_spacing / 2.));
1124-
Polygons last_p = to_polygons(last);
11251124

1125+
//Orca
1126+
std::vector<Arachne::VariableWidthLines> out_shell;
1127+
ExPolygons top_fills;
1128+
if (loop_number > 0 && params.config.only_one_perimeter_top && !surface.is_bridge() && upper_slices != nullptr) {
1129+
// Check if current layer has surfaces that are not covered by upper layer (i.e., top surfaces)
1130+
ExPolygons non_top_polygons;
1131+
ExPolygons fill_clip;
1132+
1133+
split_top_surfaces(params, lower_slices, upper_slices, last, top_fills, non_top_polygons, fill_clip);
1134+
1135+
if (top_fills.empty()) {
1136+
// No top surfaces, no special handling needed
1137+
} else {
1138+
// First we slice the outer shell
1139+
Polygons last_p = to_polygons(last);
1140+
Arachne::WallToolPaths wallToolPaths(last_p, ext_perimeter_spacing, perimeter_spacing, coord_t(1),
1141+
0, params.layer_height, params.object_config, params.print_config);
1142+
out_shell = wallToolPaths.getToolPaths();
1143+
// Make sure infill not overlap with wall
1144+
top_fills = intersection_ex(top_fills, wallToolPaths.getInnerContour());
1145+
1146+
if (!top_fills.empty()) {
1147+
// Then get the inner part that needs more walls
1148+
last = intersection_ex(non_top_polygons, wallToolPaths.getInnerContour());
1149+
loop_number--;
1150+
} else {
1151+
// Give up the outer shell because we don't have any meaningful top surface
1152+
out_shell.clear();
1153+
}
1154+
}
1155+
}
1156+
1157+
Polygons last_p = to_polygons(last);
11261158
Arachne::WallToolPaths wallToolPaths(last_p, ext_perimeter_spacing, perimeter_spacing, coord_t(loop_number + 1), 0, params.layer_height, params.object_config, params.print_config);
11271159
std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths();
1160+
1161+
//Orca
1162+
if (!out_shell.empty()) {
1163+
// Combine outer shells
1164+
size_t inset_offset = 0;
1165+
for (auto &p : out_shell) {
1166+
for (auto &l : p) {
1167+
if (l.inset_idx + 1 > inset_offset) {
1168+
inset_offset = l.inset_idx + 1;
1169+
}
1170+
}
1171+
}
1172+
for (auto &p : perimeters) {
1173+
for (auto &l : p) {
1174+
l.inset_idx += inset_offset;
1175+
}
1176+
}
1177+
perimeters.insert(perimeters.begin(), out_shell.begin(), out_shell.end());
1178+
}
1179+
11281180
loop_number = int(perimeters.size()) - 1;
11291181

11301182
#ifdef ARACHNE_DEBUG
@@ -1307,6 +1359,11 @@ void PerimeterGenerator::process_arachne(
13071359
float(- min_perimeter_infill_spacing / 2.),
13081360
float(inset + min_perimeter_infill_spacing / 2.));
13091361

1362+
// append infill areas to fill_surfaces
1363+
if (!top_fills.empty()) {
1364+
infill_areas = union_ex(infill_areas, offset_ex(top_fills, double(inset)));
1365+
}
1366+
13101367
if (lower_slices != nullptr && params.config.overhangs && params.config.extra_perimeters_on_overhangs &&
13111368
params.config.perimeters > 0 && params.layer_id > params.object_config.raft_layers) {
13121369
// Generate extra perimeters on overhang areas, and cut them to these parts only, to save print time and material
@@ -1685,4 +1742,90 @@ void PerimeterGenerator::process_classic(
16851742
append(out_fill_expolygons, std::move(infill_areas));
16861743
}
16871744

1745+
//Orca
1746+
void PerimeterGenerator::split_top_surfaces(const Parameters &params,const ExPolygons *lower_slices,const ExPolygons *upper_slices,const ExPolygons &orig_polygons, ExPolygons &top_fills,
1747+
ExPolygons &non_top_polygons, ExPolygons &fill_clip) {
1748+
// other perimeters
1749+
coord_t perimeter_width = params.perimeter_flow.scaled_width();
1750+
coord_t perimeter_spacing = params.perimeter_flow.scaled_spacing();
1751+
1752+
// external perimeters
1753+
coord_t ext_perimeter_width = params.ext_perimeter_flow.scaled_width();
1754+
coord_t ext_perimeter_spacing = params.ext_perimeter_flow.scaled_spacing();
1755+
1756+
bool has_gap_fill = params.config.gap_fill_enabled;
1757+
1758+
// split the polygons with top/not_top
1759+
// get the offset from solid surface anchor
1760+
coord_t offset_top_surface = ext_perimeter_width;
1761+
1762+
// don't takes into account too thin areas
1763+
// skip if the exposed area is smaller than "min_width_top_surface"
1764+
double min_width_top_surface = std::max(double(ext_perimeter_spacing / 2 + 10), scale_(params.config.min_width_top_surface.get_abs_value(unscale_(perimeter_width))));
1765+
1766+
Polygons grown_upper_slices = offset(*upper_slices, min_width_top_surface);
1767+
1768+
// get boungding box of last
1769+
BoundingBox last_box = get_extents(orig_polygons);
1770+
last_box.offset(SCALED_EPSILON);
1771+
1772+
// get the Polygons upper the polygon this layer
1773+
Polygons upper_polygons_series_clipped =
1774+
ClipperUtils::clip_clipper_polygons_with_subject_bbox(grown_upper_slices, last_box);
1775+
1776+
// set the clip to a virtual "second perimeter"
1777+
fill_clip = offset_ex(orig_polygons, -double(ext_perimeter_spacing));
1778+
// get the real top surface
1779+
ExPolygons grown_lower_slices;
1780+
ExPolygons bridge_checker;
1781+
auto nozzle_diameter = params.print_config.nozzle_diameter.get_at(params.config.perimeter_extruder);
1782+
// Check whether surface be bridge or not
1783+
if (lower_slices != NULL) {
1784+
// BBS: get the Polygons below the polygon this layer
1785+
Polygons lower_polygons_series_clipped =
1786+
ClipperUtils::clip_clipper_polygons_with_subject_bbox(*lower_slices, last_box);
1787+
double bridge_offset = std::max(double(ext_perimeter_spacing), (double(perimeter_width)));
1788+
// SoftFever: improve bridging
1789+
const float bridge_margin =
1790+
std::min(float(scale_(BRIDGE_INFILL_MARGIN)), float(scale_(nozzle_diameter * BRIDGE_INFILL_MARGIN / 0.4)));
1791+
bridge_checker = offset_ex(diff_ex(orig_polygons, lower_polygons_series_clipped, ApplySafetyOffset::Yes),
1792+
1.5 * bridge_offset + bridge_margin + perimeter_spacing / 2);
1793+
}
1794+
ExPolygons delete_bridge = diff_ex(orig_polygons, bridge_checker, ApplySafetyOffset::Yes);
1795+
1796+
ExPolygons top_polygons = diff_ex(delete_bridge, upper_polygons_series_clipped, ApplySafetyOffset::Yes);
1797+
// get the not-top surface, from the "real top" but enlarged by external_infill_margin (and the
1798+
// min_width_top_surface we removed a bit before)
1799+
ExPolygons temp_gap = diff_ex(top_polygons, fill_clip);
1800+
ExPolygons inner_polygons =
1801+
diff_ex(orig_polygons,
1802+
offset_ex(top_polygons, offset_top_surface + min_width_top_surface - double(ext_perimeter_spacing / 2)),
1803+
ApplySafetyOffset::Yes);
1804+
// get the enlarged top surface, by using inner_polygons instead of upper_slices, and clip it for it to be exactly
1805+
// the polygons to fill.
1806+
top_polygons = diff_ex(fill_clip, inner_polygons, ApplySafetyOffset::Yes);
1807+
// increase by half peri the inner space to fill the frontier between last and stored.
1808+
top_fills = union_ex(top_fills, top_polygons);
1809+
//set the clip to the external wall but go back inside by infill_extrusion_width/2 to be sure the extrusion won't go outside even with a 100% overlap.
1810+
double infill_spacing_unscaled = params.config.infill_extrusion_width.get_abs_value(nozzle_diameter);
1811+
if (infill_spacing_unscaled == 0) infill_spacing_unscaled = Flow::auto_extrusion_width(frInfill, nozzle_diameter);
1812+
fill_clip = offset_ex(orig_polygons, double(ext_perimeter_spacing / 2) - scale_(infill_spacing_unscaled / 2));
1813+
// ExPolygons oldLast = last;
1814+
1815+
non_top_polygons = intersection_ex(inner_polygons, orig_polygons);
1816+
if (has_gap_fill)
1817+
non_top_polygons = union_ex(non_top_polygons, temp_gap);
1818+
//{
1819+
// std::stringstream stri;
1820+
// stri << this->layer_id << "_1_"<< i <<"_only_one_peri"<< ".svg";
1821+
// SVG svg(stri.str());
1822+
// svg.draw(to_polylines(top_fills), "green");
1823+
// svg.draw(to_polylines(inner_polygons), "yellow");
1824+
// svg.draw(to_polylines(top_polygons), "cyan");
1825+
// svg.draw(to_polylines(oldLast), "orange");
1826+
// svg.draw(to_polylines(last), "red");
1827+
// svg.Close();
1828+
//}
1829+
}
1830+
16881831
}

src/libslic3r/PerimeterGenerator.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ void process_arachne(
105105

106106
ExtrusionMultiPath thick_polyline_to_multi_path(const ThickPolyline &thick_polyline, ExtrusionRole role, const Flow &flow, float tolerance, float merge_tolerance);
107107

108+
void split_top_surfaces(const Parameters &params, const ExPolygons *lower_slices,const ExPolygons *upper_slices, const ExPolygons &orig_polygons, ExPolygons &top_fills,
109+
ExPolygons &non_top_polygons, ExPolygons &fill_clip);
110+
108111
} // namespace PerimeterGenerator
109112
} // namespace Slic3r
110113

src/libslic3r/libslic3r.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,11 @@ static constexpr double INSET_OVERLAP_TOLERANCE = 0.4;
7878
// 3mm ring around the top / bottom / bridging areas.
7979
//FIXME This is quite a lot.
8080
static constexpr double EXTERNAL_INFILL_MARGIN = 3.;
81+
static constexpr double BRIDGE_INFILL_MARGIN = 1.;
8182
//FIXME Better to use an inline function with an explicit return type.
8283
//inline coord_t scale_(coordf_t v) { return coord_t(floor(v / SCALING_FACTOR + 0.5f)); }
8384
#define scale_(val) ((val) / SCALING_FACTOR)
85+
#define unscale_(val) ((val) * SCALING_FACTOR)
8486

8587
#define SCALED_EPSILON scale_(EPSILON)
8688

src/slic3r/GUI/ConfigManipulation.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,8 +353,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
353353
toggle_field("thin_walls", !have_arachne);
354354

355355
toggle_field("only_one_perimeter_first_layer", !have_arachne);
356-
toggle_field("only_one_perimeter_top", !have_arachne);
357-
toggle_field("min_width_top_surface", have_perimeters && config->opt_bool("only_one_perimeter_top") && !have_arachne);
356+
toggle_field("min_width_top_surface", have_perimeters && config->opt_bool("only_one_perimeter_top"));
358357

359358
bool have_small_area_infill_flow_compensation = config->opt_bool("small_area_infill_flow_compensation");
360359
toggle_field("small_area_infill_flow_compensation_extrusion_length_0", have_small_area_infill_flow_compensation);

0 commit comments

Comments
 (0)