Skip to content

Commit

Permalink
single wall top Arachne
Browse files Browse the repository at this point in the history
  • Loading branch information
vovodroid committed Dec 26, 2023
1 parent 6b69be6 commit 82e5dd0
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 2 deletions.
12 changes: 12 additions & 0 deletions src/libslic3r/ClipperUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,18 @@ namespace ClipperUtils {
out.end());
return out;
}
[[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygons &src, const BoundingBox &bbox)
{
Polygons out;
out.reserve(number_polygons(src));
for (const ExPolygon &p : src) {
Polygons temp = clip_clipper_polygons_with_subject_bbox(p, bbox);
out.insert(out.end(), temp.begin(), temp.end());
}

out.erase(std::remove_if(out.begin(), out.end(), [](const Polygon &polygon) {return polygon.empty(); }), out.end());
return out;
}
}

static ExPolygons PolyTreeToExPolygons(ClipperLib::PolyTree &&polytree)
Expand Down
1 change: 1 addition & 0 deletions src/libslic3r/ClipperUtils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ namespace ClipperUtils {
[[nodiscard]] Polygon clip_clipper_polygon_with_subject_bbox(const Polygon &src, const BoundingBox &bbox);
[[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const Polygons &src, const BoundingBox &bbox);
[[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygon &src, const BoundingBox &bbox);
[[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygons &src, const BoundingBox &bbox);
}

// offset Polygons
Expand Down
133 changes: 133 additions & 0 deletions src/libslic3r/PerimeterGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1123,6 +1123,39 @@ void PerimeterGenerator::process_arachne(
ExPolygons last = offset_ex(surface.expolygon.simplify_p(params.scaled_resolution), - float(ext_perimeter_width / 2. - ext_perimeter_spacing / 2.));
Polygons last_p = to_polygons(last);

std::vector<Arachne::VariableWidthLines> out_shell;

//Orca
ExPolygons top_fills;
if (loop_number > 0 && params.config.only_one_perimeter_top && !surface.is_bridge() && upper_slices != nullptr) {
// Check if current layer has surfaces that are not covered by upper layer (i.e., top surfaces)
ExPolygons non_top_polygons;
ExPolygons fill_clip;

split_top_surfaces(params, lower_slices, upper_slices, last, top_fills, non_top_polygons, fill_clip);

if (top_fills.empty()) {
// No top surfaces, no special handling needed
} else {
// First we slice the outer shell
Polygons last_p = to_polygons(last);
Arachne::WallToolPaths wallToolPaths(last_p, ext_perimeter_spacing, perimeter_spacing, coord_t(1),
0, params.layer_height, params.object_config, params.print_config);
out_shell = wallToolPaths.getToolPaths();
// Make sure infill not overlap with wall
top_fills = intersection_ex(top_fills, wallToolPaths.getInnerContour());

if (!top_fills.empty()) {
// Then get the inner part that needs more walls
last = intersection_ex(non_top_polygons, wallToolPaths.getInnerContour());
loop_number = 0;
} else {
// Give up the outer shell because we don't have any meaningful top surface
out_shell.clear();
}
}
}

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);
std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths();
loop_number = int(perimeters.size()) - 1;
Expand Down Expand Up @@ -1307,6 +1340,11 @@ void PerimeterGenerator::process_arachne(
float(- min_perimeter_infill_spacing / 2.),
float(inset + min_perimeter_infill_spacing / 2.));

// append infill areas to fill_surfaces
if (!top_fills.empty()) {
infill_areas = union_ex(infill_areas, offset_ex(top_fills, double(inset)));
}

if (lower_slices != nullptr && params.config.overhangs && params.config.extra_perimeters_on_overhangs &&
params.config.perimeters > 0 && params.layer_id > params.object_config.raft_layers) {
// Generate extra perimeters on overhang areas, and cut them to these parts only, to save print time and material
Expand Down Expand Up @@ -1685,4 +1723,99 @@ void PerimeterGenerator::process_classic(
append(out_fill_expolygons, std::move(infill_areas));
}

void PerimeterGenerator::split_top_surfaces(const Parameters &params,const ExPolygons *lower_slices,const ExPolygons *upper_slices,const ExPolygons &orig_polygons, ExPolygons &top_fills,
ExPolygons &non_top_polygons, ExPolygons &fill_clip) {
// other perimeters
coord_t perimeter_width = params.perimeter_flow.scaled_width();
coord_t perimeter_spacing = params.perimeter_flow.scaled_spacing();

// external perimeters
coord_t ext_perimeter_width = params.ext_perimeter_flow.scaled_width();
coord_t ext_perimeter_spacing = params.ext_perimeter_flow.scaled_spacing();

bool has_gap_fill = false;//this->config->gap_infill_speed.value > 0;

// split the polygons with top/not_top
// get the offset from solid surface anchor
coord_t offset_top_surface =
scale_(1.5 * (params.config.perimeters == 0
? 0.
: unscaled(double(ext_perimeter_width +
perimeter_spacing * int(int(params.config.perimeters) - int(1))))));
// if possible, try to not push the extra perimeters inside the sparse infill
if (offset_top_surface >
0.9 * (params.config.perimeters <= 1 ? 0. : (perimeter_spacing * (params.config.perimeters - 1))))
offset_top_surface -=
coord_t(0.9 * (params.config.perimeters <= 1 ? 0. : (perimeter_spacing * (params.config.perimeters - 1))));
else
offset_top_surface = 0;
// don't takes into account too thin areas
// skip if the exposed area is smaller than "min_width_top_surface"
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))));

Polygons grown_upper_slices = offset(*upper_slices, min_width_top_surface);

// get boungding box of last
BoundingBox last_box = get_extents(orig_polygons);
last_box.offset(SCALED_EPSILON);

// get the Polygons upper the polygon this layer
Polygons upper_polygons_series_clipped =
ClipperUtils::clip_clipper_polygons_with_subject_bbox(grown_upper_slices, last_box);

// set the clip to a virtual "second perimeter"
fill_clip = offset_ex(orig_polygons, -double(ext_perimeter_spacing));
// get the real top surface
ExPolygons grown_lower_slices;
ExPolygons bridge_checker;
auto nozzle_diameter = 0.4;//this->print_config->nozzle_diameter.get_at(this->config->wall_filament - 1);
// Check whether surface be bridge or not
if (lower_slices != NULL) {
// BBS: get the Polygons below the polygon this layer
Polygons lower_polygons_series_clipped =
ClipperUtils::clip_clipper_polygons_with_subject_bbox(*lower_slices, last_box);
double bridge_offset = std::max(double(ext_perimeter_spacing), (double(perimeter_width)));
// SoftFever: improve bridging
const float bridge_margin =
std::min(float(scale_(BRIDGE_INFILL_MARGIN)), float(scale_(nozzle_diameter * BRIDGE_INFILL_MARGIN / 0.4)));
bridge_checker = offset_ex(diff_ex(orig_polygons, lower_polygons_series_clipped, ApplySafetyOffset::Yes),
1.5 * bridge_offset + bridge_margin + perimeter_spacing / 2);
}
ExPolygons delete_bridge = diff_ex(orig_polygons, bridge_checker, ApplySafetyOffset::Yes);

ExPolygons top_polygons = diff_ex(delete_bridge, upper_polygons_series_clipped, ApplySafetyOffset::Yes);
// get the not-top surface, from the "real top" but enlarged by external_infill_margin (and the
// min_width_top_surface we removed a bit before)
ExPolygons temp_gap = diff_ex(top_polygons, fill_clip);
ExPolygons inner_polygons =
diff_ex(orig_polygons,
offset_ex(top_polygons, offset_top_surface + min_width_top_surface - double(ext_perimeter_spacing / 2)),
ApplySafetyOffset::Yes);
// get the enlarged top surface, by using inner_polygons instead of upper_slices, and clip it for it to be exactly
// the polygons to fill.
top_polygons = diff_ex(fill_clip, inner_polygons, ApplySafetyOffset::Yes);
// increase by half peri the inner space to fill the frontier between last and stored.
top_fills = union_ex(top_fills, top_polygons);
//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.
double infill_spacing_unscaled = params.config.infill_extrusion_width.get_abs_value(nozzle_diameter);
if (infill_spacing_unscaled == 0) infill_spacing_unscaled = Flow::auto_extrusion_width(frInfill, nozzle_diameter);
fill_clip = offset_ex(orig_polygons, double(ext_perimeter_spacing / 2) - scale_(infill_spacing_unscaled / 2));
// ExPolygons oldLast = last;

non_top_polygons = intersection_ex(inner_polygons, orig_polygons);
if (has_gap_fill)
non_top_polygons = union_ex(non_top_polygons, temp_gap);
//{
// std::stringstream stri;
// stri << this->layer_id << "_1_"<< i <<"_only_one_peri"<< ".svg";
// SVG svg(stri.str());
// svg.draw(to_polylines(top_fills), "green");
// svg.draw(to_polylines(inner_polygons), "yellow");
// svg.draw(to_polylines(top_polygons), "cyan");
// svg.draw(to_polylines(oldLast), "orange");
// svg.draw(to_polylines(last), "red");
// svg.Close();
//}
}

}
3 changes: 3 additions & 0 deletions src/libslic3r/PerimeterGenerator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ void process_arachne(

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

void split_top_surfaces(const Parameters &params, const ExPolygons *lower_slices,const ExPolygons *upper_slices, const ExPolygons &orig_polygons, ExPolygons &top_fills,
ExPolygons &non_top_polygons, ExPolygons &fill_clip);

} // namespace PerimeterGenerator
} // namespace Slic3r

Expand Down
2 changes: 2 additions & 0 deletions src/libslic3r/libslic3r.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,11 @@ static constexpr double INSET_OVERLAP_TOLERANCE = 0.4;
// 3mm ring around the top / bottom / bridging areas.
//FIXME This is quite a lot.
static constexpr double EXTERNAL_INFILL_MARGIN = 3.;
static constexpr double BRIDGE_INFILL_MARGIN = 1.;
//FIXME Better to use an inline function with an explicit return type.
//inline coord_t scale_(coordf_t v) { return coord_t(floor(v / SCALING_FACTOR + 0.5f)); }
#define scale_(val) ((val) / SCALING_FACTOR)
#define unscale_(val) ((val) * SCALING_FACTOR)

#define SCALED_EPSILON scale_(EPSILON)

Expand Down
3 changes: 1 addition & 2 deletions src/slic3r/GUI/ConfigManipulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,8 +346,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
toggle_field("min_bead_width", have_arachne);
toggle_field("thin_walls", !have_arachne);

toggle_field("only_one_perimeter_top", !have_arachne);
toggle_field("min_width_top_surface", have_perimeters && config->opt_bool("only_one_perimeter_top") && !have_arachne);
toggle_field("min_width_top_surface", have_perimeters && config->opt_bool("only_one_perimeter_top"));

bool has_arc_fitting = config->opt_enum<ArcFittingType>("arc_fitting") != ArcFittingType::Disabled;
toggle_field("arc_fitting_tolerance", has_arc_fitting);
Expand Down

0 comments on commit 82e5dd0

Please sign in to comment.