Fixes for degenerate cases.

This commit is contained in:
tamasmeszaros 2019-06-20 13:01:48 +02:00
parent c82fd692c3
commit 3b0e0aaed4
4 changed files with 80 additions and 63 deletions

View file

@ -239,48 +239,49 @@ void offset(ExPolygon& sh, coord_t distance, bool edgerounding = true) {
}
}
void offset(Polygon& sh, coord_t distance, bool edgerounding = true) {
using ClipperLib::ClipperOffset;
using ClipperLib::jtRound;
using ClipperLib::jtMiter;
using ClipperLib::etClosedPolygon;
using ClipperLib::Paths;
using ClipperLib::Path;
void offset(Polygon &sh, coord_t distance, bool edgerounding = true)
{
using ClipperLib::ClipperOffset;
using ClipperLib::jtRound;
using ClipperLib::jtMiter;
using ClipperLib::etClosedPolygon;
using ClipperLib::Paths;
using ClipperLib::Path;
auto&& ctour = Slic3rMultiPoint_to_ClipperPath(sh);
auto &&ctour = Slic3rMultiPoint_to_ClipperPath(sh);
// If the input is not at least a triangle, we can not do this algorithm
if(ctour.size() < 3) {
BOOST_LOG_TRIVIAL(error) << "Invalid geometry for offsetting!";
return;
}
// If the input is not at least a triangle, we can not do this algorithm
if (ctour.size() < 3) {
BOOST_LOG_TRIVIAL(error) << "Invalid geometry for offsetting!";
return;
}
ClipperOffset offs;
offs.ArcTolerance = 0.01*scaled(1.);
Paths result;
offs.AddPath(ctour, edgerounding ? jtRound : jtMiter, etClosedPolygon);
offs.Execute(result, static_cast<double>(distance));
ClipperOffset offs;
offs.ArcTolerance = 0.01 * scaled(1.);
Paths result;
offs.AddPath(ctour, edgerounding ? jtRound : jtMiter, etClosedPolygon);
offs.Execute(result, static_cast<double>(distance));
// Offsetting reverts the orientation and also removes the last vertex
// so boost will not have a closed polygon.
// Offsetting reverts the orientation and also removes the last vertex
// so boost will not have a closed polygon.
bool found_the_contour = false;
for(auto& r : result) {
if(ClipperLib::Orientation(r)) {
// We don't like if the offsetting generates more than one contour
// but throwing would be an overkill. Instead, we should warn the
// caller about the inability to create correct geometries
if(!found_the_contour) {
auto rr = ClipperPath_to_Slic3rPolygon(r);
sh.points.swap(rr.points);
found_the_contour = true;
} else {
BOOST_LOG_TRIVIAL(warning)
<< "Warning: offsetting result is invalid!";
}
}
}
}
bool found_the_contour = false;
for (auto &r : result) {
if (ClipperLib::Orientation(r)) {
// We don't like if the offsetting generates more than one contour
// but throwing would be an overkill. Instead, we should warn the
// caller about the inability to create correct geometries
if (!found_the_contour) {
auto rr = ClipperPath_to_Slic3rPolygon(r);
sh.points.swap(rr.points);
found_the_contour = true;
} else {
BOOST_LOG_TRIVIAL(warning)
<< "Warning: offsetting result is invalid!";
}
}
}
}
/// Unification of polygons (with clipper) preserving holes as well.
ExPolygons unify(const ExPolygons& shapes) {

View file

@ -73,6 +73,7 @@ public:
inline double ground_level() const { return m_ground_level + m_gnd_offset; }
inline void ground_level_offset(double o) { m_gnd_offset = o; }
inline double ground_level_offset() const { return m_gnd_offset; }
inline const Eigen::MatrixXd& V() const { return m_V; }
inline const Eigen::MatrixXi& F() const { return m_F; }

View file

@ -530,6 +530,7 @@ struct CompactBridge {
const Vec3d& ep,
const Vec3d& n,
double r,
bool endball = true,
size_t steps = 45)
{
Vec3d startp = sp + r * n;
@ -543,12 +544,14 @@ struct CompactBridge {
double fa = 2*PI/steps;
auto upperball = sphere(r, Portion{PI / 2 - fa, PI}, fa);
for(auto& p : upperball.points) p += startp;
auto lowerball = sphere(r, Portion{0, PI/2 + 2*fa}, fa);
for(auto& p : lowerball.points) p += endp;
if(endball) {
auto lowerball = sphere(r, Portion{0, PI/2 + 2*fa}, fa);
for(auto& p : lowerball.points) p += endp;
mesh.merge(lowerball);
}
mesh.merge(upperball);
mesh.merge(lowerball);
}
};
@ -594,13 +597,17 @@ struct Pad {
// base silhouette. Create the offsetted version and punch the
// breaksticks across its perimeter.
ExPolygons modelbase_sticks = modelbase;
ExPolygons modelbase_offs = modelbase;
if (pcfg.embed_object.object_gap_mm > 0.0)
modelbase_sticks
= offset_ex(modelbase_sticks,
modelbase_offs
= offset_ex(modelbase_offs,
float(scaled(pcfg.embed_object.object_gap_mm)));
// Create a spatial index of the support silhouette polygons.
// This will be used to check for intersections with the model
// silhouette polygons. If there is no intersection, then a certain
// part of the pad is redundant as it does not host any supports.
BoxIndex bindex;
{
unsigned idx = 0;
@ -611,14 +618,27 @@ struct Pad {
}
}
// Punching the breaksticks across the offsetted polygon perimeters
ExPolygons pad_stickholes; pad_stickholes.reserve(modelbase.size());
for(auto& poly : modelbase_sticks) {
for(auto& poly : modelbase_offs) {
if (!bindex.query(poly.contour.bounding_box(),
BoxIndex::qtIntersects).empty()) {
std::vector<BoxIndexEl> qres =
bindex.query(poly.contour.bounding_box(),
BoxIndex::qtIntersects);
if (!qres.empty()) {
// The model silhouette polygon 'poly' HAS an intersection
// with the support silhouettes. Include this polygon
// in the pad holes with the breaksticks and merge the
// original (offsetted) version with the rest of the pad
// base plate.
basep.emplace_back(poly.contour);
// The holes of 'poly' will become positive parts of the
// pad, so they has to be checked for intersections as well
// and erased if there is no intersection with the supports
auto it = poly.holes.begin();
while(it != poly.holes.end()) {
if (bindex.query(it->bounding_box(),
@ -627,7 +647,8 @@ struct Pad {
else
++it;
}
// Punch the breaksticks
sla::breakstick_holes(
poly,
pcfg.embed_object.object_gap_mm, // padding
@ -638,7 +659,7 @@ struct Pad {
pad_stickholes.emplace_back(poly);
}
}
create_base_pool(basep, tmesh, pad_stickholes, cfg);
} else {
for (const ExPolygon &bp : modelbase) basep.emplace_back(bp.contour);
@ -1495,12 +1516,13 @@ class SLASupportTree::Algorithm {
Vec3d pgnd = {endp(X), endp(Y), gndlvl};
can_add_base = result.score > min_dist;
double gnd_offs = m_mesh.ground_level_offset();
auto abort_in_shame =
[&normal_mode, &can_add_base, &endp, jp, gndlvl]()
[gnd_offs, &normal_mode, &can_add_base, &endp, jp, gndlvl]()
{
normal_mode = true;
can_add_base = false; // Nothing left to do, hope for the best
endp = {jp(X), jp(Y), gndlvl};
endp = {jp(X), jp(Y), gndlvl - gnd_offs };
};
// We have to check if the bridge is feasible.
@ -2317,7 +2339,8 @@ public:
double idist = bridge_mesh_intersect(sph, dir, R, true);
double dist = ray_mesh_intersect(sj, dir);
if (std::isinf(dist))
dist = sph(Z) - m_result.ground_level - HWIDTH_MM;
dist = sph(Z) - m_mesh.ground_level()
+ m_mesh.ground_level_offset();
if(std::isnan(idist) || idist < 2*R ||
std::isnan(dist) || dist < 2*R)
@ -2329,7 +2352,7 @@ public:
}
Vec3d ej = sj + (dist + HWIDTH_MM)* dir;
m_result.add_compact_bridge(sp, ej, n, R);
m_result.add_compact_bridge(sp, ej, n, R, !std::isinf(dist));
}
}
};

View file

@ -1084,9 +1084,6 @@ void SLAPrint::process()
using ClipperPolygons = std::vector<ClipperPolygon>;
namespace sl = libnest2d::shapelike; // For algorithms
// If the raster has vertical orientation, we will flip the coordinates
// bool flpXY = m_printer_config.display_orientation.getInt() == SLADisplayOrientation::sladoPortrait;
// Set up custom union and diff functions for clipper polygons
auto polyunion = [] (const ClipperPolygons& subjects)
{
@ -1194,11 +1191,6 @@ void SLAPrint::process()
sl::translate(poly, ClipperPoint{instances[i].shift(X),
instances[i].shift(Y)});
// if (flpXY) {
// for(auto& p : poly.Contour) std::swap(p.X, p.Y);
// for(auto& h : poly.Holes) for(auto& p : h) std::swap(p.X, p.Y);
// }
polygons.emplace_back(std::move(poly));
}
}