Added computation of bridging perimeters for Arachne.
This commit is contained in:
parent
f460c53d86
commit
dc2789a0e8
@ -5,6 +5,7 @@
|
||||
|
||||
#include "ExtrusionLine.hpp"
|
||||
#include "linearAlg2D.hpp"
|
||||
#include "../../PerimeterGenerator.hpp"
|
||||
|
||||
namespace Slic3r::Arachne
|
||||
{
|
||||
@ -231,4 +232,20 @@ int64_t ExtrusionLine::calculateExtrusionAreaDeviationError(ExtrusionJunction A,
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Slic3r::Arachne
|
||||
|
||||
namespace Slic3r {
|
||||
void extrusion_paths_append(ExtrusionPaths &dst, const ClipperLib_Z::Paths &extrusion_paths, const ExtrusionRole role, const Flow &flow)
|
||||
{
|
||||
for (const ClipperLib_Z::Path &extrusion_path : extrusion_paths) {
|
||||
ThickPolyline thick_polyline = Arachne::to_thick_polyline(extrusion_path);
|
||||
Slic3r::append(dst, thick_polyline_to_extrusion_paths(thick_polyline, role, flow, scaled<float>(0.05), 0));
|
||||
}
|
||||
}
|
||||
|
||||
void extrusion_paths_append(ExtrusionPaths &dst, const Arachne::ExtrusionLine &extrusion, const ExtrusionRole role, const Flow &flow)
|
||||
{
|
||||
ThickPolyline thick_polyline = Arachne::to_thick_polyline(extrusion);
|
||||
Slic3r::append(dst, thick_polyline_to_extrusion_paths(thick_polyline, role, flow, scaled<float>(0.05), 0));
|
||||
}
|
||||
} // namespace Slic3r
|
@ -9,6 +9,9 @@
|
||||
#include "../../Polyline.hpp"
|
||||
#include "../../Polygon.hpp"
|
||||
#include "../../BoundingBox.hpp"
|
||||
#include "../../ExtrusionEntity.hpp"
|
||||
#include "../../Flow.hpp"
|
||||
#include "../../../clipper/clipper_z.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
class ThickPolyline;
|
||||
@ -208,6 +211,26 @@ static inline Slic3r::ThickPolyline to_thick_polyline(const Arachne::ExtrusionLi
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline Slic3r::ThickPolyline to_thick_polyline(const ClipperLib_Z::Path &path)
|
||||
{
|
||||
assert(path.size() >= 2);
|
||||
Slic3r::ThickPolyline out;
|
||||
out.points.emplace_back(path.front().x(), path.front().y());
|
||||
out.width.emplace_back(path.front().z());
|
||||
out.points.emplace_back(path[1].x(), path[1].y());
|
||||
out.width.emplace_back(path[1].z());
|
||||
|
||||
auto it_prev = path.begin() + 1;
|
||||
for (auto it = path.begin() + 2; it != path.end(); ++it) {
|
||||
out.points.emplace_back(it->x(), it->y());
|
||||
out.width.emplace_back(it_prev->z());
|
||||
out.width.emplace_back(it->z());
|
||||
it_prev = it;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline Polygon to_polygon(const ExtrusionLine &line)
|
||||
{
|
||||
Polygon out;
|
||||
@ -269,4 +292,12 @@ static std::vector<Points> to_points(const std::vector<const ExtrusionLine *> &e
|
||||
using VariableWidthLines = std::vector<ExtrusionLine>; //<! The ExtrusionLines generated by libArachne
|
||||
|
||||
} // namespace Slic3r::Arachne
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
void extrusion_paths_append(ExtrusionPaths &dst, const ClipperLib_Z::Paths &extrusion_paths, const ExtrusionRole role, const Flow &flow);
|
||||
void extrusion_paths_append(ExtrusionPaths &dst, const Arachne::ExtrusionLine &extrusion, const ExtrusionRole role, const Flow &flow);
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // UTILS_EXTRUSION_LINE_H
|
||||
|
@ -2,7 +2,10 @@
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "ExtrusionEntityCollection.hpp"
|
||||
#include "ShortestPath.hpp"
|
||||
#include "clipper/clipper_z.hpp"
|
||||
|
||||
#include "Arachne/WallToolPaths.hpp"
|
||||
#include "Arachne/utils/ExtrusionLine.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
@ -277,6 +280,101 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
|
||||
return out;
|
||||
}
|
||||
|
||||
static ClipperLib_Z::Paths clip_extrusion(const ClipperLib_Z::Path &subject, const ClipperLib_Z::Paths &clip, ClipperLib_Z::ClipType clipType)
|
||||
{
|
||||
ClipperLib_Z::Clipper clipper;
|
||||
clipper.ZFillFunction([](const ClipperLib_Z::IntPoint &e1bot, const ClipperLib_Z::IntPoint &e1top, const ClipperLib_Z::IntPoint &e2bot,
|
||||
const ClipperLib_Z::IntPoint &e2top, ClipperLib_Z::IntPoint &pt) {
|
||||
ClipperLib_Z::IntPoint start = e1bot;
|
||||
ClipperLib_Z::IntPoint end = e1top;
|
||||
|
||||
if (start.z() <= 0 && end.z() <= 0) {
|
||||
start = e2bot;
|
||||
end = e2top;
|
||||
}
|
||||
|
||||
assert(start.z() > 0 && end.z() > 0);
|
||||
|
||||
// Interpolate extrusion line width.
|
||||
double length_sqr = (end - start).cast<double>().squaredNorm();
|
||||
double dist_sqr = (pt - start).cast<double>().squaredNorm();
|
||||
double t = std::sqrt(dist_sqr / length_sqr);
|
||||
|
||||
pt.z() = start.z() + coord_t((end.z() - start.z()) * t);
|
||||
});
|
||||
|
||||
clipper.AddPath(subject, ClipperLib_Z::ptSubject, false);
|
||||
clipper.AddPaths(clip, ClipperLib_Z::ptClip, true);
|
||||
|
||||
ClipperLib_Z::PolyTree clipped_polytree;
|
||||
ClipperLib_Z::Paths clipped_paths;
|
||||
clipper.Execute(clipType, clipped_polytree, ClipperLib_Z::pftNonZero, ClipperLib_Z::pftNonZero);
|
||||
ClipperLib_Z::PolyTreeToPaths(clipped_polytree, clipped_paths);
|
||||
|
||||
return clipped_paths;
|
||||
}
|
||||
|
||||
static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator &perimeter_generator, const std::vector<const Arachne::ExtrusionLine *> &extrusions)
|
||||
{
|
||||
ExtrusionEntityCollection extrusion_coll;
|
||||
for (const Arachne::ExtrusionLine *extrusion : extrusions) {
|
||||
if (extrusion->empty())
|
||||
continue;
|
||||
|
||||
const bool is_external = extrusion->inset_idx == 0;
|
||||
ExtrusionRole role = is_external ? erExternalPerimeter : erPerimeter;
|
||||
|
||||
ExtrusionPaths paths;
|
||||
// detect overhanging/bridging perimeters
|
||||
if (perimeter_generator.config->overhangs && perimeter_generator.layer_id > perimeter_generator.object_config->raft_layers
|
||||
&& ! ((perimeter_generator.object_config->support_material || perimeter_generator.object_config->support_material_enforce_layers > 0) &&
|
||||
perimeter_generator.object_config->support_material_contact_distance.value == 0)) {
|
||||
|
||||
ClipperLib_Z::Path extrusion_path;
|
||||
extrusion_path.reserve(extrusion->size());
|
||||
for (const Arachne::ExtrusionJunction &ej : extrusion->junctions)
|
||||
extrusion_path.emplace_back(ej.p.x(), ej.p.y(), ej.w);
|
||||
|
||||
ClipperLib_Z::Paths lower_slices_paths;
|
||||
lower_slices_paths.reserve(perimeter_generator.lower_slices_polygons().size());
|
||||
for (const Polygon &poly : perimeter_generator.lower_slices_polygons()) {
|
||||
lower_slices_paths.emplace_back();
|
||||
ClipperLib_Z::Path &out = lower_slices_paths.back();
|
||||
out.reserve(poly.points.size());
|
||||
for (const Point &pt : poly.points)
|
||||
out.emplace_back(pt.x(), pt.y(), 0);
|
||||
}
|
||||
|
||||
// get non-overhang paths by intersecting this loop with the grown lower slices
|
||||
extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ClipperLib_Z::ctIntersection), role,
|
||||
is_external ? perimeter_generator.ext_perimeter_flow : perimeter_generator.perimeter_flow);
|
||||
|
||||
// get overhang paths by checking what parts of this loop fall
|
||||
// outside the grown lower slices (thus where the distance between
|
||||
// the loop centerline and original lower slices is >= half nozzle diameter
|
||||
extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ClipperLib_Z::ctDifference), erOverhangPerimeter,
|
||||
perimeter_generator.overhang_flow);
|
||||
|
||||
// Reapply the nearest point search for starting point.
|
||||
// We allow polyline reversal because Clipper may have randomly reversed polylines during clipping.
|
||||
chain_and_reorder_extrusion_paths(paths, &paths.front().first_point());
|
||||
} else {
|
||||
extrusion_paths_append(paths, *extrusion, role, is_external ? perimeter_generator.ext_perimeter_flow : perimeter_generator.perimeter_flow);
|
||||
}
|
||||
|
||||
// Append paths to collection.
|
||||
if (!paths.empty()) {
|
||||
if (extrusion->is_closed)
|
||||
extrusion_coll.entities.emplace_back(new ExtrusionLoop(std::move(paths)));
|
||||
else
|
||||
for (ExtrusionPath &path : paths)
|
||||
extrusion_coll.entities.emplace_back(new ExtrusionPath(std::move(path)));
|
||||
}
|
||||
}
|
||||
|
||||
return extrusion_coll;
|
||||
}
|
||||
|
||||
// Thanks, Cura developers, for implementing an algorithm for generating perimeters with variable width (Arachne) that is based on the paper
|
||||
// "A framework for adaptive width control of dense contour-parallel toolpaths in fused deposition modeling"
|
||||
void PerimeterGenerator::process_arachne()
|
||||
@ -406,27 +504,8 @@ void PerimeterGenerator::process_arachne()
|
||||
}
|
||||
}
|
||||
|
||||
for (const Arachne::ExtrusionLine *extrusion : ordered_extrusions) {
|
||||
if (extrusion->empty())
|
||||
continue;
|
||||
|
||||
ExtrusionEntityCollection entities_coll;
|
||||
|
||||
ThickPolyline thick_polyline = Arachne::to_thick_polyline(*extrusion);
|
||||
bool ext_perimeter = extrusion->inset_idx == 0;
|
||||
ExtrusionPaths paths = thick_polyline_to_extrusion_paths(thick_polyline, ext_perimeter ? erExternalPerimeter : erPerimeter,
|
||||
ext_perimeter ? this->ext_perimeter_flow : this->perimeter_flow, scaled<float>(0.05), 0);
|
||||
// Append paths to collection.
|
||||
if (!paths.empty()) {
|
||||
if (paths.front().first_point() == paths.back().last_point())
|
||||
entities_coll.entities.emplace_back(new ExtrusionLoop(std::move(paths)));
|
||||
else
|
||||
for (ExtrusionPath &path : paths)
|
||||
entities_coll.entities.emplace_back(new ExtrusionPath(std::move(path)));
|
||||
}
|
||||
|
||||
this->loops->append(entities_coll);
|
||||
}
|
||||
if (ExtrusionEntityCollection extrusion_coll = traverse_extrusions(*this, ordered_extrusions); !extrusion_coll.empty())
|
||||
this->loops->append(extrusion_coll);
|
||||
|
||||
ExPolygons infill_contour = union_ex(wallToolPaths.getInnerContour());
|
||||
// create one more offset to be used as boundary for fill
|
||||
|
Loading…
Reference in New Issue
Block a user