OrcaSlicer/src/libslic3r/Clipper2Utils.cpp
Rodrigo Faselli 506fde8f86
Some checks failed
Build all / Build Linux (push) Waiting to run
Build all / Build Non-Linux (push) Waiting to run
Build all / Unit Tests (push) Blocked by required conditions
Build all / Flatpak (push) Waiting to run
Shellcheck / Shellcheck (push) Has been cancelled
Clipper 2 multiline Infill (#11435)
* Grid non-crossing for multiline

cleaning

Replaced negative offset logic with surface contraction to reduce overlap with perimeters.

center the infill

filltriangles

update triangles

preallocate memory

Update FillRectilinear.cpp

Update FillRectilinear.cpp

overlapp adjustment

Fix Crash

Update FillRectilinear.cpp

density tunning

density tunning

fine tunning

reserve polilines

Grid non-crossing for multiline

Co-Authored-By: Ian Bassi <12130714+ianalexis@users.noreply.github.com>
Co-Authored-By: discip <53649486+discip@users.noreply.github.com>

* Improve multiline fill offset and polyline closure

Changed offset type from jtRound to jtMiter in multiline_fill for better geometry. Updated polyline conversion to require at least 3 points and ensured polylines are closed if not already. Updated FillGyroid, FillTpmsD, and FillTpmsFK to pass the 'close' argument to multiline_fill.

cleaning

FillAdaptive Noncross

Only use clipper if worth it

safeguard

fix overlap

Update FillRectilinear.cpp

FilllRectilineal multiline clipper

Update FillRectilinear.cpp

FilllRectilineal multiline clipper

Update FillRectilinear.cpp

Update FillRectilinear.cpp

fix 3d honeycomb

Simplify polylines

Update FillBase.cpp

Update FillBase.cpp

cleaning

Improved Multiline Function

This ensures `multiline_fill()` will correctly generate multiline infill with
closed loop polylines if the input infill line is a closedloop polyline. This
ensures that the multiline infill doesn't have little gaps or overlaps at the
"closed point" of the original infill line.

This changes how the tangent is calculated for the first and last points in a
polyline if the first and last points are the same, making it a closed loop.
Instead of just using the first or last line segment, it uses the line segment
between the points before the last point and after the first point, the same
way that all the other poly-line mid points are handled.

It also uses eigen vector operations to calculate the points instead of
explicitly calculating the x and y values. This is probably faster, and if not
then it is at least more concise.

Hibrid Multiline Function

Update FillRectilinear.cpp

Update FillRectilinear.cpp

Update FillRectilinear.cpp

Update FillRectilinear.cpp

clipperutils multiline hibrido

Update FillBase.cpp

Update FillBase.cpp

Update FillBase.cpp

multiline hibrido

arc tolerance

multiline con union

Update FillBase.cpp

Update FillBase.cpp

Update FillBase.cpp

Co-Authored-By: Ian Bassi <12130714+ianalexis@users.noreply.github.com>
Co-Authored-By: Donovan Baarda <dbaarda@gmail.com>

* Switch multiline offset logic to Clipper2

Replaces Clipper-based multiline offset logic in FillBase.cpp with Clipper2, using InflatePaths and Union for offsetting and merging. Adds new conversion utilities in Clipper2Utils for handling Paths64 to Polygons/Polylines and updates headers accordingly.

* Refactor multiline_fill to always use Clipper2 logic

Removed the 'use_clipper' parameter from multiline_fill and updated all callers to use the new signature. The function now consistently applies Clipper2-based offset logic for multiline infill, simplifying the code and ensuring uniform behavior across fill patterns.

* Change offset join type to Round in multiline_fill

Replaces the Miter join type with Round in the InflatePaths call within multiline_fill. For smotther print travels.

* Increase max infill multiline to 10

Raised the maximum allowed value for the 'Fill Multiline' infill parameter from 5 to 10 to support more lines in infill patterns.

* Refactor multiline_fill to optimize offset logic

Replaces manual conversion of polylines to Clipper2 paths with Slic3rPolylines_to_Paths64 and filters short paths using std::remove_if. Uses ClipperOffset for path inflation and streamlines merging and conversion to polylines, improving performance and code clarity.

* half iteration because is bucle

* Funciona 1

Refactored the multiline_fill function to streamline the insertion of center lines by directly checking for odd line counts and removing redundant logic. This improves code clarity and reduces unnecessary checks.

* Refactor multiline_fill for improved offset logic

Reworked the multiline_fill function to simplify and clarify the logic for generating multiple offset lines. The new implementation computes offsets more explicitly for odd and even cases, creates a fresh ClipperOffset for each band, and improves conversion between Clipper2 paths and polylines. This enhances maintainability and correctness of the multiline fill generation.

* Quartercubic multiline

* fillplanePath

fix bounding box

Co-Authored-By: Ian Bassi <12130714+ianalexis@users.noreply.github.com>

* fillconcentric multiline

Co-Authored-By: Ian Bassi <12130714+ianalexis@users.noreply.github.com>

* Update FillBase.hpp

* cleaning

* Refactor multiline_fill to clean polylines and reuse offsetter

Invalid polylines with less than two points are now removed before processing. The ClipperOffset object is created once and reused for each offset, improving efficiency and code clarity.

trigger build

* Optimize Filltrapezoidal

Refactored the trapezoidal fill pattern generation to precompute base row templates and reuse them with vertical translation, reducing redundant computations and improving code clarity. This change enhances performance and maintainability by avoiding repeated construction of row patterns within loops.

* Replace push_back with emplace_back for Polyline points

Updated Polyline point insertion from push_back to emplace_back for efficiency and clarity. Also refactored row copying logic to avoid in-place modification, improving code readability and safety.

* Update FillRectilinear.cpp

* Reserve space for poliline points

* Union not needed

* Update FillRectilinear.cpp

* unused functions

* compactado

Update FillRectilinear.cpp

* Adjust minimum rows for better performance

* Update FillRectilinear.cpp

---------

Co-authored-by: Ian Bassi <12130714+ianalexis@users.noreply.github.com>
Co-authored-by: discip <53649486+discip@users.noreply.github.com>
Co-authored-by: Donovan Baarda <dbaarda@gmail.com>
Co-authored-by: Ian Bassi <ian.bassi@outlook.com>
2025-12-23 22:53:09 +02:00

216 lines
No EOL
7.5 KiB
C++

#include "Clipper2Utils.hpp"
#include "libslic3r.h"
#include "clipper2/clipper.h"
namespace Slic3r {
//BBS: FIXME
Slic3r::Polylines Paths64_to_polylines(const Clipper2Lib::Paths64& in)
{
Slic3r::Polylines out;
out.reserve(in.size());
for (const Clipper2Lib::Path64& path64 : in) {
Slic3r::Points points;
points.reserve(path64.size());
for (const Clipper2Lib::Point64& point64 : path64)
points.emplace_back(std::move(Slic3r::Point(point64.x, point64.y)));
out.emplace_back(std::move(Slic3r::Polyline(points)));
}
return out;
}
//BBS: FIXME
template <typename Container>
Clipper2Lib::Paths64 Slic3rPoints_to_Paths64(const Container& in)
{
Clipper2Lib::Paths64 out;
out.reserve(in.size());
for (const auto& item : in) {
Clipper2Lib::Path64 path;
path.reserve(item.size());
for (const Slic3r::Point& point : item.points)
path.emplace_back(std::move(Clipper2Lib::Point64(point.x(), point.y())));
out.emplace_back(std::move(path));
}
return out;
}
Clipper2Lib::Paths64 Slic3rPolylines_to_Paths64(const Polylines& in)
{
return Slic3rPoints_to_Paths64(in);
}
Points Path64ToPoints(const Clipper2Lib::Path64& path64)
{
Points points;
points.reserve(path64.size());
for (const Clipper2Lib::Point64 &point64 : path64) points.emplace_back(std::move(Slic3r::Point(point64.x, point64.y)));
return points;
}
static ExPolygons PolyTreeToExPolygons(Clipper2Lib::PolyTree64 &&polytree)
{
struct Inner
{
static void PolyTreeToExPolygonsRecursive(Clipper2Lib::PolyTree64 &&polynode, ExPolygons *expolygons)
{
size_t cnt = expolygons->size();
expolygons->resize(cnt + 1);
(*expolygons)[cnt].contour.points = Path64ToPoints(polynode.Polygon());
(*expolygons)[cnt].holes.resize(polynode.Count());
for (int i = 0; i < polynode.Count(); ++i) {
(*expolygons)[cnt].holes[i].points = Path64ToPoints(polynode[i]->Polygon());
// Add outer polygons contained by (nested within) holes.
for (int j = 0; j < polynode[i]->Count(); ++j) PolyTreeToExPolygonsRecursive(std::move(*polynode[i]->Child(j)), expolygons);
}
}
static size_t PolyTreeCountExPolygons(const Clipper2Lib::PolyPath64& polynode)
{
size_t cnt = 1;
for (size_t i = 0; i < polynode.Count(); ++i) {
for (size_t j = 0; j < polynode.Child(i)->Count(); ++j) cnt += PolyTreeCountExPolygons(*polynode.Child(i)->Child(j));
}
return cnt;
}
};
ExPolygons retval;
size_t cnt = 0;
for (int i = 0; i < polytree.Count(); ++i) cnt += Inner::PolyTreeCountExPolygons(*polytree[i]);
retval.reserve(cnt);
for (int i = 0; i < polytree.Count(); ++i) Inner::PolyTreeToExPolygonsRecursive(std::move(*polytree[i]), &retval);
return retval;
}
void SimplifyPolyTree(const Clipper2Lib::PolyPath64 &polytree, double epsilon, Clipper2Lib::PolyPath64 &result)
{
for (const auto &child : polytree) {
Clipper2Lib::PolyPath64 *newchild = result.AddChild(Clipper2Lib::SimplifyPath(child->Polygon(), epsilon));
SimplifyPolyTree(*child, epsilon, *newchild);
}
}
Clipper2Lib::Paths64 Slic3rPolygons_to_Paths64(const Polygons &in)
{
Clipper2Lib::Paths64 out;
out.reserve(in.size());
for (const Polygon &poly : in) {
Clipper2Lib::Path64 path;
path.reserve(poly.points.size());
for (const Slic3r::Point &point : poly.points) path.emplace_back(std::move(Clipper2Lib::Point64(point.x(), point.y())));
out.emplace_back(std::move(path));
}
return out;
}
Clipper2Lib::Paths64 Slic3rExPolygons_to_Paths64(const ExPolygons& in)
{
Clipper2Lib::Paths64 out;
out.reserve(in.size());
for (const ExPolygon& expolygon : in) {
for (size_t i = 0; i < expolygon.num_contours(); i++) {
const auto &poly = expolygon.contour_or_hole(i);
Clipper2Lib::Path64 path;
path.reserve(poly.points.size());
for (const Slic3r::Point &point : poly.points) path.emplace_back(std::move(Clipper2Lib::Point64(point.x(), point.y())));
out.emplace_back(std::move(path));
}
}
return out;
}
Polylines _clipper2_pl_open(Clipper2Lib::ClipType clipType, const Slic3r::Polylines& subject, const Slic3r::Polygons& clip)
{
Clipper2Lib::Clipper64 c;
c.AddOpenSubject(Slic3rPoints_to_Paths64(subject));
c.AddClip(Slic3rPoints_to_Paths64(clip));
Clipper2Lib::ClipType ct = clipType;
Clipper2Lib::FillRule fr = Clipper2Lib::FillRule::NonZero;
Clipper2Lib::Paths64 solution, solution_open;
c.Execute(ct, fr, solution, solution_open);
Slic3r::Polylines out;
out.reserve(solution.size() + solution_open.size());
polylines_append(out, std::move(Paths64_to_polylines(solution)));
polylines_append(out, std::move(Paths64_to_polylines(solution_open)));
return out;
}
Slic3r::Polylines intersection_pl_2(const Slic3r::Polylines& subject, const Slic3r::Polygons& clip)
{ return _clipper2_pl_open(Clipper2Lib::ClipType::Intersection, subject, clip); }
Slic3r::Polylines diff_pl_2(const Slic3r::Polylines& subject, const Slic3r::Polygons& clip)
{ return _clipper2_pl_open(Clipper2Lib::ClipType::Difference, subject, clip); }
ExPolygons union_ex_2(const Polygons& polygons)
{
Clipper2Lib::Clipper64 c;
c.AddSubject(Slic3rPolygons_to_Paths64(polygons));
Clipper2Lib::ClipType ct = Clipper2Lib::ClipType::Union;
Clipper2Lib::FillRule fr = Clipper2Lib::FillRule::NonZero;
Clipper2Lib::PolyTree64 solution;
c.Execute(ct, fr, solution);
ExPolygons results = PolyTreeToExPolygons(std::move(solution));
return results;
}
ExPolygons union_ex_2(const ExPolygons &expolygons)
{
Clipper2Lib::Clipper64 c;
c.AddSubject(Slic3rExPolygons_to_Paths64(expolygons));
Clipper2Lib::ClipType ct = Clipper2Lib::ClipType::Union;
Clipper2Lib::FillRule fr = Clipper2Lib::FillRule::NonZero;
Clipper2Lib::PolyTree64 solution;
c.Execute(ct, fr, solution);
ExPolygons results = PolyTreeToExPolygons(std::move(solution));
return results;
}
// 对 ExPolygons 进行偏移
ExPolygons offset_ex_2(const ExPolygons &expolygons, double delta)
{
Clipper2Lib::Paths64 subject = Slic3rExPolygons_to_Paths64(expolygons);
Clipper2Lib::ClipperOffset offsetter;
offsetter.AddPaths(subject, Clipper2Lib::JoinType::Round, Clipper2Lib::EndType::Polygon);
Clipper2Lib::PolyPath64 polytree;
offsetter.Execute(delta, polytree);
ExPolygons results = PolyTreeToExPolygons(std::move(polytree));
return results;
}
ExPolygons offset2_ex_2(const ExPolygons& expolygons, double delta1, double delta2)
{
// 1st offset
Clipper2Lib::Paths64 subject = Slic3rExPolygons_to_Paths64(expolygons);
Clipper2Lib::ClipperOffset offsetter;
offsetter.AddPaths(subject, Clipper2Lib::JoinType::Round, Clipper2Lib::EndType::Polygon);
Clipper2Lib::PolyPath64 polytree;
offsetter.Execute(delta1, polytree);
// simplify the result
Clipper2Lib::PolyPath64 polytree2;
SimplifyPolyTree(polytree, SCALED_EPSILON, polytree2);
// 2nd offset
offsetter.Clear();
offsetter.AddPaths(Clipper2Lib::PolyTreeToPaths64(polytree2), Clipper2Lib::JoinType::Round, Clipper2Lib::EndType::Polygon);
polytree.Clear();
offsetter.Execute(delta2, polytree);
// convert back to expolygons
ExPolygons results = PolyTreeToExPolygons(std::move(polytree));
return results;
}
}