FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
cgal.cpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
8#include <iostream>
9#include <fstream>
10#include <algorithm>
11
12#ifdef FEAT_HAVE_CGAL
13
14#define CGAL_HEADER_ONLY 1
15
16#ifdef FEAT_COMPILER_MICROSOFT
17#pragma warning(disable: 4244)
18#endif // FEAT_COMPILER_MICROSOFT
19
20FEAT_DISABLE_WARNINGS
21#define CGAL_NO_DEPRECATION_WARNINGS 1
22#include <CGAL/Simple_cartesian.h>
23#include <CGAL/AABB_tree.h>
24#include <CGAL/AABB_traits.h> // deprecated in CGAL 6.x
25#include <CGAL/Surface_mesh.h>
26#include <CGAL/AABB_face_graph_triangle_primitive.h>
27#include <CGAL/algorithm.h>
28#include <CGAL/Side_of_triangle_mesh.h>
29#include <CGAL/Aff_transformation_3.h>
30#include <CGAL/Polygon_mesh_processing/transform.h>
31#include <CGAL/Polygon_mesh_processing/compute_normal.h>
32#include <CGAL/Polygon_mesh_processing/detect_features.h>
33#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>
34FEAT_RESTORE_WARNINGS
35
36// check if cgal threading support is enabled
37#ifdef FEAT_HAVE_OMP
38#ifndef CGAL_HAS_THREADS
39static_assert(false, "No cgal multithreading support");
40#endif
41
42#ifndef BOOST_HAS_THREADS
43static_assert(false, "Boost has no threads");
44#endif
45#endif
46
47
48#ifdef FEAT_COMPILER_INTEL
49#pragma warning disable 3280
50#pragma warning disable 1224
51#endif //FEAT_COMPILER_INTEL
52
53#ifdef FEAT_COMPILER_MICROSOFT
54#pragma warning(default: 4244)
55#endif // FEAT_COMPILER_MICROSOFT
56
57#undef FEAT_EICKT
58
59#include <kernel/geometry/cgal.hpp>
60
61#ifdef FEAT_HAVE_HALFMATH
62#include <kernel/util/half.hpp>
63#endif
64
65namespace FEAT::Geometry
66{
67 template<typename DT_>
68 struct CGALTypeWrapper
69 {
70 typedef DT_ CGALDT_;
71 typedef typename CGAL::Simple_cartesian<DT_> K;
72 typedef typename K::Point_3 Point_;
73 typedef typename K::Segment_3 Segment_;
74 typedef typename CGAL::Surface_mesh<Point_> Polyhedron_;
75 typedef typename CGAL::AABB_face_graph_triangle_primitive<Polyhedron_> Primitive_;
76 typedef typename CGAL::AABB_traits<K, Primitive_> Traits_;
77 typedef typename CGAL::AABB_tree<Traits_> Tree_;
78 typedef typename CGAL::Side_of_triangle_mesh<Polyhedron_, K> Point_inside_;
79 typedef typename CGAL::Aff_transformation_3<K> Transformation_;
80 typedef typename CGAL::AABB_traits<K, Primitive_>::Point_and_primitive_id Point_and_primitive_id_;
81 typedef std::optional< typename Tree_::template Intersection_and_primitive_id<Segment_>::Type > Segment_intersection_;
82 };
83
84 template<typename DT_>
85 struct CGALWrapperData
86 {
87 typedef CGALTypeWrapper<DT_> TW_;
88 typename TW_::Polyhedron_ * _polyhedron;
89 typename TW_::Tree_ * _tree;
90 typename TW_::Point_inside_ * _inside_tester;
91
92 CGALWrapperData() :
93 _polyhedron(nullptr),
94 _tree(nullptr),
95 _inside_tester(nullptr)
96 {
97 }
98
99 CGALWrapperData(const CGALWrapperData&) = delete;
100 CGALWrapperData& operator=(const CGALWrapperData&) = delete;
101
102 void swap(CGALWrapperData& other)
103 {
104 std::swap(this->_polyhedron, other._polyhedron);
105 std::swap(this->_tree, other._tree);
106 std::swap(this->_inside_tester, other._inside_tester);
107 }
108
109 CGALWrapperData(CGALWrapperData&& other) noexcept
110 : _polyhedron(nullptr), _tree(nullptr), _inside_tester(nullptr)
111 {
112 this->swap(other);
113 }
114
115 CGALWrapperData& operator=(CGALWrapperData&& other) noexcept
116 {
117 this->swap(other);
118 return *this;
119 }
120
121
122 ~CGALWrapperData()
123 {
124 if(_inside_tester)
125 delete _inside_tester;
126 if(_tree)
127 delete _tree;
128 if(_polyhedron)
129 delete _polyhedron;
130 }
131 };
132
133 #ifdef FEAT_HAVE_QUADMATH
134 template<>
135 struct CGALTypeWrapper<__float128>
136 {
137 typedef double CGALDT_;
138 typedef typename CGAL::Simple_cartesian<double> K;
139 typedef typename K::Point_3 Point_;
140 typedef typename K::Segment_3 Segment_;
141 typedef typename CGAL::Surface_mesh<Point_> Polyhedron_;
142 typedef typename CGAL::AABB_face_graph_triangle_primitive<Polyhedron_> Primitive_;
143 typedef typename CGAL::AABB_traits<K, Primitive_> Traits_;
144 typedef typename CGAL::AABB_tree<Traits_> Tree_;
145 typedef typename CGAL::Side_of_triangle_mesh<Polyhedron_, K> Point_inside_;
146 typedef typename CGAL::Aff_transformation_3<K> Transformation_;
147 typedef typename CGAL::AABB_traits<K, Primitive_>::Point_and_primitive_id Point_and_primitive_id_;
148 typedef std::optional< typename Tree_::template Intersection_and_primitive_id<Segment_>::Type > Segment_intersection_;
149 };
150 #endif
151
152 template<typename DT_>
153 using PointTypeAlias = typename FEAT::Geometry::template CGALWrapper<DT_>::PointType;
154
155 template<typename DT_>
156 using TransformMatrixAlias = typename FEAT::Geometry::template CGALWrapper<DT_>::TransformMatrix;
157
158 template<typename DT_>
159 CGALWrapper<DT_>::CGALWrapper(std::istream & file, CGALFileMode file_mode) :
160 _cgal_data(nullptr)
161 {
162 _parse_mesh(file, file_mode);
163 }
164
165 template<typename DT_>
166 CGALWrapper<DT_>::CGALWrapper(const String & filename, CGALFileMode file_mode) :
167 _cgal_data(nullptr)
168 {
169 std::ifstream file(filename.c_str());
170 XASSERTM(file.is_open(), "CGALWrapper: file read error: " + filename + " !");
171 _parse_mesh(file, file_mode);
172 file.close();
173 }
174
175 template <typename DT_>
176 static CGALWrapperData<DT_> *from_topology(
177 const std::vector<typename CGALWrapper<DT_>::PointType> &vertices,
178 const std::vector<std::array<Index, 3>> &faces)
179 {
180 using VertexType = typename CGALTypeWrapper<DT_>::Point_;
181 using SurfaceMesh = typename CGALTypeWrapper<DT_>::Polyhedron_;
182 using VertexIndex = typename SurfaceMesh::Vertex_index;
183 using FaceIndex = typename SurfaceMesh::Face_index;
184
185 auto* result = new CGALWrapperData<DT_>;
186 result->_polyhedron = new SurfaceMesh;
187
188 // Add vertices to surface mesh
189 std::vector<VertexIndex> vs(vertices.size());
190 for(Index i(0); i < vertices.size(); i++)
191 {
192 VertexType vertex(vertices[i][0], vertices[i][1], vertices[i][2]);
193 vs[i] = result->_polyhedron->add_vertex(vertex);
194 }
195
196 // Add faces to surface mesh
197 for(const std::array<Index, 3>& face : faces)
198 {
199 FaceIndex i = result->_polyhedron->add_face(vs[face[0]], vs[face[1]], vs[face[2]]);
200
201 XASSERTM(i != SurfaceMesh::null_face(), "Failed to add face to surface mesh!");
202 }
203
204 return result;
205 }
206
207 template<typename DT_>
208 CGALWrapper<DT_>::CGALWrapper(
209 const std::vector<typename CGALWrapper<DT_>::PointType> &vertices,
210 const std::vector<std::array<Index, 3>> &faces) :
211 _cgal_data(from_topology<DT_>(vertices, faces))
212 {
213 _init_wrapper();
214 }
215
216 template<typename DT_>
217 CGALWrapper<DT_>::CGALWrapper::~CGALWrapper()
218 {
219 if(_cgal_data)
220 delete (CGALWrapperData<DT_>*)_cgal_data;
221 }
222
223
224 template<typename DT_>
225 bool CGALWrapper<DT_>::point_inside(DT_ x, DT_ y, DT_ z) const
226 {
227 typedef typename CGALTypeWrapper<DT_>::CGALDT_ IDT_;
228 typename CGALTypeWrapper<DT_>::Point_ query{IDT_(x), IDT_(y), IDT_(z)};
229
230 // Determine the side and return true if inside!
231 CGALWrapperData<DT_> * cd = (CGALWrapperData<DT_>*)_cgal_data;
232 return (*(cd->_inside_tester))(query) == CGAL::ON_BOUNDED_SIDE;
233 }
234
235 template<typename DT_>
236 bool CGALWrapper<DT_>::point_not_outside(DT_ x, DT_ y, DT_ z) const
237 {
238 typedef typename CGALTypeWrapper<DT_>::CGALDT_ IDT_;
239 typename CGALTypeWrapper<DT_>::Point_ query{IDT_(x), IDT_(y), IDT_(z)};
240
241 // Determine the side and return true if inside!
242 CGALWrapperData<DT_> * cd = (CGALWrapperData<DT_>*)_cgal_data;
243 CGAL::Bounded_side test_result = (*(cd->_inside_tester))(query);
244 return test_result != CGAL::ON_UNBOUNDED_SIDE;
245 }
246
247 template<typename DT_>
248 DT_ CGALWrapper<DT_>::squared_distance(DT_ x, DT_ y, DT_ z) const
249 {
250 typedef typename CGALTypeWrapper<DT_>::CGALDT_ IDT_;
251 typename CGALTypeWrapper<DT_>::Point_ query{IDT_(x), IDT_(y), IDT_(z)};
252
253 CGALWrapperData<DT_> * cd = (CGALWrapperData<DT_>*)_cgal_data;
254 return DT_(cd->_tree->squared_distance(query));
255 }
256
257 template<typename DT_>
258 DT_ CGALWrapper<DT_>::squared_distance_to_feature(const CGALFeature& f, const PointType& p) const
259 {
260 return (p - closest_point_on_feature(f, p)).norm_euclid_sqr();
261 }
262
263
264 template<typename DT_>
265 typename CGALWrapper<DT_>::PointType CGALWrapper<DT_>::closest_point(const PointType& point) const
266 {
267 return closest_point(point[0], point[1], point[2]);
268 }
269
270 template<typename DT_>
271 typename CGALWrapper<DT_>::PointType CGALWrapper<DT_>::closest_point(DT_ x, DT_ y, DT_ z) const
272 {
273 typedef typename CGALTypeWrapper<DT_>::CGALDT_ IDT_;
274 typename CGALTypeWrapper<DT_>::Point_ query{IDT_(x), IDT_(y), IDT_(z)};
275 CGALWrapperData<DT_> * cd = (CGALWrapperData<DT_>*)_cgal_data;
276 typename CGALTypeWrapper<DT_>::Point_ n_point = cd->_tree->closest_point(query);
277 return PointType{{DT_(n_point[0]), DT_(n_point[1]), DT_(n_point[2])}};
278 }
279
280 template<typename DT_>
281 typename CGALWrapper<DT_>::PointType CGALWrapper<DT_>::closest_point(const PointType& point, PointType& primitive_grad) const
282 {
283 typedef typename CGALTypeWrapper<DT_>::CGALDT_ IDT_;
284 typename CGALTypeWrapper<DT_>::Point_ query{IDT_(point[0]), IDT_(point[1]), IDT_(point[2])};
285 CGALWrapperData<DT_> * cd = (CGALWrapperData<DT_>*)_cgal_data;
286 const typename CGALTypeWrapper<DT_>::Point_and_primitive_id_& cl_p_query = cd->_tree->closest_point_and_primitive(query);
287 typename CGALTypeWrapper<DT_>::Polyhedron_::Face_index f = cl_p_query.second;
288 auto v = CGAL::Polygon_mesh_processing::compute_face_normal(f,*(cd->_polyhedron));
289 for(int i = 0; i < 3; ++i)
290 primitive_grad[i] = DT_(v[i]);
291 return PointType{{DT_(cl_p_query.first[0]), DT_(cl_p_query.first[1]), DT_(cl_p_query.first[2])}};
292 }
293
294 template<typename DT_>
295 typename CGALWrapper<DT_>::PointType
296 CGALWrapper<DT_>::closest_point_on_feature(const CGALFeature& f, const PointType& query) const
297 {
298 using PolyhedronType = typename CGALTypeWrapper<DT_>::Polyhedron_;
299 using VertexIndex = typename PolyhedronType::Vertex_index;
300
301 CGALWrapperData<DT_>* cd = (CGALWrapperData<DT_>*)_cgal_data;
302 PolyhedronType* poly = cd->_polyhedron;
303
304 const auto to_feat_point = [](const auto& p)
305 {
306 return PointType{p.x(), p.y(), p.z()};
307 };
308
309 PointType closest = to_feat_point(poly->point(VertexIndex(f[0])));
310 DT_ distance_to_closest = (query - closest).norm_euclid_sqr();
311
312 const auto closest_point_on_segment = [&](PointType start, PointType end, PointType q)
313 {
314 PointType segment = end - start;
315 PointType segment_dir = segment.normalize();
316
317 // Orthogonal projection of (query - start) onto the segment
318 DT_ coefficient = Math::clamp(dot(segment_dir, q - start), DT_(0.0), DT_(1.0));
319
320 return start + coefficient * segment_dir;
321 };
322
323 for(std::size_t i(0); i < f.size() - 1; i++)
324 {
325 PointType segment_start = to_feat_point(poly->point(VertexIndex(f[i])));
326 PointType segment_end = to_feat_point(poly->point(VertexIndex(f[i + 1])));
327
328 PointType closest_on_segment = closest_point_on_segment(segment_start, segment_end, query);
329
330 DT_ distance_to_segment = (query - closest_on_segment).norm_euclid_sqr();
331 if(distance_to_segment < distance_to_closest)
332 {
333 closest = closest_on_segment;
334 distance_to_closest = distance_to_segment;
335 }
336 }
337
338 return closest;
339 }
340
341 template<typename DT_>
342 typename CGALWrapper<DT_>::PointType CGALWrapper<DT_>::point(std::uint32_t idx) const
343 {
344 using PolyhedronType = typename CGALTypeWrapper<DT_>::Polyhedron_;
345 using VertexIndex = typename PolyhedronType::Vertex_index;
346
347 const auto to_feat_point = [](const auto& p)
348 {
349 return PointType{p.x(), p.y(), p.z()};
350 };
351
352 CGALWrapperData<DT_>* cd = (CGALWrapperData<DT_>*)_cgal_data;
353
354 return to_feat_point(cd->_polyhedron->point(VertexIndex(idx)));
355 }
356
357 template<typename DT_>
358 void CGALWrapper<DT_>::_parse_mesh(std::istream & file, CGALFileMode file_mode)
359 {
360 delete (CGALWrapperData<DT_>*)_cgal_data;
361
362 _cgal_data = new CGALWrapperData<DT_>;
363 CGALWrapperData<DT_> * cd = (CGALWrapperData<DT_>*)_cgal_data;
364
365 cd->_polyhedron = new typename CGALTypeWrapper<DT_>::Polyhedron_;
366
367 bool status(false);
368 switch(file_mode)
369 {
370 case CGALFileMode::fm_off:
371 status = CGAL::IO::read_OFF(file, *(cd->_polyhedron));
372 XASSERTM(status == true, "CGAL::IO::read_OFF: read/parse error !");
373 break;
374 case CGALFileMode::fm_obj:
375 status = CGAL::IO::read_OBJ(file, *(cd->_polyhedron));
376 XASSERTM(status == true, "CGAL::IO::read_OBJ: read/parse error !");
377 break;
378 default:
379 XASSERTM(false, "CGAL FileMode not supported!");
380 }
381
382 _init_wrapper();
383
384 }
385
386 template<typename DT_>
387 CGALFeatureNetwork CGALWrapper<DT_>::detect_features(DT_ critical_angle)
388 {
389 using PolyhedronType = typename CGALTypeWrapper<DT_>::Polyhedron_;
390 using VertexIndex = typename PolyhedronType::Vertex_index;
391 using EdgeIndex = typename PolyhedronType::Edge_index;
392 using HalfedgeIndex = typename PolyhedronType::Halfedge_index;
393 using EdgeIsSharpMapType = typename PolyhedronType::template Property_map<EdgeIndex, bool>;
394
395 CGALFeatureNetwork result;
396
397 auto* cd = static_cast<CGALWrapperData<DT_>*>(_cgal_data);
398 PolyhedronType* poly = cd->_polyhedron;
399
401 // Detect sharp edges
403
404 std::pair<EdgeIsSharpMapType, bool> map = poly->template add_property_map<EdgeIndex, bool>("e:is_sharp");
405
406 if(map.second)
407 {
408 // Property was newly created. Fill it with proper data.
409 CGAL::Polygon_mesh_processing::detect_sharp_edges(*poly, critical_angle, map.first);
410 }
411
413 // Find feature starting points
415
416 std::vector<VertexIndex> seeds;
417
418 for(VertexIndex v : poly->vertices())
419 {
420 Index incident_feature_edges(0);
421
422 for(HalfedgeIndex he : poly->halfedges_around_target(poly->halfedge(v)))
423 {
424 EdgeIndex edge = poly->edge(he);
425 if(map.first[edge])
426 {
427 incident_feature_edges++;
428 }
429 }
430
431 // At least one incident feature that is not just a feature passing through this vertex
432 if(incident_feature_edges != 0 && incident_feature_edges != 2)
433 {
434 seeds.push_back(v);
435 }
436 }
437
439 // Flood fill for feature lines
441
442 std::vector<bool> visited(poly->number_of_edges(), false);
443 const auto flood_feature = [&](VertexIndex v, HalfedgeIndex h)
444 {
445 CGALFeature feature;
446 feature.push_back(static_cast<std::uint32_t>(v));
447 VertexIndex current = poly->source(h);
448 feature.push_back(static_cast<std::uint32_t>(current));
449
450 visited[poly->edge(h)] = true;
451
452 while(current != v && std::find(seeds.begin(), seeds.end(), current) == seeds.end())
453 {
454 for(HalfedgeIndex he : poly->halfedges_around_target(poly->halfedge(current)))
455 {
456 EdgeIndex e = poly->edge(he);
457 if(!map.first[e] || visited[e])
458 {
459 // Edge is either not sharp or has already been visited.
460 // Either way it is not the way forward
461 continue;
462 }
463
464 current = poly->source(he);
465 feature.push_back(static_cast<std::uint32_t>(current));
466 visited[e] = true;
467 }
468 }
469
470 return feature;
471 };
472
474 // Fill in features
476
477 for(VertexIndex seed : seeds)
478 {
479 for(HalfedgeIndex he : poly->halfedges_around_target(poly->halfedge(seed)))
480 {
481 EdgeIndex e = poly->edge(he);
482 if(map.first[e] && !visited[e])
483 {
484 // Edge is sharp and unvisited. It must be the start of a new feature.
485 result.push_back(flood_feature(seed, he));
486 }
487 }
488 }
489
490 // On isolated circular features, all vertices have exactly two incident sharp edges.
491 // They thus contain to seed vertices and have to be handled specially.
492
493 for(EdgeIndex e : poly->edges())
494 {
495 if(map.first[e] && !visited[e])
496 {
497 HalfedgeIndex he = poly->halfedge(e);
498 VertexIndex start = poly->target(he);
499
500 result.push_back(flood_feature(start, he));
501 }
502 }
503
504 return result;
505 }
506
507 template<typename DT_>
508 void CGALWrapper<DT_>::transform(const TransformMatrix& scale_rot, const PointType& translation, DT_ scale)
509 {
510 typedef typename CGALTypeWrapper<DT_>::CGALDT_ IDT_;
511 CGALWrapperData<DT_> * cd = (CGALWrapperData<DT_>*)_cgal_data;
512 //delete tree and _inside_tester
513 _delete_tree();
514 //build affine transformation
515 typename CGALTypeWrapper<DT_>::Transformation_ trafo_mat{(IDT_)(scale_rot[0][0]), (IDT_)(scale_rot[0][1]), (IDT_)(scale_rot[0][2]), (IDT_)(translation[0]),
516 (IDT_)(scale_rot[1][0]), (IDT_)(scale_rot[1][1]), (IDT_)(scale_rot[1][2]), (IDT_)(translation[1]),
517 (IDT_)(scale_rot[2][0]), (IDT_)(scale_rot[2][1]), (IDT_)(scale_rot[2][2]), (IDT_)(translation[2]),
518 IDT_(scale)};
519 //apply affine transformation on polyhedron
520 CGAL::Polygon_mesh_processing::transform(trafo_mat, *(cd->_polyhedron));
521 //create new trees
522 _init_wrapper();
523
524
525 }
526
527 template<typename DT_>
528 std::size_t CGALWrapper<DT_>::bytes() const
529 {
530 auto* cd = static_cast<CGALWrapperData<DT_>*>(_cgal_data);
531
532 // CGALs surface mesh uses std::uint32_t to store it indices
533 constexpr std::size_t index_size = sizeof(std::uint32_t);
534
535 // CGAL stores an halfedge-index, the vertex coordinates, and a removed flag for each vertex
536 constexpr std::size_t bytes_per_vertex = index_size + sizeof(typename CGALTypeWrapper<DT_>::Point_) + sizeof(bool);
537
538 // CGAL stores 4 indices per halfedge
539 constexpr std::size_t bytes_per_halfedge = 4 * index_size;
540
541 // CGAL stores just the removed flag for edges
542 constexpr std::size_t bytes_per_edge = sizeof(bool);
543
544 // CGAL stores 1 index per face and the removed flag
545 constexpr std::size_t bytes_per_face = index_size + sizeof(bool);
546
547 std::size_t result = 0;
548
549 if(cd->_polyhedron)
550 {
551 result += cd->_polyhedron->number_of_vertices() * bytes_per_vertex +
552 cd->_polyhedron->number_of_halfedges() * bytes_per_halfedge +
553 cd->_polyhedron->number_of_edges() * bytes_per_edge +
554 cd->_polyhedron->number_of_faces() * bytes_per_face;
555 }
556
557 if(cd->_tree != nullptr)
558 {
559 // See https://doc.cgal.org/latest/AABB_tree/index.html, section 4.2 Memory
560 constexpr std::size_t bytes_per_primitive = 150;
561
562 result += cd->_tree->size() * bytes_per_primitive;
563 }
564
565 // Inside tester stores no meaningful own data
566
567 return result;
568 }
569
570 template<typename DT_>
571 void CGALWrapper<DT_>::_delete_tree()
572 {
573 CGALWrapperData<DT_> * cd = (CGALWrapperData<DT_>*)_cgal_data;
574 XASSERTM(cd->_polyhedron != nullptr, "ERROR: Polyhedron is not initialized!");
575 delete cd->_inside_tester;
576 cd->_inside_tester = nullptr;
577 delete cd->_tree;
578 cd->_tree = nullptr;
579 }
580
581 template<typename DT_>
582 void CGALWrapper<DT_>::_init_wrapper()
583 {
584 CGALWrapperData<DT_> * cd = (CGALWrapperData<DT_>*)_cgal_data;
585 XASSERTM(cd->_polyhedron != nullptr, "ERROR: Polyhedron is not initialized!");
586 XASSERTM(cd->_tree == nullptr && cd->_inside_tester == nullptr, "ERROR: Tree or Inside Tester are already initialized");
587
588 // Construct AABB tree with a KdTree
589 cd->_tree = new typename CGALTypeWrapper<DT_>::Tree_(faces(*(cd->_polyhedron)).first, faces(*(cd->_polyhedron)).second, *(cd->_polyhedron));
590 cd->_tree->accelerate_distance_queries();
591 // Initialize the point-in-polyhedron tester
592 cd->_inside_tester = new typename CGALTypeWrapper<DT_>::Point_inside_(*(cd->_tree));
593 }
594
595 template<typename DT_>
596 CGALWrapper<DT_>::CGALWrapper(CGALWrapper<DT_>&& other) noexcept
597 : _cgal_data(nullptr)
598 {
599 std::swap(this->_cgal_data, other._cgal_data);
600 }
601
602 template<typename DT_>
603 CGALWrapper<DT_>& CGALWrapper<DT_>::operator=(CGALWrapper<DT_>&& other) noexcept
604 {
605 std::swap(this->_cgal_data, other._cgal_data);
606 return *this;
607 }
608
609 template<typename DT_>
611 {
612 typename CGALTypeWrapper<DT_>::Point_ t(a[0], a[1], a[2]), z(b[0], b[1], b[2]);
613 typename CGALTypeWrapper<DT_>::Segment_ seg(t,z);
614 return static_cast<CGALWrapperData<DT_>*>(this->_cgal_data)->_tree->do_intersect(seg);
615 }
616
617} // namespace Geometry
618
619
620// explicitly instantiate templates for all sensible datatype
621
624#ifdef FEAT_HAVE_HALFMATH
626#endif
627#ifdef FEAT_HAVE_QUADMATH
629#endif
630
631#elif !defined(DOXYGEN)
632
633// Dummy class instance to silence ipo linker optimization warnings about empty libgeometry
634class ipo_foobar_geometry_cgal
635{
636public:
637 int i;
638 ipo_foobar_geometry_cgal() :
639 i(0)
640 {
641 (void)i;
642 }
643} ipo_barfoo_geometry_cgal;
644
645#endif // FEAT_HAVE_CGAL
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
FEAT Kernel base header.
Wrapper for the CGAL Library.
Definition: cgal.hpp:57
bool intersects_line(const PointType &a, const PointType &b) const
tests whether the cgal mesh intersects with the line segment a->b
CGALWrapper(const CGALWrapper &)=delete
rule of five
Tiny Vector class template.
Geometry namespace.
std::vector< CGALFeature > CGALFeatureNetwork
A FeatureNetwork is a list of features.
Definition: cgal.hpp:43
std::vector< std::uint32_t > CGALFeature
A feature is an edge-path on a surface mesh, stored as a list of vertex indices.
Definition: cgal.hpp:36
@ other
generic/other permutation strategy
CUDA_HOST_DEVICE T_ dot(const T_ &a, const T_ &b)
Computes the dot-product of two scalars.
std::uint64_t Index
Index data type.