mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-12 01:07:57 -06:00
Introduction of ClipperLib_Z: The Clipper library compiled with support
of the Z coordinate, compiled in the ClipperLib_Z namespace. Update of Lukas's new brim clipping: All the brim contours are now clipped by the ClipperLib_Z library in one shot.
This commit is contained in:
parent
bb896b4c13
commit
ea8b6262cf
7 changed files with 148 additions and 46 deletions
|
@ -4,4 +4,6 @@ cmake_minimum_required(VERSION 2.6)
|
||||||
add_library(clipper STATIC
|
add_library(clipper STATIC
|
||||||
clipper.cpp
|
clipper.cpp
|
||||||
clipper.hpp
|
clipper.hpp
|
||||||
|
clipper_z.cpp
|
||||||
|
clipper_z.hpp
|
||||||
)
|
)
|
||||||
|
|
|
@ -51,7 +51,11 @@
|
||||||
#include <Shiny/Shiny.h>
|
#include <Shiny/Shiny.h>
|
||||||
#include <libslic3r/Int128.hpp>
|
#include <libslic3r/Int128.hpp>
|
||||||
|
|
||||||
|
#ifdef use_xyz
|
||||||
|
namespace ClipperLib_Z {
|
||||||
|
#else /* use_xyz */
|
||||||
namespace ClipperLib {
|
namespace ClipperLib {
|
||||||
|
#endif /* use_xyz */
|
||||||
|
|
||||||
static double const pi = 3.141592653589793238;
|
static double const pi = 3.141592653589793238;
|
||||||
static double const two_pi = pi *2;
|
static double const two_pi = pi *2;
|
||||||
|
@ -1616,7 +1620,7 @@ void Clipper::SetZ(IntPoint& pt, TEdge& e1, TEdge& e2)
|
||||||
else if (pt == e1.Top) pt.Z = e1.Top.Z;
|
else if (pt == e1.Top) pt.Z = e1.Top.Z;
|
||||||
else if (pt == e2.Bot) pt.Z = e2.Bot.Z;
|
else if (pt == e2.Bot) pt.Z = e2.Bot.Z;
|
||||||
else if (pt == e2.Top) pt.Z = e2.Top.Z;
|
else if (pt == e2.Top) pt.Z = e2.Top.Z;
|
||||||
else (*m_ZFill)(e1.Bot, e1.Top, e2.Bot, e2.Top, pt);
|
else m_ZFill(e1.Bot, e1.Top, e2.Bot, e2.Top, pt);
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#define clipper_hpp
|
#define clipper_hpp
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#define CLIPPER_VERSION "6.2.6"
|
#define CLIPPER_VERSION "6.2.6"
|
||||||
|
|
||||||
|
@ -56,7 +57,11 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
|
#ifdef use_xyz
|
||||||
|
namespace ClipperLib_Z {
|
||||||
|
#else /* use_xyz */
|
||||||
namespace ClipperLib {
|
namespace ClipperLib {
|
||||||
|
#endif /* use_xyz */
|
||||||
|
|
||||||
enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor };
|
enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor };
|
||||||
enum PolyType { ptSubject, ptClip };
|
enum PolyType { ptSubject, ptClip };
|
||||||
|
@ -114,7 +119,7 @@ struct DoublePoint
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
#ifdef use_xyz
|
#ifdef use_xyz
|
||||||
typedef void (*ZFillCallback)(IntPoint& e1bot, IntPoint& e1top, IntPoint& e2bot, IntPoint& e2top, IntPoint& pt);
|
typedef std::function<void(const IntPoint& e1bot, const IntPoint& e1top, const IntPoint& e2bot, const IntPoint& e2top, IntPoint& pt)> ZFillCallback;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4};
|
enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4};
|
||||||
|
|
7
src/clipper/clipper_z.cpp
Normal file
7
src/clipper/clipper_z.cpp
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// Hackish wrapper around the ClipperLib library to compile the Clipper library with the Z support.
|
||||||
|
|
||||||
|
// Enable the Z coordinate support.
|
||||||
|
#define use_xyz
|
||||||
|
|
||||||
|
// and let it compile
|
||||||
|
#include "clipper.cpp"
|
18
src/clipper/clipper_z.hpp
Normal file
18
src/clipper/clipper_z.hpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// Hackish wrapper around the ClipperLib library to compile the Clipper library with the Z support.
|
||||||
|
|
||||||
|
#ifndef clipper_z_hpp
|
||||||
|
#ifdef clipper_hpp
|
||||||
|
#error "You should include the clipper_z.hpp first"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define clipper_z_hpp
|
||||||
|
|
||||||
|
// Enable the Z coordinate support.
|
||||||
|
#define use_xyz
|
||||||
|
|
||||||
|
#include "clipper.hpp"
|
||||||
|
|
||||||
|
#undef clipper_hpp
|
||||||
|
#undef use_xyz
|
||||||
|
|
||||||
|
#endif clipper_z_hpp
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include "clipper/clipper_z.hpp"
|
||||||
|
|
||||||
#include "Print.hpp"
|
#include "Print.hpp"
|
||||||
#include "BoundingBox.hpp"
|
#include "BoundingBox.hpp"
|
||||||
#include "ClipperUtils.hpp"
|
#include "ClipperUtils.hpp"
|
||||||
|
@ -1729,53 +1731,115 @@ void Print::_make_brim()
|
||||||
ClipperLib::jtRound,
|
ClipperLib::jtRound,
|
||||||
float(scale_(0.1)));
|
float(scale_(0.1)));
|
||||||
|
|
||||||
const Polygon& skirt_inner = skirt_inners.front();
|
// First calculate the trimming region.
|
||||||
const Polygon& skirt_outer = skirt_outers.front();
|
ClipperLib_Z::Paths trimming;
|
||||||
|
{
|
||||||
for (size_t i=0; i<loops.size(); ++i) {
|
ClipperLib_Z::Paths input_subject;
|
||||||
Polylines lines;
|
ClipperLib_Z::Paths input_clip;
|
||||||
lines.push_back(Polyline());
|
for (const Polygon &poly : skirt_outers) {
|
||||||
bool del = false;
|
input_subject.emplace_back();
|
||||||
const Polygon& poly = loops[i];
|
ClipperLib_Z::Path &out = input_subject.back();
|
||||||
// Check all points of the polygon, consider the first to also be at the end so the loop is closed
|
out.reserve(poly.points.size());
|
||||||
for (int pt_idx=0; pt_idx <= (int)poly.points.size(); ++pt_idx) {
|
for (const Point &pt : poly.points)
|
||||||
const Point* pt = (pt_idx == (int)poly.points.size() ? &poly.points[0] : &poly.points[pt_idx]);
|
out.emplace_back(pt.x(), pt.y(), 0);
|
||||||
const Point* last_pt = (pt_idx == 0 ? nullptr : &poly.points[pt_idx-1]);
|
|
||||||
bool valid_point = skirt_inner.contains(*pt) || ! skirt_outer.contains(*pt);
|
|
||||||
Points intersections(2); // inner and outer intersection
|
|
||||||
|
|
||||||
if (pt_idx > 0) {
|
|
||||||
Line line(*last_pt, *pt);
|
|
||||||
bool inner = skirt_inner.first_intersection(line, &intersections[0]);
|
|
||||||
bool outer = skirt_outer.first_intersection(line, &intersections[1]);
|
|
||||||
del = del || inner || outer;
|
|
||||||
if (inner != outer) {// there is exactly one intersection
|
|
||||||
lines.back().append(inner ? intersections[0] : intersections[1]);
|
|
||||||
}
|
|
||||||
if (inner && outer) {
|
|
||||||
int nearest_idx = pt->nearest_point_index(intersections);
|
|
||||||
lines.back().append(intersections[! nearest_idx]);
|
|
||||||
lines.push_back(Polyline());
|
|
||||||
lines.back().append(intersections[nearest_idx]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (valid_point)
|
|
||||||
lines.back().append(*pt);
|
|
||||||
else {
|
|
||||||
del = true;
|
|
||||||
lines.push_back(Polyline());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If we found a single intersection, we should erase the respective ExtrusionLoop
|
|
||||||
// and append the polylines that we created.
|
|
||||||
if (del) {
|
|
||||||
loops.erase(loops.begin() + (i--));
|
|
||||||
extrusion_entities_append_paths(m_brim.entities, std::move(lines), erSkirt, float(flow.mm3_per_mm()), float(flow.width), float(this->skirt_first_layer_height()));
|
|
||||||
}
|
}
|
||||||
|
for (const Polygon &poly : skirt_inners) {
|
||||||
|
input_clip.emplace_back();
|
||||||
|
ClipperLib_Z::Path &out = input_clip.back();
|
||||||
|
out.reserve(poly.points.size());
|
||||||
|
for (const Point &pt : poly.points)
|
||||||
|
out.emplace_back(pt.x(), pt.y(), 0);
|
||||||
}
|
}
|
||||||
|
// init Clipper
|
||||||
|
ClipperLib_Z::Clipper clipper;
|
||||||
|
// add polygons
|
||||||
|
clipper.AddPaths(input_subject, ClipperLib_Z::ptSubject, true);
|
||||||
|
clipper.AddPaths(input_clip, ClipperLib_Z::ptClip, true);
|
||||||
|
// perform operation
|
||||||
|
clipper.Execute(ClipperLib_Z::ctDifference, trimming, ClipperLib_Z::pftEvenOdd, ClipperLib_Z::pftEvenOdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Second, trim the extrusion loops with the trimming regions.
|
||||||
|
ClipperLib_Z::Paths loops_trimmed;
|
||||||
|
{
|
||||||
|
// Produce a closed polyline (repeat the first point at the end).
|
||||||
|
ClipperLib_Z::Paths input_clip;
|
||||||
|
for (const Polygon &loop : loops) {
|
||||||
|
input_clip.emplace_back();
|
||||||
|
ClipperLib_Z::Path& out = input_clip.back();
|
||||||
|
out.reserve(loop.points.size());
|
||||||
|
int64_t loop_idx = &loop - &loops.front();
|
||||||
|
for (const Point& pt : loop.points)
|
||||||
|
// The Z coordinate carries index of the source loop.
|
||||||
|
out.emplace_back(pt.x(), pt.y(), loop_idx + 1);
|
||||||
|
out.emplace_back(out.front());
|
||||||
|
}
|
||||||
|
// init Clipper
|
||||||
|
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) {
|
||||||
|
// Assign a valid input loop identifier. Such an identifier is strictly positive, the next line is safe even in case one side of a segment
|
||||||
|
// hat the Z coordinate not set to the contour coordinate.
|
||||||
|
pt.Z = std::max(std::max(e1bot.Z, e1top.Z), std::max(e2bot.Z, e2top.Z));
|
||||||
|
});
|
||||||
|
// add polygons
|
||||||
|
clipper.AddPaths(input_clip, ClipperLib_Z::ptSubject, false);
|
||||||
|
clipper.AddPaths(trimming, ClipperLib_Z::ptClip, true);
|
||||||
|
// perform operation
|
||||||
|
ClipperLib_Z::PolyTree loops_trimmed_tree;
|
||||||
|
clipper.Execute(ClipperLib_Z::ctDifference, loops_trimmed_tree, ClipperLib_Z::pftEvenOdd, ClipperLib_Z::pftEvenOdd);
|
||||||
|
ClipperLib_Z::PolyTreeToPaths(loops_trimmed_tree, loops_trimmed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Third, produce the extrusions, sorted by the source loop indices.
|
||||||
|
{
|
||||||
|
std::vector<std::pair<const ClipperLib_Z::Path*, size_t>> loops_trimmed_order;
|
||||||
|
loops_trimmed_order.reserve(loops_trimmed.size());
|
||||||
|
for (const ClipperLib_Z::Path &path : loops_trimmed) {
|
||||||
|
size_t input_idx = 0;
|
||||||
|
for (const ClipperLib_Z::IntPoint &pt : path)
|
||||||
|
if (pt.Z > 0) {
|
||||||
|
input_idx = (size_t)pt.Z;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
assert(input_idx != 0);
|
||||||
|
loops_trimmed_order.emplace_back(&path, input_idx);
|
||||||
|
}
|
||||||
|
std::stable_sort(loops_trimmed_order.begin(), loops_trimmed_order.end(),
|
||||||
|
[](const std::pair<const ClipperLib_Z::Path*, size_t> &l, const std::pair<const ClipperLib_Z::Path*, size_t> &r) {
|
||||||
|
return l.second < r.second;
|
||||||
|
});
|
||||||
|
Vec3f last_pt(0.f, 0.f, 0.f);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < loops_trimmed_order.size();) {
|
||||||
|
// Find all pieces that the initial loop was split into.
|
||||||
|
size_t j = i + 1;
|
||||||
|
for (; j < loops_trimmed_order.size() && loops_trimmed_order[i].first == loops_trimmed_order[j].first; ++ j) ;
|
||||||
|
const ClipperLib_Z::Path &first_path = *loops_trimmed_order[i].first;
|
||||||
|
if (i + 1 == j && first_path.size() > 3 && first_path.front().X == first_path.back().X && first_path.front().Y == first_path.back().Y) {
|
||||||
|
auto *loop = new ExtrusionLoop();
|
||||||
|
m_brim.entities.emplace_back(loop);
|
||||||
|
loop->paths.emplace_back(erSkirt, float(flow.mm3_per_mm()), float(flow.width), float(this->skirt_first_layer_height()));
|
||||||
|
Points &points = loop->paths.front().polyline.points;
|
||||||
|
points.reserve(first_path.size());
|
||||||
|
for (const ClipperLib_Z::IntPoint &pt : first_path)
|
||||||
|
points.emplace_back(coord_t(pt.X), coord_t(pt.Y));
|
||||||
|
i = j;
|
||||||
|
} else {
|
||||||
|
//FIXME this is not optimal as the G-code generator will follow the sequence of paths verbatim without respect to minimum travel distance.
|
||||||
|
for (; i < j; ++ i) {
|
||||||
|
m_brim.entities.emplace_back(new ExtrusionPath(erSkirt, float(flow.mm3_per_mm()), float(flow.width), float(this->skirt_first_layer_height())));
|
||||||
|
const ClipperLib_Z::Path &path = *loops_trimmed_order[i].first;
|
||||||
|
Points &points = static_cast<ExtrusionPath*>(m_brim.entities.back())->polyline.points;
|
||||||
|
points.reserve(path.size());
|
||||||
|
for (const ClipperLib_Z::IntPoint &pt : path)
|
||||||
|
points.emplace_back(coord_t(pt.X), coord_t(pt.Y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
extrusion_entities_append_loops(m_brim.entities, std::move(loops), erSkirt, float(flow.mm3_per_mm()), float(flow.width), float(this->skirt_first_layer_height()));
|
extrusion_entities_append_loops(m_brim.entities, std::move(loops), erSkirt, float(flow.mm3_per_mm()), float(flow.width), float(this->skirt_first_layer_height()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wipe tower support.
|
// Wipe tower support.
|
||||||
|
|
|
@ -105,6 +105,8 @@
|
||||||
#include <cereal/access.hpp>
|
#include <cereal/access.hpp>
|
||||||
#include <cereal/types/base_class.hpp>
|
#include <cereal/types/base_class.hpp>
|
||||||
|
|
||||||
|
#include <clipper/clipper_z.hpp>
|
||||||
|
#include <clipper/clipper.hpp>
|
||||||
#include "BoundingBox.hpp"
|
#include "BoundingBox.hpp"
|
||||||
#include "ClipperUtils.hpp"
|
#include "ClipperUtils.hpp"
|
||||||
#include "Config.hpp"
|
#include "Config.hpp"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue