23#ifndef VCL_ALGORITHMS_MESH_CONVEX_HULL_H
24#define VCL_ALGORITHMS_MESH_CONVEX_HULL_H
26#include <vclib/algorithms/core/bounding_box.h>
27#include <vclib/algorithms/core/box/box3.h>
28#include <vclib/algorithms/core/visibility.h>
29#include <vclib/algorithms/mesh/create/tetrahedron.h>
30#include <vclib/algorithms/mesh/update/topology.h>
31#include <vclib/concepts/mesh.h>
32#include <vclib/mesh/requirements.h>
33#include <vclib/misc/logger.h>
34#include <vclib/misc/parallel.h>
35#include <vclib/misc/shuffle.h>
36#include <vclib/space/complex/graph/bipartite_graph.h>
37#include <vclib/space/complex/mesh_pos.h>
52void firstTetOptimization(R&& points)
54 using PointType = std::ranges::range_value_t<R>;
55 using Iterator = std::ranges::iterator_t<R>;
59 std::array<std::pair<double, Iterator>, 6> distances;
62 for (uint i = 0; i < 6; ++i) {
63 auto it = std::ranges::begin(points);
64 const auto& boxCorner = i < 3 ? box.min() : box.max();
66 std::make_pair(std::abs(boxCorner(i % 3) - (*it)(i % 3)), it);
67 for (++it; it != std::ranges::end(points); ++it) {
68 double d = std::abs(boxCorner(i % 3) - (*it)(i % 3));
69 if (d < distances[i].first) {
70 distances[i] = std::make_pair(d, it);
76 std::sort(distances.begin(), distances.end(), [](
auto& a,
auto& b) {
77 return a.first < b.first;
81 for (uint i = 0; i < 6; ++i) {
82 std::iter_swap(std::ranges::begin(points) + i, distances[i].second);
95void shufflePoints(R&& points,
bool deterministic =
false)
96 requires Point3Concept<std::ranges::range_value_t<R>>
100 firstTetOptimization(points);
102 auto itP0 = std::ranges::begin(points);
103 auto itP1 = std::next(itP0);
104 auto itP2 = std::next(itP1);
105 auto itP3 = std::next(itP2);
106 auto itP = std::next(itP2);
108 auto rEnd = std::ranges::end(points);
111 itP = std::next(itP);
115 throw std::runtime_error(
"All points are coplanar.");
118 std::iter_swap(itP, itP3);
121template<FaceMeshConcept MeshType, Po
int3Concept Po
intType>
122MeshType makeTetrahedron(
128 using FaceType = MeshType::FaceType;
133 result = createTetrahedron<MeshType>(p0, p2, p1, p3);
136 result = createTetrahedron<MeshType>(p0, p1, p2, p3);
139 if constexpr (face::HasOptionalAdjacentFaces<FaceType>) {
140 result.enablePerFaceAdjacentFaces();
143 updatePerFaceAdjacentFaces(result);
148template<FaceMeshConcept MeshType, Range R>
149auto initConflictGraph(
const MeshType& mesh, R&& points)
150 requires Point3Concept<std::ranges::range_value_t<R>>
152 using PointType = std::ranges::range_value_t<R>;
153 using MPointType = MeshType::VertexType::CoordType;
154 using FaceType = MeshType::FaceType;
155 using GraphType = BipartiteGraph<PointType, uint>;
161 for (
const auto& face : mesh.
faces()) {
162 graph.addRightNode(face.index());
165 for (
const auto& point : points) {
167 for (
const auto& face : mesh.
faces()) {
170 graph.addLeftNode(point);
173 graph.addArc(point, face.index());
194template<FaceConcept FaceType, VertexConcept VertexType>
195std::vector<std::pair<uint, uint>> horizonFaces(
196 const std::set<const FaceType*>& visibleFaces,
197 std::set<const VertexType*>& horizonVertices)
199 std::vector<std::pair<uint, uint>> horizon;
201 const FaceType* firstFace =
nullptr;
203 const FaceType* currentFace =
nullptr;
208 for (
auto it = visibleFaces.begin(); it != visibleFaces.end() && !found;
211 for (
const FaceType* adjFace : (*it)->
adjFaces()) {
213 if (visibleFaces.find(adjFace) == visibleFaces.end()) {
216 currentFace = firstFace;
217 currentEdge = firstEdge;
226 MeshPos<FaceType> pos(currentFace, currentEdge);
228 horizonVertices.insert(pos.vertex());
230 while (visibleFaces.find(pos.face()) != visibleFaces.end()) {
231 pos.nextEdgeAdjacentToV();
233 auto p = std::make_pair(pos.face()->index(), pos.edge());
234 horizon.push_back(p);
237 currentFace = pos.face();
238 currentEdge = pos.edge();
239 }
while (currentFace != firstFace || currentEdge != firstEdge);
244template<Po
int3Concept Po
intType, FaceMeshConcept MeshType>
245auto potentialConflictPoints(
246 const BipartiteGraph<PointType, uint>& conflictGraph,
247 const PointType& currentPoint,
251 using FaceType = MeshType::FaceType;
253 std::vector<std::set<PointType>> potentialConflictPoints(horizon.size());
256 for (
const auto& [faceIndex, edgeIndex] : horizon) {
257 for (
const auto& p : conflictGraph.adjacentRightNodes(faceIndex)) {
258 potentialConflictPoints[i].insert(p);
261 const FaceType& face =
convexHull.face(faceIndex);
263 uint adjFaceIndex = face.adjFace(edgeIndex)->index();
265 for (
const auto& p : conflictGraph.adjacentRightNodes(adjFaceIndex)) {
266 potentialConflictPoints[i].insert(p);
269 potentialConflictPoints[i].erase(currentPoint);
274 return potentialConflictPoints;
278 FaceMeshConcept MeshType,
279 FaceConcept FaceType,
280 VertexConcept VertexType>
281void deleteVisibleFaces(
283 const std::set<const FaceType*>& visibleFaces,
284 const std::set<const VertexType*>& horizonVertices)
286 std::set<const VertexType*> verticesToDelete;
288 for (
const FaceType* face : visibleFaces) {
289 for (
const VertexType* vertex : face->
vertices()) {
290 if (horizonVertices.find(vertex) == horizonVertices.end()) {
291 verticesToDelete.insert(vertex);
297 for (
const VertexType* vertex : verticesToDelete) {
302template<Po
int3Concept Po
intType, FaceMeshConcept MeshType>
303std::vector<uint> addNewFaces(
305 const PointType& currentPoint,
306 const std::vector<std::pair<uint, uint>>& horizon)
308 using VertexType = MeshType::VertexType;
309 using FaceType = MeshType::FaceType;
311 std::vector<uint> newFaces;
313 newFaces.reserve(horizon.size());
320 for (
const auto& [faceIndex, edgeIndex] : horizon) {
321 uint v1 =
convexHull.face(faceIndex).vertexIndexMod(edgeIndex + 1);
322 uint v2 =
convexHull.face(faceIndex).vertexIndex(edgeIndex);
325 newFaces.push_back(f);
336 convexHull.face(faceIndex).setAdjFace(edgeIndex, f);
341 convexHull.face(firstFace).setAdjFace(0, lastFace);
342 convexHull.face(lastFace).setAdjFace(2, firstFace);
347template<Po
int3Concept Po
intType, FaceMeshConcept MeshType>
348void updateNewConflicts(
349 BipartiteGraph<PointType, uint>& conflictGraph,
351 const std::vector<uint>& newFaces,
352 const std::vector<std::set<PointType>>& potentialConflictPoints)
354 using FaceType = MeshType::FaceType;
356 for (uint i = 0; i < newFaces.size(); ++i) {
357 conflictGraph.addRightNode(newFaces[i]);
359 const FaceType& face =
convexHull.face(newFaces[i]);
361 for (
const auto& p : potentialConflictPoints[i]) {
363 conflictGraph.addArc(p, newFaces[i]);
382template<FaceMeshConcept MeshType, Range R, LoggerConcept LogType = NullLogger>
389 using PointType = std::ranges::range_value_t<R>;
390 using VertexType = MeshType::VertexType;
391 using FaceType = MeshType::FaceType;
395 "MeshType must have per-face adjacent faces.");
397 log.log(0,
"Shuffling points...");
400 std::ranges::begin(points), std::ranges::end(points));
404 log.log(0,
"Making first tetrahedron...");
406 auto result = detail::makeTetrahedron<MeshType>(
413 log.log(0,
"Computing convex hull...");
415 log.startProgress(
"Processing Points...",
pointsCopy.size() - 4);
436 auto potentialConflictPoints = detail::potentialConflictPoints(
454 detail::updateNewConflicts(
465 log.log(100,
"Convex hull computed.");
480template<FaceMeshConcept MeshType, Range R, LoggerConcept LogType = NullLogger>
A class representing a line segment in n-dimensional space. The class is parameterized by a PointConc...
Definition segment.h:43
Concept for points in three-dimensional space.
Definition point.h:130
bool facePointVisibility(const FaceType &face, const PointType &point)
Checks if a point is visible from a face, i.e., if the point is in the half-space defined by the face...
Definition visibility.h:185
bool trianglePointVisibility(const TriangleType &triangle, const PointType &point)
Checks if a point is visible from a triangle, i.e., if the point is in the half-space defined by the ...
Definition visibility.h:142
bool arePointsCoplanar(const PointType &p1, const PointType &p2, const PointType &p3, const PointType &p4)
Checks if 4 points are coplanar.
Definition visibility.h:120
auto boundingBox(const PointType &p)
Compute the bounding box of a single point.
Definition bounding_box.h:65
auto convexHull(InputIterator first, InputIterator end)
Get the 2D convex hull using Graham scan algorithm on a set of points.
Definition convex_hull.h:137
NullLogger nullLogger
The nullLogger object is an object of type NullLogger that is used as default argument in the functio...
Definition null_logger.h:125
void shuffle(R &&range, bool deterministic=false)
Shuffle the elements of a range.
Definition shuffle.h:43
constexpr uint UINT_NULL
The UINT_NULL value represent a null value of uint that is the maximum value that can be represented ...
Definition base.h:48
constexpr detail::FacesView faces
A view that allows to iterate overt the Face elements of an object.
Definition face.h:52
constexpr detail::AdjFacesView adjFaces
The adjFaces view allows to obtain a view that access to the adjacent faces of the object that has be...
Definition adj_faces.h:65
constexpr detail::VerticesView vertices
A view that allows to iterate over the Vertex elements of an object.
Definition vertex.h:60