mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-21 13:47:59 -06:00
New slice_mesh() variant slicing with a single plane only, running
on a single thread only (not parallelized). The new slice_mesh() is used to calculate contour of objects sunken below the print bed.
This commit is contained in:
parent
8df2525355
commit
eb6392dccd
5 changed files with 131 additions and 27 deletions
|
@ -698,27 +698,29 @@ struct EdgeToFace {
|
||||||
bool operator<(const EdgeToFace &other) const { return vertex_low < other.vertex_low || (vertex_low == other.vertex_low && vertex_high < other.vertex_high); }
|
bool operator<(const EdgeToFace &other) const { return vertex_low < other.vertex_low || (vertex_low == other.vertex_low && vertex_high < other.vertex_high); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename ThrowOnCancelCallback>
|
template<typename FaceFilter, typename ThrowOnCancelCallback>
|
||||||
static std::vector<EdgeToFace> create_edge_map(
|
static std::vector<EdgeToFace> create_edge_map(
|
||||||
const indexed_triangle_set &its, ThrowOnCancelCallback throw_on_cancel)
|
const indexed_triangle_set &its, FaceFilter face_filter, ThrowOnCancelCallback throw_on_cancel)
|
||||||
{
|
{
|
||||||
std::vector<EdgeToFace> edges_map;
|
std::vector<EdgeToFace> edges_map;
|
||||||
edges_map.assign(its.indices.size() * 3, EdgeToFace());
|
edges_map.reserve(its.indices.size() * 3);
|
||||||
for (uint32_t facet_idx = 0; facet_idx < its.indices.size(); ++ facet_idx)
|
for (uint32_t facet_idx = 0; facet_idx < its.indices.size(); ++ facet_idx)
|
||||||
for (int i = 0; i < 3; ++ i) {
|
if (face_filter(facet_idx))
|
||||||
EdgeToFace &e2f = edges_map[facet_idx * 3 + i];
|
for (int i = 0; i < 3; ++ i) {
|
||||||
e2f.vertex_low = its.indices[facet_idx][i];
|
edges_map.push_back({});
|
||||||
e2f.vertex_high = its.indices[facet_idx][(i + 1) % 3];
|
EdgeToFace &e2f = edges_map.back();
|
||||||
e2f.face = facet_idx;
|
e2f.vertex_low = its.indices[facet_idx][i];
|
||||||
// 1 based indexing, to be always strictly positive.
|
e2f.vertex_high = its.indices[facet_idx][(i + 1) % 3];
|
||||||
e2f.face_edge = i + 1;
|
e2f.face = facet_idx;
|
||||||
if (e2f.vertex_low > e2f.vertex_high) {
|
// 1 based indexing, to be always strictly positive.
|
||||||
// Sort the vertices
|
e2f.face_edge = i + 1;
|
||||||
std::swap(e2f.vertex_low, e2f.vertex_high);
|
if (e2f.vertex_low > e2f.vertex_high) {
|
||||||
// and make the face_edge negative to indicate a flipped edge.
|
// Sort the vertices
|
||||||
e2f.face_edge = - e2f.face_edge;
|
std::swap(e2f.vertex_low, e2f.vertex_high);
|
||||||
|
// and make the face_edge negative to indicate a flipped edge.
|
||||||
|
e2f.face_edge = - e2f.face_edge;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
throw_on_cancel();
|
throw_on_cancel();
|
||||||
std::sort(edges_map.begin(), edges_map.end());
|
std::sort(edges_map.begin(), edges_map.end());
|
||||||
|
|
||||||
|
@ -727,12 +729,12 @@ static std::vector<EdgeToFace> create_edge_map(
|
||||||
|
|
||||||
// Map from a face edge to a unique edge identifier or -1 if no neighbor exists.
|
// Map from a face edge to a unique edge identifier or -1 if no neighbor exists.
|
||||||
// Two neighbor faces share a unique edge identifier even if they are flipped.
|
// Two neighbor faces share a unique edge identifier even if they are flipped.
|
||||||
template<typename ThrowOnCancelCallback>
|
template<typename FaceFilter, typename ThrowOnCancelCallback>
|
||||||
static inline std::vector<Vec3i> its_face_edge_ids_impl(const indexed_triangle_set &its, ThrowOnCancelCallback throw_on_cancel)
|
static inline std::vector<Vec3i> its_face_edge_ids_impl(const indexed_triangle_set &its, FaceFilter face_filter, ThrowOnCancelCallback throw_on_cancel)
|
||||||
{
|
{
|
||||||
std::vector<Vec3i> out(its.indices.size(), Vec3i(-1, -1, -1));
|
std::vector<Vec3i> out(its.indices.size(), Vec3i(-1, -1, -1));
|
||||||
|
|
||||||
std::vector<EdgeToFace> edges_map = create_edge_map(its, throw_on_cancel);
|
std::vector<EdgeToFace> edges_map = create_edge_map(its, face_filter, throw_on_cancel);
|
||||||
|
|
||||||
// Assign a unique common edge id to touching triangle edges.
|
// Assign a unique common edge id to touching triangle edges.
|
||||||
int num_edges = 0;
|
int num_edges = 0;
|
||||||
|
@ -780,12 +782,17 @@ static inline std::vector<Vec3i> its_face_edge_ids_impl(const indexed_triangle_s
|
||||||
|
|
||||||
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its)
|
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its)
|
||||||
{
|
{
|
||||||
return its_face_edge_ids_impl(its, [](){});
|
return its_face_edge_ids_impl(its, [](const uint32_t){ return true; }, [](){});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, std::function<void()> throw_on_cancel_callback)
|
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, std::function<void()> throw_on_cancel_callback)
|
||||||
{
|
{
|
||||||
return its_face_edge_ids_impl(its, throw_on_cancel_callback);
|
return its_face_edge_ids_impl(its, [](const uint32_t){ return true; }, throw_on_cancel_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, const std::vector<bool> &face_mask)
|
||||||
|
{
|
||||||
|
return its_face_edge_ids_impl(its, [&face_mask](const uint32_t idx){ return face_mask[idx]; }, [](){});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Having the face neighbors available, assign unique edge IDs to face edges for chaining of polygons over slices.
|
// Having the face neighbors available, assign unique edge IDs to face edges for chaining of polygons over slices.
|
||||||
|
|
|
@ -118,6 +118,7 @@ private:
|
||||||
// Used for chaining slice lines into polygons.
|
// Used for chaining slice lines into polygons.
|
||||||
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its);
|
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its);
|
||||||
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, std::function<void()> throw_on_cancel_callback);
|
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, std::function<void()> throw_on_cancel_callback);
|
||||||
|
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, const std::vector<bool> &face_mask);
|
||||||
// Having the face neighbors available, assign unique edge IDs to face edges for chaining of polygons over slices.
|
// Having the face neighbors available, assign unique edge IDs to face edges for chaining of polygons over slices.
|
||||||
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, std::vector<Vec3i> &face_neighbors, bool assign_unbound_edges = false, int *num_edges = nullptr);
|
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, std::vector<Vec3i> &face_neighbors, bool assign_unbound_edges = false, int *num_edges = nullptr);
|
||||||
|
|
||||||
|
|
|
@ -362,6 +362,35 @@ static inline std::vector<IntersectionLines> slice_make_lines(
|
||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename TransformVertex, typename FaceFilter>
|
||||||
|
static inline IntersectionLines slice_make_lines(
|
||||||
|
const std::vector<stl_vertex> &mesh_vertices,
|
||||||
|
const TransformVertex &transform_vertex_fn,
|
||||||
|
const std::vector<stl_triangle_vertex_indices> &mesh_faces,
|
||||||
|
const std::vector<Vec3i> &face_edge_ids,
|
||||||
|
const float plane_z,
|
||||||
|
FaceFilter face_filter)
|
||||||
|
{
|
||||||
|
IntersectionLines lines;
|
||||||
|
for (int face_idx = 0; face_idx < mesh_faces.size(); ++ face_idx)
|
||||||
|
if (face_filter(face_idx)) {
|
||||||
|
const Vec3i &indices = mesh_faces[face_idx];
|
||||||
|
stl_vertex vertices[3] { transform_vertex_fn(mesh_vertices[indices(0)]), transform_vertex_fn(mesh_vertices[indices(1)]), transform_vertex_fn(mesh_vertices[indices(2)]) };
|
||||||
|
// find facet extents
|
||||||
|
const float min_z = fminf(vertices[0].z(), fminf(vertices[1].z(), vertices[2].z()));
|
||||||
|
const float max_z = fmaxf(vertices[0].z(), fmaxf(vertices[1].z(), vertices[2].z()));
|
||||||
|
assert(min_z <= plane_z && max_z >= plane_z);
|
||||||
|
int idx_vertex_lowest = (vertices[1].z() == min_z) ? 1 : ((vertices[2].z() == min_z) ? 2 : 0);
|
||||||
|
IntersectionLine il;
|
||||||
|
// Ignore horizontal triangles. Any valid horizontal triangle must have a vertical triangle connected, otherwise the part has zero volume.
|
||||||
|
if (min_z != max_z && slice_facet(plane_z, vertices, indices, face_edge_ids[face_idx], idx_vertex_lowest, false, il) == FacetSliceType::Slicing) {
|
||||||
|
assert(il.edge_type != IntersectionLine::FacetEdgeType::Horizontal);
|
||||||
|
lines.emplace_back(il);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
// For projecting triangle sets onto slice slabs.
|
// For projecting triangle sets onto slice slabs.
|
||||||
struct SlabLines {
|
struct SlabLines {
|
||||||
// Intersection lines of a slice with a triangle set, CCW oriented.
|
// Intersection lines of a slice with a triangle set, CCW oriented.
|
||||||
|
@ -1720,6 +1749,69 @@ std::vector<Polygons> slice_mesh(
|
||||||
return layers;
|
return layers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Specialized version for a single slicing plane only, running on a single thread.
|
||||||
|
Polygons slice_mesh(
|
||||||
|
const indexed_triangle_set &mesh,
|
||||||
|
// Unscaled Zs
|
||||||
|
const float plane_z,
|
||||||
|
const MeshSlicingParams ¶ms)
|
||||||
|
{
|
||||||
|
std::vector<IntersectionLines> lines;
|
||||||
|
|
||||||
|
{
|
||||||
|
bool trafo_identity = is_identity(params.trafo);
|
||||||
|
Transform3f tf;
|
||||||
|
std::vector<bool> face_mask(mesh.indices.size(), false);
|
||||||
|
|
||||||
|
{
|
||||||
|
// 1) Mark vertices as below or above the slicing plane.
|
||||||
|
std::vector<char> vertex_side(mesh.vertices.size(), 0);
|
||||||
|
if (trafo_identity) {
|
||||||
|
for (size_t i = 0; i < mesh.vertices.size(); ++ i) {
|
||||||
|
float z = mesh.vertices[i].z();
|
||||||
|
char s = z < plane_z ? -1 : z == plane_z ? 0 : 1;
|
||||||
|
vertex_side[i] = s;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tf = make_trafo_for_slicing(params.trafo);
|
||||||
|
for (size_t i = 0; i < mesh.vertices.size(); ++ i) {
|
||||||
|
//FIXME don't need to transform x & y, just Z.
|
||||||
|
float z = (tf * mesh.vertices[i]).z();
|
||||||
|
char s = z < plane_z ? -1 : z == plane_z ? 0 : 1;
|
||||||
|
vertex_side[i] = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Mark faces crossing the plane.
|
||||||
|
for (size_t i = 0; i < mesh.indices.size(); ++ i) {
|
||||||
|
const Vec3i &face = mesh.indices[i];
|
||||||
|
int sides[3] = { vertex_side[face(0)], vertex_side[face(1)], vertex_side[face(2)] };
|
||||||
|
face_mask[i] = sides[0] * sides[1] <= 0 || sides[1] * sides[2] <= 0 || sides[0] * sides[2] <= 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) Calculate face neighbors for just the faces in face_mask.
|
||||||
|
std::vector<Vec3i> face_edge_ids = its_face_edge_ids(mesh, face_mask);
|
||||||
|
|
||||||
|
// 4) Slice "face_mask" triangles, collect line segments.
|
||||||
|
// It likely is not worthwile to copy the vertices. Apply the transformation in place.
|
||||||
|
if (trafo_identity) {
|
||||||
|
lines.emplace_back(slice_make_lines(
|
||||||
|
mesh.vertices, [](const Vec3f &p) { return Vec3f(scaled<float>(p.x()), scaled<float>(p.y()), p.z()); },
|
||||||
|
mesh.indices, face_edge_ids, plane_z, [&face_mask](int face_idx) { return face_mask[face_idx]; }));
|
||||||
|
} else {
|
||||||
|
// Transform the vertices, scale up in XY, not in Z.
|
||||||
|
lines.emplace_back(slice_make_lines(mesh.vertices, [tf](const Vec3f& p) { return tf * p; }, mesh.indices, face_edge_ids, plane_z,
|
||||||
|
[&face_mask](int face_idx) { return face_mask[face_idx]; }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5) Chain the line segments.
|
||||||
|
std::vector<Polygons> layers = make_loops(lines, params, [](){});
|
||||||
|
assert(layers.size() == 1);
|
||||||
|
return layers.front();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<ExPolygons> slice_mesh_ex(
|
std::vector<ExPolygons> slice_mesh_ex(
|
||||||
const indexed_triangle_set &mesh,
|
const indexed_triangle_set &mesh,
|
||||||
const std::vector<float> &zs,
|
const std::vector<float> &zs,
|
||||||
|
|
|
@ -52,6 +52,12 @@ std::vector<Polygons> slice_mesh(
|
||||||
const MeshSlicingParams ¶ms,
|
const MeshSlicingParams ¶ms,
|
||||||
std::function<void()> throw_on_cancel = []{});
|
std::function<void()> throw_on_cancel = []{});
|
||||||
|
|
||||||
|
// Specialized version for a single slicing plane only, running on a single thread.
|
||||||
|
Polygons slice_mesh(
|
||||||
|
const indexed_triangle_set &mesh,
|
||||||
|
const float plane_z,
|
||||||
|
const MeshSlicingParams ¶ms);
|
||||||
|
|
||||||
std::vector<ExPolygons> slice_mesh_ex(
|
std::vector<ExPolygons> slice_mesh_ex(
|
||||||
const indexed_triangle_set &mesh,
|
const indexed_triangle_set &mesh,
|
||||||
const std::vector<float> &zs,
|
const std::vector<float> &zs,
|
||||||
|
|
|
@ -302,7 +302,7 @@ void GLVolume::SinkingContours::update()
|
||||||
#if ALG_SLICE == ALG_SLICE_MESH
|
#if ALG_SLICE == ALG_SLICE_MESH
|
||||||
MeshSlicingParams slicing_params;
|
MeshSlicingParams slicing_params;
|
||||||
slicing_params.trafo = m_parent.world_matrix();
|
slicing_params.trafo = m_parent.world_matrix();
|
||||||
std::vector<Polygons> list_of_polys = slice_mesh(mesh.its, std::vector<float>{ 0.0f }, slicing_params);
|
Polygons polygons = slice_mesh(mesh.its, 0.0f, slicing_params);
|
||||||
|
|
||||||
auto append_polygon = [this](const Polygon& polygon, GUI::GLModel::InitializationData& data) {
|
auto append_polygon = [this](const Polygon& polygon, GUI::GLModel::InitializationData& data) {
|
||||||
if (!polygon.empty()) {
|
if (!polygon.empty()) {
|
||||||
|
@ -326,11 +326,9 @@ void GLVolume::SinkingContours::update()
|
||||||
|
|
||||||
m_model.reset();
|
m_model.reset();
|
||||||
GUI::GLModel::InitializationData init_data;
|
GUI::GLModel::InitializationData init_data;
|
||||||
for (const Polygons& polygons : list_of_polys) {
|
for (const Polygon& polygon : polygons) {
|
||||||
for (const Polygon& polygon : polygons) {
|
// contour
|
||||||
// contour
|
append_polygon(polygon, init_data);
|
||||||
append_polygon(polygon, init_data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
MeshSlicingParamsEx slicing_params;
|
MeshSlicingParamsEx slicing_params;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue