Speed up by skip model triangles out of bounding box

+ skip outward traingles (actualy set to 89 Degree for sure)
This commit is contained in:
Filip Sykala 2022-05-30 19:30:14 +02:00
parent 49467667f8
commit b69653f967

View File

@ -68,6 +68,9 @@ using FI = CGAL::SM_Face_index;
using P3 = CGAL::Epick::Point_3; using P3 = CGAL::Epick::Point_3;
using Project = Emboss::IProjection;
using Project3f = Emboss::IProject3f;
/// <summary> /// <summary>
/// IntersectingElement /// IntersectingElement
/// ///
@ -154,7 +157,32 @@ struct IntersectingElement
/// <param name="projection">direction</param> /// <param name="projection">direction</param>
void set_skip_for_outward_projection(std::vector<bool> &skip_indicies, void set_skip_for_outward_projection(std::vector<bool> &skip_indicies,
const indexed_triangle_set &its, const indexed_triangle_set &its,
const Emboss::IProject3f &projection); const Project3f &projection);
/// <summary>
/// Set true for indicies outward and almost parallel together.
/// Note: internally calculate normals
/// </summary>
/// <param name="skip_indicies">Flag to convert triangle to cgal</param>
/// <param name="its">model</param>
/// <param name="projection">Direction to measure angle</param>
/// <param name="max_angle">Maximal allowed angle between opposit normal and projection direction [in DEG]</param>
void set_skip_by_angle(std::vector<bool> &skip_indicies,
const indexed_triangle_set &its,
const Project3f &projection,
double max_angle = 89.);
/// <summary>
/// Set true for indices out of area of interest
/// </summary>
/// <param name="skip_indicies">Flag to convert triangle to cgal</param>
/// <param name="its">model</param>
/// <param name="projection">Convert 2d point to pair of 3d points</param>
/// <param name="shapes">after projection define AOI</param>
void set_skip_for_out_of_aoi(std::vector<bool> &skip_indicies,
const indexed_triangle_set &its,
const Project &projection,
const ExPolygons &shapes);
/// <summary> /// <summary>
/// Convert triangle mesh model to CGAL Surface_mesh /// Convert triangle mesh model to CGAL Surface_mesh
@ -162,11 +190,11 @@ void set_skip_for_outward_projection(std::vector<bool> &skip_indicies,
/// Add property map for source face index /// Add property map for source face index
/// </summary> /// </summary>
/// <param name="its">Model</param> /// <param name="its">Model</param>
/// <param name="projection">Projection to filtrate out oposite triangles</param> /// <param name="skip_indicies">Flags that triangle should be skiped</param>
/// <returns>CGAL mesh - half edge mesh</returns> /// <returns>CGAL mesh - half edge mesh</returns>
CutMesh to_cgal(const indexed_triangle_set &its, const ::Emboss::IProject3f & projection); CutMesh to_cgal(const indexed_triangle_set &its,
const std::vector<bool> &skip_indicies);
using Project = Emboss::IProjection;
/// <summary> /// <summary>
/// Covert 2d shape (e.g. Glyph) to CGAL model /// Covert 2d shape (e.g. Glyph) to CGAL model
/// </summary> /// </summary>
@ -293,7 +321,7 @@ void set_face_type(FaceTypeMap &face_type_map,
void set_almost_parallel_type(FaceTypeMap &face_type_map, void set_almost_parallel_type(FaceTypeMap &face_type_map,
const CutMesh &mesh, const CutMesh &mesh,
const Emboss::IProject3f &projection); const Project3f &projection);
/// <summary> /// <summary>
/// Check if face is almost parallel /// Check if face is almost parallel
@ -306,7 +334,7 @@ void set_almost_parallel_type(FaceTypeMap &face_type_map,
/// <returns>True when Triangle is almost parallel with direction of projection</returns> /// <returns>True when Triangle is almost parallel with direction of projection</returns>
bool is_almost_parallel(FI fi, bool is_almost_parallel(FI fi,
const CutMesh &mesh, const CutMesh &mesh,
const Emboss::IProject3f &projection, const Project3f &projection,
float threshold = static_cast<float>(std::cos(80 * M_PI / 180))); float threshold = static_cast<float>(std::cos(80 * M_PI / 180)));
/// <summary> /// <summary>
@ -424,7 +452,7 @@ bool has_minimal_contour_points(const std::vector<HI> &outlines,
/// <returns>True when triangle normal is toward projection otherwise FALSE</returns> /// <returns>True when triangle normal is toward projection otherwise FALSE</returns>
bool is_toward_projection(FI fi, bool is_toward_projection(FI fi,
const CutMesh &mesh, const CutMesh &mesh,
const Emboss::IProject3f &projection); const Project3f &projection);
/// <summary> /// <summary>
/// Check orientation of triangle defined by vertices a, b, c in CCW order /// Check orientation of triangle defined by vertices a, b, c in CCW order
@ -437,7 +465,7 @@ bool is_toward_projection(FI fi,
bool is_toward_projection(const Vec3f &a, bool is_toward_projection(const Vec3f &a,
const Vec3f &b, const Vec3f &b,
const Vec3f &c, const Vec3f &c,
const Emboss::IProject3f &projection); const Project3f &projection);
/// <summary> /// <summary>
/// Check orientation of triangle /// Check orientation of triangle
/// </summary> /// </summary>
@ -447,7 +475,7 @@ bool is_toward_projection(const Vec3f &a,
/// <returns>True when triangle normal is toward projection otherwise FALSE</returns> /// <returns>True when triangle normal is toward projection otherwise FALSE</returns>
bool is_toward_projection(const stl_triangle_vertex_indices &t, bool is_toward_projection(const stl_triangle_vertex_indices &t,
const std::vector<stl_vertex> &vertices, const std::vector<stl_vertex> &vertices,
const Emboss::IProject3f &projection); const Project3f &projection);
/// <summary> /// <summary>
/// Copy triangles from CGAL mesh into index triangle set /// Copy triangles from CGAL mesh into index triangle set
@ -502,7 +530,16 @@ SurfaceCut Slic3r::cut_surface(const indexed_triangle_set &model,
const ExPolygons &shapes, const ExPolygons &shapes,
const Emboss::IProjection &projection) const Emboss::IProjection &projection)
{ {
priv::CutMesh cgal_model = priv::to_cgal(model, projection); if (model.empty() || shapes.empty() ) return {};
std::vector<bool> skip_indicies(model.indices.size(), {false});
// cut out of bounding box triangles
priv::set_skip_for_out_of_aoi(skip_indicies, model, projection, shapes);
// cut out opposit triangles
//priv::set_skip_for_outward_projection(skip_indicies, model, projection);
priv::set_skip_by_angle(skip_indicies, model, projection);
priv::CutMesh cgal_model = priv::to_cgal(model, skip_indicies);
#ifdef DEBUG_OUTPUT_DIR #ifdef DEBUG_OUTPUT_DIR
CGAL::IO::write_OFF(DEBUG_OUTPUT_DIR + "model.off", cgal_model); // only debug CGAL::IO::write_OFF(DEBUG_OUTPUT_DIR + "model.off", cgal_model); // only debug
@ -548,10 +585,11 @@ SurfaceCut Slic3r::cut_surface(const indexed_triangle_set &model,
priv::store(cgal_model, face_type_map, DEBUG_OUTPUT_DIR + "constrained.off"); // only debug priv::store(cgal_model, face_type_map, DEBUG_OUTPUT_DIR + "constrained.off"); // only debug
#endif // DEBUG_OUTPUT_DIR #endif // DEBUG_OUTPUT_DIR
priv::set_almost_parallel_type(face_type_map, cgal_model, projection); // It is neccesary when almost parallel face are contained in projection
#ifdef DEBUG_OUTPUT_DIR // priv::set_almost_parallel_type(face_type_map, cgal_model, projection);
priv::store(cgal_model, face_type_map, DEBUG_OUTPUT_DIR + "constrainedWithAlmostParallel.off"); // only debug //#ifdef DEBUG_OUTPUT_DIR
#endif // DEBUG_OUTPUT_DIR // priv::store(cgal_model, face_type_map, DEBUG_OUTPUT_DIR + "constrainedWithAlmostParallel.off"); // only debug
//#endif // DEBUG_OUTPUT_DIR
priv::flood_fill_inner(cgal_model, face_type_map); priv::flood_fill_inner(cgal_model, face_type_map);
// Seed fill the other faces inside the region. // Seed fill the other faces inside the region.
@ -588,11 +626,12 @@ SurfaceCut Slic3r::cut_surface(const indexed_triangle_set &model,
priv::store(result, DEBUG_OUTPUT_DIR + "cuts/"); // only debug priv::store(result, DEBUG_OUTPUT_DIR + "cuts/"); // only debug
#endif // DEBUG_OUTPUT_DIR #endif // DEBUG_OUTPUT_DIR
// TODO: fill skipped source triangles to surface of cut
return merge(std::move(result)); return merge(std::move(result));
} }
indexed_triangle_set Slic3r::cuts2model(const SurfaceCuts &cuts, indexed_triangle_set Slic3r::cuts2model(const SurfaceCuts &cuts,
const Emboss::IProject3f &projection) const priv::Project3f &projection)
{ {
indexed_triangle_set result; indexed_triangle_set result;
size_t count_vertices = 0; size_t count_vertices = 0;
@ -673,7 +712,7 @@ indexed_triangle_set Slic3r::cuts2model(const SurfaceCuts &cuts,
} }
indexed_triangle_set Slic3r::cut2model(const SurfaceCut &cut, indexed_triangle_set Slic3r::cut2model(const SurfaceCut &cut,
const Emboss::IProject3f &projection) const priv::Project3f &projection)
{ {
assert(!cut.empty()); assert(!cut.empty());
size_t count_vertices = cut.vertices.size() * 2; size_t count_vertices = cut.vertices.size() * 2;
@ -737,7 +776,7 @@ indexed_triangle_set Slic3r::cut2model(const SurfaceCut &cut,
bool priv::is_toward_projection(FI fi, bool priv::is_toward_projection(FI fi,
const CutMesh &mesh, const CutMesh &mesh,
const Emboss::IProject3f &projection) const Project3f &projection)
{ {
HI hi = mesh.halfedge(fi); HI hi = mesh.halfedge(fi);
@ -754,7 +793,7 @@ bool priv::is_toward_projection(FI fi,
bool priv::is_toward_projection(const stl_triangle_vertex_indices &t, bool priv::is_toward_projection(const stl_triangle_vertex_indices &t,
const std::vector<stl_vertex> &vertices, const std::vector<stl_vertex> &vertices,
const Emboss::IProject3f &projection) const Project3f &projection)
{ {
return is_toward_projection(vertices[t[0]], vertices[t[1]], return is_toward_projection(vertices[t[0]], vertices[t[1]],
vertices[t[2]], projection); vertices[t[2]], projection);
@ -763,7 +802,7 @@ bool priv::is_toward_projection(const stl_triangle_vertex_indices &t,
bool priv::is_toward_projection(const Vec3f &a, bool priv::is_toward_projection(const Vec3f &a,
const Vec3f &b, const Vec3f &b,
const Vec3f &c, const Vec3f &c,
const Emboss::IProject3f &projection) const Project3f &projection)
{ {
P3 cgal_a(a.x(), a.y(), a.z()); P3 cgal_a(a.x(), a.y(), a.z());
P3 cgal_b(b.x(), b.y(), b.z()); P3 cgal_b(b.x(), b.y(), b.z());
@ -779,8 +818,9 @@ bool priv::is_toward_projection(const Vec3f &a,
void priv::set_skip_for_outward_projection(std::vector<bool> &skip_indicies, void priv::set_skip_for_outward_projection(std::vector<bool> &skip_indicies,
const indexed_triangle_set &its, const indexed_triangle_set &its,
const Emboss::IProject3f &projection) const Project3f &projection)
{ {
assert(skip_indicies.size() == its.indices.size());
for (const auto &t : its.indices) { for (const auto &t : its.indices) {
size_t index = &t - &its.indices.front(); size_t index = &t - &its.indices.front();
if (skip_indicies[index]) continue; if (skip_indicies[index]) continue;
@ -789,14 +829,129 @@ void priv::set_skip_for_outward_projection(std::vector<bool> &skip_indicies,
} }
} }
priv::CutMesh priv::to_cgal(const indexed_triangle_set &its, void priv::set_skip_by_angle(std::vector<bool> &skip_indicies,
const Emboss::IProject3f &projection) const indexed_triangle_set &its,
const Project3f &projection,
double max_angle)
{ {
if (its.empty()) return {}; float threshold = static_cast<float>(cos(max_angle / 180. * M_PI));
std::vector<bool> skip_indicies(its.indices.size(), {false}); assert(skip_indicies.size() == its.indices.size());
// cut out opposit triangles for (const stl_triangle_vertex_indices& face : its.indices) {
set_skip_for_outward_projection(skip_indicies, its, projection); size_t index = &face - &its.indices.front();
if (skip_indicies[index]) continue;
Vec3f n = its_face_normal(its, face);
const Vec3f v = its.vertices[face[0]];
// Improve: For Orthogonal Projection it is same for each vertex
Vec3f projected = projection.project(v);
Vec3f project_dir = projected - v;
project_dir.normalize();
float cos_alpha = project_dir.dot(n);
if (cos_alpha > threshold) continue;
skip_indicies[index] = true;
}
}
void priv::set_skip_for_out_of_aoi(std::vector<bool> &skip_indicies,
const indexed_triangle_set &its,
const Project &projection,
const ExPolygons &shapes)
{
assert(skip_indicies.size() == its.indices.size());
BoundingBox shapes_bb = get_extents(shapes);
// 1`*----* 2`
// / 2 /|
// 1 *----* |
// | | * 3`
// | |/
// 0 *----* 3
//////////////////
std::array<std::pair<Vec3f, Vec3f>, 4> bb;
int index = 0;
for (Point v :
{shapes_bb.min, Point{shapes_bb.min.x(), shapes_bb.max.y()},
shapes_bb.max, Point{shapes_bb.max.x(), shapes_bb.min.y()}})
bb[index++] = projection.create_front_back(v);
// define planes to test
// 0 .. under
// 1 .. left
// 2 .. above
// 3 .. right
size_t prev_i = 3;
std::array<std::pair<Vec3d, Vec3d>, 4> point_normals;
for (size_t i = 0; i < 4; i++) {
const Vec3f &p1 = bb[i].first;
const Vec3f &p2 = bb[i].second;
const Vec3f &p3 = bb[prev_i].first;
prev_i = i;
Vec3d v1 = (p2 - p1).cast<double>();
v1.normalize();
Vec3d v2 = (p3 - p1).cast<double>();
v2.normalize();
Vec3d normal = v2.cross(v1);
normal.normalize();
point_normals[i] = {p1.cast<double>(), normal};
}
// same meaning as point normal
std::array<std::vector<bool>, 4> is_on_sides;
for (size_t side = 0; side < 4; side++)
is_on_sides[side] = std::vector<bool>(its.vertices.size(), {false});
auto is_out_of = [&point_normals](int side, const Vec3d &v) -> bool {
const auto &[p, n] = point_normals[side];
double signed_distance = (v - p).dot(n);
return signed_distance > 1e-5;
};
// inspect all vertices when it is out of bounding box
for (size_t i = 0; i < its.vertices.size(); i++) {
Vec3d v = its.vertices[i].cast<double>();
// under + above
for (int side : {0, 2}) {
if (is_out_of(side, v)) {
is_on_sides[side][i] = true;
break;
}
}
// left + right
for (int side : {1, 3}) {
if (is_out_of(side, v)) {
is_on_sides[side][i] = true;
break;
}
}
}
auto is_all_on_one_side = [is_on_sides](const Vec3i &t) -> bool {
for (size_t side = 0; side < 4; side++) {
bool result = true;
for (auto vi : t){
if (!is_on_sides[side][vi]) {
result = false;
break;
}
}
if (result) return true;
}
return false;
};
// inspect all triangles, when it is out of bounding box
for (size_t i = 0; i < its.indices.size(); i++) {
if (skip_indicies[i]) continue;
const auto& t = its.indices[i];
if (is_all_on_one_side(t))
skip_indicies[i] = true;
}
}
priv::CutMesh priv::to_cgal(const indexed_triangle_set &its,
const std::vector<bool> &skip_indicies)
{
const std::vector<stl_vertex> &vertices = its.vertices; const std::vector<stl_vertex> &vertices = its.vertices;
const std::vector<stl_triangle_vertex_indices> &indices = its.indices; const std::vector<stl_triangle_vertex_indices> &indices = its.indices;
@ -1022,7 +1177,7 @@ void priv::set_face_type(FaceTypeMap &face_type_map,
void priv::set_almost_parallel_type(FaceTypeMap &face_type_map, void priv::set_almost_parallel_type(FaceTypeMap &face_type_map,
const CutMesh &mesh, const CutMesh &mesh,
const Emboss::IProject3f &projection) const Project3f &projection)
{ {
for (const FI &fi : mesh.faces()) { for (const FI &fi : mesh.faces()) {
auto &type = face_type_map[fi]; auto &type = face_type_map[fi];
@ -1040,7 +1195,7 @@ void priv::set_almost_parallel_type(FaceTypeMap &face_type_map,
} }
} }
bool priv::is_almost_parallel(FI fi, const CutMesh &mesh, const Emboss::IProject3f &projection, float threshold) bool priv::is_almost_parallel(FI fi, const CutMesh &mesh, const Project3f &projection, float threshold)
{ {
HI hi = mesh.halfedge(fi); HI hi = mesh.halfedge(fi);
std::array<VI, 3> vis = { std::array<VI, 3> vis = {