This commit is contained in:
bubnikv 2020-04-28 19:31:18 +02:00
commit 4de4d765ee
154 changed files with 21745 additions and 4745 deletions

View file

@ -2665,4 +2665,168 @@ void PrintObject::_generate_support_material()
support_material.generate(*this);
}
void PrintObject::project_and_append_custom_supports(
FacetSupportType type, std::vector<ExPolygons>& expolys) const
{
for (const ModelVolume* mv : this->model_object()->volumes) {
const std::vector<int> custom_facets = mv->m_supported_facets.get_facets(type);
if (custom_facets.empty())
continue;
const TriangleMesh& mesh = mv->mesh();
const Transform3f& tr1 = mv->get_matrix().cast<float>();
const Transform3f& tr2 = this->trafo().cast<float>();
const Transform3f tr = tr2 * tr1;
// The projection will be at most a pentagon. Let's minimize heap
// reallocations by saving in in the following struct.
// Points are used so that scaling can be done in parallel
// and they can be moved from to create an ExPolygon later.
struct LightPolygon {
LightPolygon() { pts.reserve(5); }
Points pts;
void add(const Vec2f& pt) {
pts.emplace_back(scale_(pt.x()), scale_(pt.y()));
assert(pts.size() <= 5);
}
};
// Structure to collect projected polygons. One element for each triangle.
// Saves vector of polygons and layer_id of the first one.
struct TriangleProjections {
size_t first_layer_id;
std::vector<LightPolygon> polygons;
};
// Vector to collect resulting projections from each triangle.
std::vector<TriangleProjections> projections_of_triangles(custom_facets.size());
// Iterate over all triangles.
tbb::parallel_for(
tbb::blocked_range<size_t>(0, custom_facets.size()),
[&](const tbb::blocked_range<size_t>& range) {
for (size_t idx = range.begin(); idx < range.end(); ++ idx) {
std::array<Vec3f, 3> facet;
// Transform the triangle into worlds coords.
for (int i=0; i<3; ++i)
facet[i] = tr * mesh.its.vertices[mesh.its.indices[custom_facets[idx]](i)];
// Ignore triangles with upward-pointing normal.
if ((facet[1]-facet[0]).cross(facet[2]-facet[0]).z() > 0.)
continue;
// Sort the three vertices according to z-coordinate.
std::sort(facet.begin(), facet.end(),
[](const Vec3f& pt1, const Vec3f&pt2) {
return pt1.z() < pt2.z();
});
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()));
}
// Find lowest slice not below the triangle.
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;
// 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())
++last_layer_id;
projections_of_triangles[idx].polygons.resize(
last_layer_id - projections_of_triangles[idx].first_layer_id + 1);
// Calculate how to move points on triangle sides per unit z increment.
Vec2f ta(trianglef[1] - trianglef[0]);
Vec2f tb(trianglef[2] - trianglef[0]);
ta *= 1./(facet[1].z() - facet[0].z());
tb *= 1./(facet[2].z() - facet[0].z());
// Projection on current slice will be build directly in place.
LightPolygon* proj = &projections_of_triangles[idx].polygons[0];
proj->add(trianglef[0]);
bool passed_first = false;
bool stop = false;
// Project a sub-polygon on all slices intersecting the triangle.
while (it != layers().end()) {
const float z = (*it)->slice_z;
// Projections of triangle sides intersections with slices.
// a moves along one side, b tracks the other.
Vec2f a;
Vec2f b;
// If the middle vertex was already passed, append the vertex
// and use ta for tracking the remaining side.
if (z > facet[1].z() && ! passed_first) {
proj->add(trianglef[1]);
ta = trianglef[2]-trianglef[1];
ta *= 1./(facet[2].z() - facet[1].z());
passed_first = true;
}
// This slice is above the triangle already.
if (z > facet[2].z() || it+1 == layers().end()) {
proj->add(trianglef[2]);
stop = true;
}
else {
// Move a, b along the side it currently tracks to get
// projected intersection with current slice.
a = passed_first ? (trianglef[1]+ta*(z-facet[1].z()))
: (trianglef[0]+ta*(z-facet[0].z()));
b = trianglef[0]+tb*(z-facet[0].z());
proj->add(a);
proj->add(b);
}
if (stop)
break;
// Advance to the next layer.
++it;
++proj;
assert(proj <= &projections_of_triangles[idx].polygons.back() );
// a, b are first two points of the polygon for the next layer.
proj->add(b);
proj->add(a);
}
}
}); // end of parallel_for
// Make sure that the output vector can be used.
expolys.resize(layers().size());
// Now append the collected polygons to respective layers.
for (auto& trg : projections_of_triangles) {
int layer_id = trg.first_layer_id;
for (const LightPolygon& poly : trg.polygons) {
expolys[layer_id].emplace_back(std::move(poly.pts));
++layer_id;
}
}
} // loop over ModelVolumes
}
} // namespace Slic3r