Fix of Paint on support ignores some paints. #5948
When projecting the horizontal or nearly horizontal support enforcers or blockers into object layers, the projection may fall on a layer above or below the layer where it should in case the nearly horizontal support enforcer or blocker triangles are intersecting the slicing plane of one of the object layers. Due to numerical issues, projection of the support blocker or enforcer triangles may not fall to the same side of the slicing plane as when slicing the object. To make the projection robust, horizontal triangles are newly projected to both the layer below and above if they are close to the object slicing plane.
This commit is contained in:
parent
e1c201e714
commit
8ba230db9f
@ -2802,7 +2802,8 @@ void PrintObject::project_and_append_custom_facets(
|
||||
const Transform3f& tr2 = this->trafo().cast<float>();
|
||||
const Transform3f tr = tr2 * tr1;
|
||||
const float tr_det_sign = (tr.matrix().determinant() > 0. ? 1.f : -1.f);
|
||||
|
||||
const Vec2f center = unscaled<float>(this->center_offset());
|
||||
ConstLayerPtrsAdaptor layers = this->layers();
|
||||
|
||||
// The projection will be at most a pentagon. Let's minimize heap
|
||||
// reallocations by saving in in the following struct.
|
||||
@ -2810,10 +2811,17 @@ void PrintObject::project_and_append_custom_facets(
|
||||
// and they can be moved from to create an ExPolygon later.
|
||||
struct LightPolygon {
|
||||
LightPolygon() { pts.reserve(5); }
|
||||
LightPolygon(const std::array<Vec2f, 3>& tri) {
|
||||
pts.reserve(3);
|
||||
pts.emplace_back(scaled<coord_t>(tri.front()));
|
||||
pts.emplace_back(scaled<coord_t>(tri[1]));
|
||||
pts.emplace_back(scaled<coord_t>(tri.back()));
|
||||
}
|
||||
|
||||
Points pts;
|
||||
|
||||
void add(const Vec2f& pt) {
|
||||
pts.emplace_back(scale_(pt.x()), scale_(pt.y()));
|
||||
pts.emplace_back(scaled<coord_t>(pt));
|
||||
assert(pts.size() <= 5);
|
||||
}
|
||||
};
|
||||
@ -2831,7 +2839,7 @@ void PrintObject::project_and_append_custom_facets(
|
||||
// Iterate over all triangles.
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<size_t>(0, custom_facets.indices.size()),
|
||||
[&](const tbb::blocked_range<size_t>& range) {
|
||||
[center, &custom_facets, &tr, tr_det_sign, seam, layers, &projections_of_triangles](const tbb::blocked_range<size_t>& range) {
|
||||
for (size_t idx = range.begin(); idx < range.end(); ++ idx) {
|
||||
|
||||
std::array<Vec3f, 3> facet;
|
||||
@ -2857,30 +2865,43 @@ void PrintObject::project_and_append_custom_facets(
|
||||
});
|
||||
|
||||
std::array<Vec2f, 3> trianglef;
|
||||
for (int i=0; i<3; ++i) {
|
||||
trianglef[i] = Vec2f(facet[i].x(), facet[i].y());
|
||||
trianglef[i] -= Vec2f(unscale<float>(this->center_offset().x()),
|
||||
unscale<float>(this->center_offset().y()));
|
||||
}
|
||||
for (int i=0; i<3; ++i)
|
||||
trianglef[i] = to_2d(facet[i]) - center;
|
||||
|
||||
// Find lowest slice not below the triangle.
|
||||
auto it = std::lower_bound(layers().begin(), layers().end(), facet[0].z()+EPSILON,
|
||||
auto it = std::lower_bound(layers.begin(), layers.end(), facet[0].z()+EPSILON,
|
||||
[](const Layer* l1, float z) {
|
||||
return l1->slice_z < z;
|
||||
});
|
||||
|
||||
// Count how many projections will be generated for this triangle
|
||||
// and allocate respective amount in projections_of_triangles.
|
||||
projections_of_triangles[idx].first_layer_id = it-layers().begin();
|
||||
size_t last_layer_id = projections_of_triangles[idx].first_layer_id;
|
||||
size_t first_layer_id = projections_of_triangles[idx].first_layer_id = it - layers.begin();
|
||||
size_t last_layer_id = first_layer_id;
|
||||
// The cast in the condition below is important. The comparison must
|
||||
// be an exact opposite of the one lower in the code where
|
||||
// the polygons are appended. And that one is on floats.
|
||||
while (last_layer_id + 1 < layers().size()
|
||||
&& float(layers()[last_layer_id]->slice_z) <= facet[2].z())
|
||||
while (last_layer_id + 1 < layers.size()
|
||||
&& float(layers[last_layer_id]->slice_z) <= facet[2].z())
|
||||
++last_layer_id;
|
||||
projections_of_triangles[idx].polygons.resize(
|
||||
last_layer_id - projections_of_triangles[idx].first_layer_id + 1);
|
||||
|
||||
if (first_layer_id == last_layer_id) {
|
||||
// The triangle fits just a single slab, just project it. This also avoids division by zero for horizontal triangles.
|
||||
float dz = facet[2].z() - facet[0].z();
|
||||
assert(dz >= 0);
|
||||
// The face is nearly horizontal and it crosses the slicing plane at first_layer_id - 1.
|
||||
// Rather add this face to both the planes.
|
||||
bool add_below = dz < float(2. * EPSILON) && first_layer_id > 0 && layers[first_layer_id - 1]->slice_z > facet[0].z() - EPSILON;
|
||||
projections_of_triangles[idx].polygons.reserve(add_below ? 2 : 1);
|
||||
projections_of_triangles[idx].polygons.emplace_back(trianglef);
|
||||
if (add_below) {
|
||||
-- projections_of_triangles[idx].first_layer_id;
|
||||
projections_of_triangles[idx].polygons.emplace_back(trianglef);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
projections_of_triangles[idx].polygons.resize(last_layer_id - first_layer_id + 1);
|
||||
|
||||
// Calculate how to move points on triangle sides per unit z increment.
|
||||
Vec2f ta(trianglef[1] - trianglef[0]);
|
||||
@ -2896,7 +2917,7 @@ void PrintObject::project_and_append_custom_facets(
|
||||
bool stop = false;
|
||||
|
||||
// Project a sub-polygon on all slices intersecting the triangle.
|
||||
while (it != layers().end()) {
|
||||
while (it != layers.end()) {
|
||||
const float z = float((*it)->slice_z);
|
||||
|
||||
// Projections of triangle sides intersections with slices.
|
||||
@ -2914,7 +2935,7 @@ void PrintObject::project_and_append_custom_facets(
|
||||
}
|
||||
|
||||
// This slice is above the triangle already.
|
||||
if (z > facet[2].z() || it+1 == layers().end()) {
|
||||
if (z > facet[2].z() || it+1 == layers.end()) {
|
||||
proj->add(trianglef[2]);
|
||||
stop = true;
|
||||
}
|
||||
@ -2944,14 +2965,19 @@ void PrintObject::project_and_append_custom_facets(
|
||||
}); // end of parallel_for
|
||||
|
||||
// Make sure that the output vector can be used.
|
||||
expolys.resize(layers().size());
|
||||
expolys.resize(layers.size());
|
||||
|
||||
// Now append the collected polygons to respective layers.
|
||||
for (auto& trg : projections_of_triangles) {
|
||||
int layer_id = int(trg.first_layer_id);
|
||||
for (const LightPolygon& poly : trg.polygons) {
|
||||
for (LightPolygon &poly : trg.polygons) {
|
||||
if (layer_id >= int(expolys.size()))
|
||||
break; // part of triangle could be projected above top layer
|
||||
assert(! poly.pts.empty());
|
||||
// The resulting triangles are fed to the Clipper library, which seem to handle flipped triangles well.
|
||||
// if (cross2(Vec2d((poly.pts[1] - poly.pts[0]).cast<double>()), Vec2d((poly.pts[2] - poly.pts[1]).cast<double>())) < 0)
|
||||
// std::swap(poly.pts.front(), poly.pts.back());
|
||||
|
||||
expolys[layer_id].emplace_back(std::move(poly.pts));
|
||||
++layer_id;
|
||||
}
|
||||
|
@ -1408,8 +1408,18 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
|
||||
const ExPolygons &enforcer = enforcers[layer_id];
|
||||
if (! enforcer.empty()) {
|
||||
// Enforce supports (as if with 90 degrees of slope) for the regions covered by the enforcer meshes.
|
||||
#ifdef SLIC3R_DEBUG
|
||||
ExPolygons enforcers_united = union_ex(to_polygons(enforcer), false);
|
||||
#endif // SLIC3R_DEBUG
|
||||
Polygons new_contacts = diff(intersection(layerm_polygons, to_polygons(std::move(enforcer))),
|
||||
offset(lower_layer_polygons, 0.05f * fw, SUPPORT_SURFACES_OFFSET_PARAMETERS));
|
||||
#ifdef SLIC3R_DEBUG
|
||||
SVG::export_expolygons(debug_out_path("support-top-contacts-enforcers-run%d-layer%d-z%f.svg", iRun, layer_id, layer.print_z),
|
||||
{ { { union_ex(layerm_polygons, false) }, { "layerm_polygons", "gray", 0.2f } },
|
||||
{ { union_ex(lower_layer_polygons, false) }, { "lower_layer_polygons", "green", 0.5f } },
|
||||
{ enforcers_united, { "enforcers", "blue", 0.5f } },
|
||||
{ { union_ex(new_contacts, true) }, { "new_contacts", "red", "black", "", scaled<coord_t>(0.1f), 0.5f } } });
|
||||
#endif /* SLIC3R_DEBUG */
|
||||
if (! new_contacts.empty()) {
|
||||
if (diff_polygons.empty())
|
||||
diff_polygons = std::move(new_contacts);
|
||||
|
Loading…
Reference in New Issue
Block a user