OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::MeshBoolean::cgal Namespace Reference

Classes

struct  CGALMesh
struct  CGALMeshDeleter

Typedefs

using EpecKernel = CGAL::Exact_predicates_exact_constructions_kernel
using EpicKernel = CGAL::Exact_predicates_inexact_constructions_kernel
using _EpicMesh = CGAL::Surface_mesh<EpicKernel::Point_3>
using _EpecMesh = CGAL::Surface_mesh<EpecKernel::Point_3>
using CGALMeshPtr = std::unique_ptr<CGALMesh, CGALMeshDeleter>

Functions

void save_CGALMesh (const std::string &fname, const CGALMesh &cgal_mesh)
template<class _Mesh>
void triangle_mesh_to_cgal (const TriangleMesh &M, _Mesh &out)
template<class _Mesh>
void triangle_mesh_to_cgal (const std::vector< stl_vertex > &V, const std::vector< stl_triangle_vertex_indices > &F, _Mesh &out)
Vec3f to_vec3f (const _EpicMesh::Point &v)
Vec3f to_vec3f (const _EpecMesh::Point &v)
template<class _Mesh>
indexed_triangle_set cgal_to_indexed_triangle_set (const _Mesh &cgalmesh)
template<class _Mesh>
TriangleMesh cgal_to_triangle_mesh (const _Mesh &cgalmesh)
std::unique_ptr< CGALMesh, CGALMeshDeleter > triangle_mesh_to_cgal (const std::vector< stl_vertex > &V, const std::vector< stl_triangle_vertex_indices > &F)
TriangleMesh cgal_to_triangle_mesh (const CGALMesh &cgalmesh)
indexed_triangle_set cgal_to_indexed_triangle_set (const CGALMesh &cgalmesh)
indexed_triangle_set remesh_isotropic (const indexed_triangle_set &mesh, double target_edge_length, unsigned n_iterations, double sharp_angle_deg, unsigned n_relaxation_steps)
std::optional< std::vector< Vec2f > > parameterize_lscm (const indexed_triangle_set &mesh)
static bool _cgal_diff (CGALMesh &A, CGALMesh &B, CGALMesh &R)
static bool _cgal_union (CGALMesh &A, CGALMesh &B, CGALMesh &R)
static bool _cgal_intersection (CGALMesh &A, CGALMesh &B, CGALMesh &R)
template<class Op>
void _cgal_do (Op &&op, CGALMesh &A, CGALMesh &B)
void minus (CGALMesh &A, CGALMesh &B)
void plus (CGALMesh &A, CGALMesh &B)
void intersect (CGALMesh &A, CGALMesh &B)
bool does_self_intersect (const CGALMesh &mesh)
void segment (CGALMesh &src, std::vector< CGALMesh > &dst, double smoothing_alpha=0.5, int segment_number=5)
std::vector< TriangleMesh > segment (const TriangleMesh &src, double smoothing_alpha, int segment_number)
void merge (std::vector< _EpicMesh > &srcs, _EpicMesh &dst)
TriangleMesh merge (std::vector< TriangleMesh > meshes)
template<class Op>
void _mesh_boolean_do (Op &&op, indexed_triangle_set &A, const indexed_triangle_set &B)
template<class Op>
void _mesh_boolean_do (Op &&op, TriangleMesh &A, const TriangleMesh &B)
void minus (TriangleMesh &A, const TriangleMesh &B)
void plus (TriangleMesh &A, const TriangleMesh &B)
void intersect (TriangleMesh &A, const TriangleMesh &B)
void minus (indexed_triangle_set &A, const indexed_triangle_set &B)
void plus (indexed_triangle_set &A, const indexed_triangle_set &B)
void intersect (indexed_triangle_set &A, const indexed_triangle_set &B)
bool does_self_intersect (const TriangleMesh &mesh)
bool does_bound_a_volume (const CGALMesh &mesh)
bool empty (const CGALMesh &mesh)
CGALMeshPtr clone (const CGALMesh &m)
CGALMeshPtr triangle_mesh_to_cgal (const indexed_triangle_set &M)
CGALMeshPtr triangle_mesh_to_cgal (const TriangleMesh &M)

Typedef Documentation

◆ _EpecMesh

using Slic3r::MeshBoolean::cgal::_EpecMesh = CGAL::Surface_mesh<EpecKernel::Point_3>

◆ _EpicMesh

using Slic3r::MeshBoolean::cgal::_EpicMesh = CGAL::Surface_mesh<EpicKernel::Point_3>

◆ CGALMeshPtr

◆ EpecKernel

using Slic3r::MeshBoolean::cgal::EpecKernel = CGAL::Exact_predicates_exact_constructions_kernel

◆ EpicKernel

using Slic3r::MeshBoolean::cgal::EpicKernel = CGAL::Exact_predicates_inexact_constructions_kernel

Function Documentation

◆ _cgal_diff()

bool Slic3r::MeshBoolean::cgal::_cgal_diff ( CGALMesh & A,
CGALMesh & B,
CGALMesh & R )
static
437{
438 const auto &p = CGALParams::throw_on_self_intersection(true);
439 return CGALProc::corefine_and_compute_difference(A.m, B.m, R.m, p, p);
440}
_EpicMesh m
Definition MeshBoolean.cpp:153

References Slic3r::MeshBoolean::cgal::CGALMesh::m.

Referenced by minus(), minus(), and minus().

Here is the caller graph for this function:

◆ _cgal_do()

template<class Op>
void Slic3r::MeshBoolean::cgal::_cgal_do ( Op && op,
CGALMesh & A,
CGALMesh & B )
455{
456 bool success = false;
457 bool hw_fail = false;
458 try {
459 CGALMesh result;
460 try_catch_signal({SIGSEGV, SIGFPE}, [&success, &A, &B, &result, &op] {
461 success = op(A, B, result);
462 }, [&] { hw_fail = true; });
463 A = std::move(result); // In-place operation does not work
464 } catch (...) {
465 success = false;
466 }
467
468 if (hw_fail)
469 throw Slic3r::HardCrash("CGAL mesh boolean operation crashed.");
470
471 if (! success)
472 throw Slic3r::RuntimeError("CGAL mesh boolean operation failed.");
473}
void try_catch_signal(const SignalT(&sigs)[N], TryFn &&fn, CatchFn &&cfn)
Definition TryCatchSignalSEH.hpp:20
Definition MeshBoolean.cpp:152

References Slic3r::try_catch_signal().

Referenced by _mesh_boolean_do(), _mesh_boolean_do(), intersect(), minus(), and plus().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _cgal_intersection()

bool Slic3r::MeshBoolean::cgal::_cgal_intersection ( CGALMesh & A,
CGALMesh & B,
CGALMesh & R )
static
449{
450 const auto &p = CGALParams::throw_on_self_intersection(true);
451 return CGALProc::corefine_and_compute_intersection(A.m, B.m, R.m, p, p);
452}

References Slic3r::MeshBoolean::cgal::CGALMesh::m.

Referenced by intersect(), intersect(), and intersect().

Here is the caller graph for this function:

◆ _cgal_union()

bool Slic3r::MeshBoolean::cgal::_cgal_union ( CGALMesh & A,
CGALMesh & B,
CGALMesh & R )
static
443{
444 const auto &p = CGALParams::throw_on_self_intersection(true);
445 return CGALProc::corefine_and_compute_union(A.m, B.m, R.m, p, p);
446}

References Slic3r::MeshBoolean::cgal::CGALMesh::m.

Referenced by plus(), plus(), and plus().

Here is the caller graph for this function:

◆ _mesh_boolean_do() [1/2]

template<class Op>
void Slic3r::MeshBoolean::cgal::_mesh_boolean_do ( Op && op,
indexed_triangle_set & A,
const indexed_triangle_set & B )
586{
587 CGALMesh meshA;
588 CGALMesh meshB;
589 triangle_mesh_to_cgal(A.vertices, A.indices, meshA.m);
590 triangle_mesh_to_cgal(B.vertices, B.indices, meshB.m);
591
592 _cgal_do(op, meshA, meshB);
593
595}
void _cgal_do(Op &&op, CGALMesh &A, CGALMesh &B)
Definition MeshBoolean.cpp:454
indexed_triangle_set cgal_to_indexed_triangle_set(const _Mesh &cgalmesh)
Definition MeshBoolean.cpp:229
void triangle_mesh_to_cgal(const TriangleMesh &M, _Mesh &out)
Definition MeshBoolean.cpp:167

References _cgal_do(), cgal_to_indexed_triangle_set(), Slic3r::MeshBoolean::cgal::CGALMesh::m, and triangle_mesh_to_cgal().

Referenced by intersect(), intersect(), minus(), minus(), plus(), and plus().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _mesh_boolean_do() [2/2]

template<class Op>
void Slic3r::MeshBoolean::cgal::_mesh_boolean_do ( Op && op,
TriangleMesh & A,
const TriangleMesh & B )
598{
599 CGALMesh meshA;
600 CGALMesh meshB;
601 triangle_mesh_to_cgal(A.its.vertices, A.its.indices, meshA.m);
602 triangle_mesh_to_cgal(B.its.vertices, B.its.indices, meshB.m);
603
604 _cgal_do(op, meshA, meshB);
605
606 A = cgal_to_triangle_mesh(meshA);
607}
indexed_triangle_set its
Definition TriangleMesh.hpp:164
TriangleMesh cgal_to_triangle_mesh(const _Mesh &cgalmesh)
Definition MeshBoolean.cpp:262

References _cgal_do(), cgal_to_triangle_mesh(), Slic3r::TriangleMesh::its, Slic3r::MeshBoolean::cgal::CGALMesh::m, and triangle_mesh_to_cgal().

Here is the call graph for this function:

◆ cgal_to_indexed_triangle_set() [1/2]

template<class _Mesh>
indexed_triangle_set Slic3r::MeshBoolean::cgal::cgal_to_indexed_triangle_set ( const _Mesh & cgalmesh)
230{
231 indexed_triangle_set its;
232 its.vertices.reserve(cgalmesh.num_vertices());
233 its.indices.reserve(cgalmesh.num_faces());
234
235 const auto &faces = cgalmesh.faces();
236 const auto &vertices = cgalmesh.vertices();
237 int vsize = int(vertices.size());
238
239 for (const auto &vi : vertices) {
240 auto &v = cgalmesh.point(vi); // Don't ask...
241 its.vertices.emplace_back(to_vec3f(v));
242 }
243
244 for (const auto &face : faces) {
245 auto vtc = cgalmesh.vertices_around_face(cgalmesh.halfedge(face));
246
247 int i = 0;
248 Vec3i32 facet;
249 for (auto v : vtc) {
250 int iv = v;
251 if (i > 2 || iv < 0 || iv >= vsize) { i = 0; break; }
252 facet(i++) = iv;
253 }
254
255 if (i == 3)
256 its.indices.emplace_back(facet);
257 }
258
259 return its;
260}
Vec3f to_vec3f(const _EpicMesh::Point &v)
Definition MeshBoolean.cpp:216
Eigen::Matrix< int32_t, 3, 1, Eigen::DontAlign > Vec3i32
Definition Point.hpp:59

References to_vec3f().

Referenced by _mesh_boolean_do(), cgal_to_indexed_triangle_set(), cgal_to_triangle_mesh(), cgal_to_triangle_mesh(), and remesh_isotropic().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cgal_to_indexed_triangle_set() [2/2]

indexed_triangle_set Slic3r::MeshBoolean::cgal::cgal_to_indexed_triangle_set ( const CGALMesh & cgalmesh)
283{
284 return cgal_to_indexed_triangle_set(cgalmesh.m);
285}

References cgal_to_indexed_triangle_set(), and Slic3r::MeshBoolean::cgal::CGALMesh::m.

Here is the call graph for this function:

◆ cgal_to_triangle_mesh() [1/2]

template<class _Mesh>
TriangleMesh Slic3r::MeshBoolean::cgal::cgal_to_triangle_mesh ( const _Mesh & cgalmesh)
263{
264 indexed_triangle_set its = cgal_to_indexed_triangle_set(cgalmesh);
265 return TriangleMesh(std::move(its));
266}
Definition TriangleMesh.hpp:94

References cgal_to_indexed_triangle_set().

Referenced by _mesh_boolean_do(), Slic3r::GUI::Plater::combine_mesh_fff(), Slic3r::GUI::Plater::export_stl(), merge(), and segment().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cgal_to_triangle_mesh() [2/2]

TriangleMesh Slic3r::MeshBoolean::cgal::cgal_to_triangle_mesh ( const CGALMesh & cgalmesh)
278{
280}

References cgal_to_indexed_triangle_set(), and Slic3r::MeshBoolean::cgal::CGALMesh::m.

Here is the call graph for this function:

◆ clone()

CGALMeshPtr Slic3r::MeshBoolean::cgal::clone ( const CGALMesh & m)
659{
660 return CGALMeshPtr{new CGALMesh{m}};
661}
std::unique_ptr< CGALMesh, CGALMeshDeleter > CGALMeshPtr
Definition MeshBoolean.hpp:35

◆ does_bound_a_volume()

bool Slic3r::MeshBoolean::cgal::does_bound_a_volume ( const CGALMesh & mesh)
649{
650 return CGAL::is_closed(mesh.m) && CGALProc::does_bound_a_volume(mesh.m);
651}

References Slic3r::MeshBoolean::cgal::CGALMesh::m.

Referenced by Slic3r::csg::check_csgmesh_booleans().

Here is the caller graph for this function:

◆ does_self_intersect() [1/2]

bool Slic3r::MeshBoolean::cgal::does_self_intersect ( const CGALMesh & mesh)
478{ return CGALProc::does_self_intersect(mesh.m); }

References Slic3r::MeshBoolean::cgal::CGALMesh::m.

Referenced by Slic3r::csg::check_csgmesh_booleans().

Here is the caller graph for this function:

◆ does_self_intersect() [2/2]

bool Slic3r::MeshBoolean::cgal::does_self_intersect ( const TriangleMesh & mesh)
640{
641 CGALMesh cgalm;
642 triangle_mesh_to_cgal(mesh.its.vertices, mesh.its.indices, cgalm.m);
643 return CGALProc::does_self_intersect(cgalm.m);
644}

References Slic3r::TriangleMesh::its, Slic3r::MeshBoolean::cgal::CGALMesh::m, and triangle_mesh_to_cgal().

Here is the call graph for this function:

◆ empty()

bool Slic3r::MeshBoolean::cgal::empty ( const CGALMesh & mesh)
654{
655 return mesh.m.is_empty();
656}

References Slic3r::MeshBoolean::cgal::CGALMesh::m.

Referenced by Slic3r::csg::check_csgmesh_booleans().

Here is the caller graph for this function:

◆ intersect() [1/3]

void Slic3r::MeshBoolean::cgal::intersect ( CGALMesh & A,
CGALMesh & B )
static bool _cgal_intersection(CGALMesh &A, CGALMesh &B, CGALMesh &R)
Definition MeshBoolean.cpp:448

References _cgal_do(), and _cgal_intersection().

Referenced by Slic3r::csg::detail_cgal::perform_csg().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ intersect() [2/3]

void Slic3r::MeshBoolean::cgal::intersect ( indexed_triangle_set & A,
const indexed_triangle_set & B )
635{
637}
void _mesh_boolean_do(Op &&op, indexed_triangle_set &A, const indexed_triangle_set &B)
Definition MeshBoolean.cpp:585

References _cgal_intersection(), and _mesh_boolean_do().

Here is the call graph for this function:

◆ intersect() [3/3]

void Slic3r::MeshBoolean::cgal::intersect ( TriangleMesh & A,
const TriangleMesh & B )
620{
622}

References _cgal_intersection(), and _mesh_boolean_do().

Here is the call graph for this function:

◆ merge() [1/2]

void Slic3r::MeshBoolean::cgal::merge ( std::vector< _EpicMesh > & srcs,
_EpicMesh & dst )
561{
562 _EpicMesh mesh_merged;
563 for (size_t i = 0; i < srcs.size(); i++)
564 {
565 mesh_merged.join(srcs[i]);
566 }
567 if (mesh_merged.is_empty() == false) {
568 CGAL::Polygon_mesh_processing::stitch_borders(mesh_merged);
569 dst = std::move(mesh_merged);
570 }
571}
CGAL::Surface_mesh< EpicKernel::Point_3 > _EpicMesh
Definition MeshBoolean.cpp:149

Referenced by merge(), and Slic3r::ModelObject::merge_volumes().

Here is the caller graph for this function:

◆ merge() [2/2]

TriangleMesh Slic3r::MeshBoolean::cgal::merge ( std::vector< TriangleMesh > meshes)
574{
575 std::vector<_EpicMesh> srcs(meshes.size());
576 for (size_t i = 0; i < meshes.size(); i++)
577 {
579 }
580 _EpicMesh dst;
581 merge(srcs, dst);
582 return cgal_to_triangle_mesh(dst);
583}
void merge(std::vector< _EpicMesh > &srcs, _EpicMesh &dst)
Definition MeshBoolean.cpp:560

References cgal_to_triangle_mesh(), merge(), and triangle_mesh_to_cgal().

Here is the call graph for this function:

◆ minus() [1/3]

void Slic3r::MeshBoolean::cgal::minus ( CGALMesh & A,
CGALMesh & B )
475{ _cgal_do(_cgal_diff, A, B); }
static bool _cgal_diff(CGALMesh &A, CGALMesh &B, CGALMesh &R)
Definition MeshBoolean.cpp:436

References _cgal_diff(), and _cgal_do().

Referenced by Slic3r::csg::detail_cgal::perform_csg().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ minus() [2/3]

void Slic3r::MeshBoolean::cgal::minus ( indexed_triangle_set & A,
const indexed_triangle_set & B )
625{
627}

References _cgal_diff(), and _mesh_boolean_do().

Here is the call graph for this function:

◆ minus() [3/3]

void Slic3r::MeshBoolean::cgal::minus ( TriangleMesh & A,
const TriangleMesh & B )
610{
612}

References _cgal_diff(), and _mesh_boolean_do().

Here is the call graph for this function:

◆ parameterize_lscm()

std::optional< std::vector< Vec2f > > Slic3r::MeshBoolean::cgal::parameterize_lscm ( const indexed_triangle_set & mesh)
362{
363 namespace SMP = CGAL::Surface_mesh_parameterization;
364
365 if (mesh.indices.empty())
366 return std::nullopt;
367
368 _EpicMesh cgal_mesh;
369 triangle_mesh_to_cgal(mesh.vertices, mesh.indices, cgal_mesh);
370
371 using vertex_descriptor = boost::graph_traits<_EpicMesh>::vertex_descriptor;
372 using halfedge_descriptor = boost::graph_traits<_EpicMesh>::halfedge_descriptor;
373
374 // LSCM assumes a single topological disk: one connected component, one boundary loop. A patch
375 // with several disconnected painted islands, or with a hole in it, doesn't qualify -- bail out
376 // rather than silently parameterizing just one arbitrary piece of it.
377 {
378 std::vector<std::size_t> component_id(num_faces(cgal_mesh));
379 const std::size_t num_components = CGAL::Polygon_mesh_processing::connected_components(
380 cgal_mesh, CGAL::make_property_map(component_id));
381 if (num_components != 1)
382 return std::nullopt;
383 }
384
385 const halfedge_descriptor border = CGAL::Polygon_mesh_processing::longest_border(cgal_mesh).first;
386 if (border == halfedge_descriptor())
387 return std::nullopt; // no boundary at all -- a closed patch, which isn't a disk either
388
389 // ...and exactly one boundary loop. One connected component is not enough on its own: a patch with
390 // a hole in it (paint a ring, or erase the middle of a stroke) is a single component with two
391 // loops, and LSCM will happily "parameterize" it into an overlapping, folded-over chart rather
392 // than fail. Walk the border halfedges and check every one of them belongs to the longest loop.
393 {
394 std::size_t border_halfedges = 0;
395 for (halfedge_descriptor h : halfedges(cgal_mesh))
396 if (is_border(h, cgal_mesh))
397 ++border_halfedges;
398 std::size_t loop_length = 0;
399 halfedge_descriptor h = border;
400 do {
401 ++loop_length;
402 h = next(h, cgal_mesh);
403 } while (h != border && loop_length <= border_halfedges);
404 if (loop_length != border_halfedges)
405 return std::nullopt; // more than one boundary loop -- not a topological disk
406 }
407
408 using Point_2 = EpicKernel::Point_2;
409 using UV_pmap = _EpicMesh::Property_map<vertex_descriptor, Point_2>;
410 UV_pmap uv_map = cgal_mesh.add_property_map<vertex_descriptor, Point_2>("h:uv", Point_2(0, 0)).first;
411
412 using Parameterizer = SMP::LSCM_parameterizer_3<_EpicMesh>;
413 const SMP::Error_code err = SMP::parameterize(cgal_mesh, Parameterizer(), border, uv_map);
414 if (err != SMP::OK)
415 return std::nullopt;
416
417 // triangle_mesh_to_cgal() adds vertices in the exact same order as mesh.vertices (see above),
418 // and Surface_mesh assigns indices sequentially on insertion into a fresh mesh, so a
419 // vertex_descriptor's index here is guaranteed to match the original input vertex index --
420 // the same assumption cgal_to_indexed_triangle_set() above already relies on.
421 std::vector<Vec2f> result(mesh.vertices.size(), Vec2f::Zero());
422 for (vertex_descriptor vd : vertices(cgal_mesh)) {
423 const std::size_t idx = std::size_t(vd);
424 if (idx < result.size()) {
425 const Point_2 &uv = uv_map[vd];
426 result[idx] = Vec2f(float(uv.x()), float(uv.y()));
427 }
428 }
429 return result;
430}
Eigen::Matrix< float, 2, 1, Eigen::DontAlign > Vec2f
Definition Point.hpp:64

References triangle_mesh_to_cgal().

Referenced by Slic3r::compute_patch_unwrap().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ plus() [1/3]

void Slic3r::MeshBoolean::cgal::plus ( CGALMesh & A,
CGALMesh & B )
476{ _cgal_do(_cgal_union, A, B); }
static bool _cgal_union(CGALMesh &A, CGALMesh &B, CGALMesh &R)
Definition MeshBoolean.cpp:442

References _cgal_do(), and _cgal_union().

Referenced by Slic3r::csg::detail_cgal::perform_csg().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ plus() [2/3]

void Slic3r::MeshBoolean::cgal::plus ( indexed_triangle_set & A,
const indexed_triangle_set & B )
630{
632}

References _cgal_union(), and _mesh_boolean_do().

Here is the call graph for this function:

◆ plus() [3/3]

void Slic3r::MeshBoolean::cgal::plus ( TriangleMesh & A,
const TriangleMesh & B )
615{
617}

References _cgal_union(), and _mesh_boolean_do().

Here is the call graph for this function:

◆ remesh_isotropic()

indexed_triangle_set Slic3r::MeshBoolean::cgal::remesh_isotropic ( const indexed_triangle_set & mesh,
double target_edge_length,
unsigned n_iterations,
double sharp_angle_deg,
unsigned n_relaxation_steps )
294{
295 if (mesh.indices.empty() || target_edge_length <= 0.0)
296 return mesh;
297
298 _EpicMesh cgal_mesh;
299 triangle_mesh_to_cgal(mesh.vertices, mesh.indices, cgal_mesh);
300 if (cgal_mesh.is_empty() || cgal_mesh.number_of_faces() == 0)
301 return mesh;
302
303 // Surface_mesh::add_face() refuses any face that would make the mesh non-manifold and returns a
304 // null descriptor instead. Remeshing a mesh that silently lost faces that way produces holes in
305 // the output, so bail out and let the caller report it rather than hand back a punctured model.
306 if (cgal_mesh.number_of_faces() != mesh.indices.size())
307 return mesh;
308
309 using edge_descriptor = boost::graph_traits<_EpicMesh>::edge_descriptor;
310 try {
311 // Sharp edges and open borders are pinned before remeshing. Without that, the tangential
312 // relaxation pass slides vertices along the surface and rounds every hard feature off - a
313 // cube comes back with wobbly, eroded edges, which is the most visible way "remeshing does
314 // not work properly". protect_constraints() forbids splitting or collapsing them, but it
315 // requires each constrained edge to already be shorter than 4/3 * target, hence the split
316 // first (passing the map so the halves inherit the constraint). This mirrors CGAL's own
317 // isotropic_remeshing example.
318 auto ecm = cgal_mesh.add_property_map<edge_descriptor, bool>("e:is_constrained", false).first;
319 if (sharp_angle_deg > 0.0)
320 CGALProc::detect_sharp_edges(cgal_mesh, sharp_angle_deg, ecm);
321 for (edge_descriptor e : edges(cgal_mesh)) {
322 const auto h = halfedge(e, cgal_mesh);
323 if (is_border(h, cgal_mesh) || is_border(opposite(h, cgal_mesh), cgal_mesh))
324 put(ecm, e, true);
325 }
326
327 std::vector<edge_descriptor> constrained;
328 for (edge_descriptor e : edges(cgal_mesh))
329 if (get(ecm, e))
330 constrained.push_back(e);
331 if (!constrained.empty())
332 CGALProc::split_long_edges(constrained, target_edge_length, cgal_mesh,
333 CGALParams::edge_is_constrained_map(ecm));
334
335 CGALProc::isotropic_remeshing(faces(cgal_mesh), target_edge_length, cgal_mesh,
336 CGALParams::number_of_iterations(n_iterations)
337 .number_of_relaxation_steps(n_relaxation_steps)
338 .edge_is_constrained_map(ecm)
339 .protect_constraints(true));
340 } catch (const std::exception &) {
341 return mesh; // CGAL throws on some non-manifold / degenerate inputs; leave the mesh untouched
342 }
343 if (cgal_mesh.number_of_faces() == 0)
344 return mesh;
345
346 // isotropic_remeshing edits in place, and its edge collapses only *mark* vertices and faces as
347 // removed - the underlying arrays keep the holes until the garbage is collected. That matters
348 // because cgal_to_indexed_triangle_set() numbers its output vertices by iteration order (which
349 // skips removed slots) while reading each face's corner as the raw integer value of the vertex
350 // descriptor (which does not). Past the first collapse the two disagree, so every triangle
351 // points at the wrong vertices, and any descriptor beyond the live vertex count is dropped
352 // together with its triangle. Compacting first makes descriptor == iteration order again.
353 cgal_mesh.collect_garbage();
354 return cgal_to_indexed_triangle_set(cgal_mesh);
355}
ColorRGB opposite(const ColorRGB &color)
Definition Color.cpp:281

References cgal_to_indexed_triangle_set(), Slic3r::opposite(), and triangle_mesh_to_cgal().

Referenced by Slic3r::GUI::GLGizmoTextureDisplacement::plan_remesh().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ save_CGALMesh()

void Slic3r::MeshBoolean::cgal::save_CGALMesh ( const std::string & fname,
const CGALMesh & cgal_mesh )
158 {
159 std::ofstream os(fname);
160 os << cgal_mesh.m;
161 os.close();
162}

References Slic3r::MeshBoolean::cgal::CGALMesh::m.

◆ segment() [1/2]

void Slic3r::MeshBoolean::cgal::segment ( CGALMesh & src,
std::vector< CGALMesh > & dst,
double smoothing_alpha = 0.5,
int segment_number = 5 )
481{
482 typedef boost::graph_traits<_EpicMesh>::face_descriptor face_descriptor;
483 typedef _EpicMesh::Property_map<face_descriptor, double> Facet_double_map;
484 typedef CGAL::Face_filtered_graph<_EpicMesh> Filtered_graph;
485
486 _EpicMesh mesh = src.m;
487 Facet_double_map sdf_property_map;
488
489 sdf_property_map = mesh.add_property_map<face_descriptor, double>("f:sdf").first;
490
491 CGAL::sdf_values(mesh, sdf_property_map);
492
493 // create a property-map for segment-ids
494 typedef _EpicMesh::Property_map<face_descriptor, std::size_t> Facet_int_map;
495 Facet_int_map segment_property_map = mesh.add_property_map<face_descriptor, std::size_t>("f:sid").first;;
496 // segment the mesh using default parameters for number of levels, and smoothing lambda
497 // Any other scalar values can be used instead of using SDF values computed using the CGAL function
498 std::size_t number_of_segments = CGAL::segmentation_from_sdf_values(mesh, sdf_property_map, segment_property_map, segment_number, smoothing_alpha);
499 //print area of each segment and then put it in a Mesh and print it in an OFF file
500 Filtered_graph segment_mesh(mesh);
501 _EpicMesh mesh_merged;
502 for (std::size_t id = 0; id < number_of_segments; ++id)
503 {
504 segment_mesh.set_selected_faces(id, segment_property_map);
505 //std::cout << "Segment " << id << "'s area is : " << CGAL::Polygon_mesh_processing::area(segment_mesh) << std::endl;
506 _EpicMesh out;
507 CGAL::copy_face_graph(segment_mesh, out);
508
509 // save_CGALMesh("out.off", out);
510
511 // fill holes
512 typedef boost::graph_traits<_EpicMesh>::halfedge_descriptor halfedge_descriptor;
513 typedef boost::graph_traits<_EpicMesh>::vertex_descriptor vertex_descriptor;
514 std::vector<halfedge_descriptor> border_cycles;
515 CGAL::extract_boundary_cycles(out, std::back_inserter(border_cycles));
516 for (halfedge_descriptor h : border_cycles)
517 {
518 std::vector<face_descriptor> patch_facets;
519#if 0
520 std::vector<vertex_descriptor> patch_vertices;
521 CGAL::Polygon_mesh_processing::triangulate_and_refine_hole(out, h, std::back_inserter(patch_facets),
522 std::back_inserter(patch_vertices));
523 std::cout << "* Number of facets in constructed patch: " << patch_facets.size() << std::endl;
524 std::cout << " Number of vertices in constructed patch: " << patch_vertices.size() << std::endl;
525#else
526 CGAL::Polygon_mesh_processing::triangulate_hole(out, h, CGAL::parameters::default_values().face_output_iterator(std::back_inserter(patch_facets)));
527#endif
528 }
529
530 //if (id > 2) {
531 // mesh_merged.join(out);
532 //}
533 //else
534 {
535 dst.emplace_back(CGALMesh(out));
536 }
537 }
538 //if (mesh_merged.is_empty() == false) {
539 // CGAL::Polygon_mesh_processing::stitch_borders(mesh_merged);
540 // dst.emplace_back(std::move(CGALMesh(mesh_merged)));
541 //}
542}

References Slic3r::MeshBoolean::cgal::CGALMesh::m.

Referenced by segment().

Here is the caller graph for this function:

◆ segment() [2/2]

std::vector< TriangleMesh > Slic3r::MeshBoolean::cgal::segment ( const TriangleMesh & src,
double smoothing_alpha,
int segment_number )
545{
546 CGALMesh in_cgal_mesh;
548 std::vector<CGALMesh> out_cgal_meshes;
549 segment(in_cgal_mesh, out_cgal_meshes, smoothing_alpha, segment_number);
550
551 std::vector<TriangleMesh> out_meshes;
552 for (auto& outf_cgal_mesh: out_cgal_meshes)
553 {
554 out_meshes.emplace_back(cgal_to_triangle_mesh(outf_cgal_mesh.m));
555 }
556
557 return out_meshes;
558}
void segment(CGALMesh &src, std::vector< CGALMesh > &dst, double smoothing_alpha=0.5, int segment_number=5)
Definition MeshBoolean.cpp:480

References cgal_to_triangle_mesh(), Slic3r::MeshBoolean::cgal::CGALMesh::m, segment(), and triangle_mesh_to_cgal().

Here is the call graph for this function:

◆ to_vec3f() [1/2]

Vec3f Slic3r::MeshBoolean::cgal::to_vec3f ( const _EpecMesh::Point & v)
inline
222{
223 CGAL::Cartesian_converter<EpecKernel, EpicKernel> cvt;
224 auto iv = cvt(v);
225 return { float(iv.x()), float(iv.y()), float(iv.z()) };
226}

◆ to_vec3f() [2/2]

Vec3f Slic3r::MeshBoolean::cgal::to_vec3f ( const _EpicMesh::Point & v)
inline
217{
218 return { float(v.x()), float(v.y()), float(v.z()) };
219}

Referenced by cgal_to_indexed_triangle_set().

Here is the caller graph for this function:

◆ triangle_mesh_to_cgal() [1/5]

CGALMeshPtr Slic3r::MeshBoolean::cgal::triangle_mesh_to_cgal ( const indexed_triangle_set & M)
inline
46{
47 return triangle_mesh_to_cgal(M.vertices, M.indices);
48}

References triangle_mesh_to_cgal().

Here is the call graph for this function:

◆ triangle_mesh_to_cgal() [2/5]

CGALMeshPtr Slic3r::MeshBoolean::cgal::triangle_mesh_to_cgal ( const std::vector< stl_vertex > & V,
const std::vector< stl_triangle_vertex_indices > & F )
271{
272 std::unique_ptr<CGALMesh, CGALMeshDeleter> out(new CGALMesh{});
273 triangle_mesh_to_cgal(V, F, out->m);
274 return out;
275}
@ F
Definition libslic3r.h:145

References Slic3r::F, and triangle_mesh_to_cgal().

Here is the call graph for this function:

◆ triangle_mesh_to_cgal() [3/5]

template<class _Mesh>
void Slic3r::MeshBoolean::cgal::triangle_mesh_to_cgal ( const std::vector< stl_vertex > & V,
const std::vector< stl_triangle_vertex_indices > & F,
_Mesh & out )
200{
201 if (F.empty()) return;
202
203 size_t vertices_count = V.size();
204 size_t edges_count = (F.size()* 3) / 2;
205 size_t faces_count = F.size();
206 out.reserve(vertices_count, edges_count, faces_count);
207
208 for (auto &v : V)
209 out.add_vertex(typename _Mesh::Point{v.x(), v.y(), v.z()});
210
211 using VI = typename _Mesh::Vertex_index;
212 for (auto &f : F)
213 out.add_face(VI(f(0)), VI(f(1)), VI(f(2)));
214}
static double f(double x, double z_sin, double z_cos, bool vertical, bool flip)
Definition FillGyroid.cpp:124

References Slic3r::F, and Slic3r::f().

Here is the call graph for this function:

◆ triangle_mesh_to_cgal() [4/5]

CGALMeshPtr Slic3r::MeshBoolean::cgal::triangle_mesh_to_cgal ( const TriangleMesh & M)
inline
50{
51 return triangle_mesh_to_cgal(M.its);
52}

References Slic3r::TriangleMesh::its, and triangle_mesh_to_cgal().

Here is the call graph for this function:

◆ triangle_mesh_to_cgal() [5/5]

template<class _Mesh>
void Slic3r::MeshBoolean::cgal::triangle_mesh_to_cgal ( const TriangleMesh & M,
_Mesh & out )
168{
169 using Index3 = std::array<size_t, 3>;
170
171 if (M.empty()) return;
172
173 std::vector<typename _Mesh::Point> points;
174 std::vector<Index3> indices;
175 points.reserve(M.its.vertices.size());
176 indices.reserve(M.its.indices.size());
177 for (auto& v : M.its.vertices) points.emplace_back(v.x(), v.y(), v.z());
178 for (auto& _f : M.its.indices) {
179 auto f = _f.cast<size_t>();
180 indices.emplace_back(Index3{ f(0), f(1), f(2) });
181 }
182
183 CGALProc::orient_polygon_soup(points, indices);
184 CGALProc::polygon_soup_to_polygon_mesh(points, indices, out);
185
186 // Number the faces because 'orient_to_bound_a_volume' needs a face <--> index map
187 unsigned index = 0;
188 for (auto face : out.faces()) face = CGAL::SM_Face_index(index++);
189
190 if (CGAL::is_closed(out))
191 CGALProc::orient_to_bound_a_volume(out);
192 else
193 throw Slic3r::RuntimeError("Mesh not watertight");
194}
bool empty() const
Definition TriangleMesh.hpp:146

References Slic3r::TriangleMesh::empty(), Slic3r::f(), and Slic3r::TriangleMesh::its.

Referenced by _mesh_boolean_do(), _mesh_boolean_do(), Slic3r::csg::check_csgmesh_booleans(), does_self_intersect(), Slic3r::csg::get_cgalmesh(), merge(), parameterize_lscm(), Slic3r::csg::perform_csgmesh_booleans(), Slic3r::csg::perform_csgmesh_booleans_cgal(), remesh_isotropic(), segment(), triangle_mesh_to_cgal(), triangle_mesh_to_cgal(), and triangle_mesh_to_cgal().

Here is the call graph for this function:
Here is the caller graph for this function: