23#ifndef VCL_ALGORITHMS_MESH_CONVEX_HULL_H
24#define VCL_ALGORITHMS_MESH_CONVEX_HULL_H
26#include <vclib/algorithms/mesh/create/tetrahedron.h>
27#include <vclib/algorithms/mesh/update/topology.h>
29#include <vclib/algorithms/core.h>
30#include <vclib/mesh.h>
31#include <vclib/space/complex.h>
46void firstTetOptimization(R&& points)
48 using PointType = std::ranges::range_value_t<R>;
49 using Iterator = std::ranges::iterator_t<R>;
53 std::array<std::pair<double, Iterator>, 6> distances;
56 for (uint i = 0; i < 6; ++i) {
57 auto it = std::ranges::begin(points);
58 const auto& boxCorner = i < 3 ? box.min() : box.max();
60 std::make_pair(std::abs(boxCorner(i % 3) - (*it)(i % 3)), it);
61 for (++it; it != std::ranges::end(points); ++it) {
62 double d = std::abs(boxCorner(i % 3) - (*it)(i % 3));
63 if (d < distances[i].first) {
64 distances[i] = std::make_pair(d, it);
70 std::sort(distances.begin(), distances.end(), [](
auto& a,
auto& b) {
71 return a.first < b.first;
75 for (uint i = 0; i < 6 && i < points.size(); ++i) {
76 std::iter_swap(std::ranges::begin(points) + i, distances[i].second);
90void shufflePoints(R&& points, std::optional<uint> seed = std::nullopt)
91 requires Point3Concept<std::ranges::range_value_t<R>>
95 firstTetOptimization(points);
97 auto itP0 = std::ranges::begin(points);
98 auto itP = std::next(itP0);
101 while (itP != std::ranges::end(points) && *itP0 == *itP) {
102 itP = std::next(itP);
104 if (itP == std::ranges::end(points)) {
105 throw std::runtime_error(
"All points are coincident.");
107 auto itP1 = std::next(itP0);
108 std::iter_swap(itP, itP1);
110 itP = std::next(itP);
113 while (itP != std::ranges::end(points) &&
115 itP = std::next(itP);
117 if (itP == std::ranges::end(points)) {
118 throw std::runtime_error(
"All points are collinear.");
120 auto itP2 = std::next(itP1);
121 std::iter_swap(itP, itP2);
123 itP = std::next(itP);
125 auto rEnd = std::ranges::end(points);
128 itP = std::next(itP);
131 throw std::runtime_error(
"All points are coplanar.");
133 auto itP3 = std::next(itP2);
134 std::iter_swap(itP, itP3);
137template<FaceMeshConcept MeshType, Po
int3Concept Po
intType>
138MeshType makeTetrahedron(
144 using FaceType = MeshType::FaceType;
149 result = createTetrahedron<MeshType>(p0, p2, p1, p3);
152 result = createTetrahedron<MeshType>(p0, p1, p2, p3);
155 if constexpr (face::HasOptionalAdjacentFaces<FaceType>) {
156 result.enablePerFaceAdjacentFaces();
159 updatePerFaceAdjacentFaces(result);
164template<FaceMeshConcept MeshType, Range R>
165auto initConflictGraph(
const MeshType& mesh, R&& points)
166 requires Point3Concept<std::ranges::range_value_t<R>>
168 using PointType = std::ranges::range_value_t<R>;
169 using MPointType = MeshType::VertexType::PositionType;
170 using FaceType = MeshType::FaceType;
171 using GraphType = BipartiteGraph<PointType, uint>;
177 for (
const auto& face : mesh.
faces()) {
178 graph.addRightNode(face.index());
181 for (
const auto& point : points) {
183 for (
const auto& face : mesh.
faces()) {
186 graph.addLeftNode(point);
189 graph.addArc(point, face.index());
210template<FaceConcept FaceType, VertexConcept VertexType>
211std::vector<std::pair<uint, uint>> horizonFaces(
212 const std::set<const FaceType*>& visibleFaces,
213 std::set<const VertexType*>& horizonVertices)
215 std::vector<std::pair<uint, uint>> horizon;
217 const FaceType* firstFace =
nullptr;
219 const FaceType* currentFace =
nullptr;
224 for (
auto it = visibleFaces.begin(); it != visibleFaces.end() && !found;
227 for (
const FaceType* adjFace : (*it)->
adjFaces()) {
229 if (visibleFaces.find(adjFace) == visibleFaces.end()) {
232 currentFace = firstFace;
233 currentEdge = firstEdge;
242 MeshPos<FaceType> pos(currentFace, currentEdge);
244 horizonVertices.insert(pos.vertex());
246 while (visibleFaces.find(pos.face()) != visibleFaces.end()) {
247 pos.nextEdgeAdjacentToV();
249 auto p = std::make_pair(pos.face()->index(), pos.edge());
250 horizon.push_back(p);
253 currentFace = pos.face();
254 currentEdge = pos.edge();
255 }
while (currentFace != firstFace || currentEdge != firstEdge);
260template<Po
int3Concept Po
intType, FaceMeshConcept MeshType>
261auto potentialConflictPoints(
262 const BipartiteGraph<PointType, uint>& conflictGraph,
263 const PointType& currentPoint,
267 using FaceType = MeshType::FaceType;
269 std::vector<std::set<PointType>> potentialConflictPoints(horizon.size());
272 for (
const auto& [faceIndex, edgeIndex] : horizon) {
273 for (
const auto& p : conflictGraph.adjacentRightNodes(faceIndex)) {
274 potentialConflictPoints[i].insert(p);
277 const FaceType& face =
convexHull.face(faceIndex);
279 uint adjFaceIndex = face.adjFace(edgeIndex)->index();
281 for (
const auto& p : conflictGraph.adjacentRightNodes(adjFaceIndex)) {
282 potentialConflictPoints[i].insert(p);
285 potentialConflictPoints[i].erase(currentPoint);
290 return potentialConflictPoints;
294 FaceMeshConcept MeshType,
295 FaceConcept FaceType,
296 VertexConcept VertexType>
297void deleteVisibleFaces(
299 const std::set<const FaceType*>& visibleFaces,
300 const std::set<const VertexType*>& horizonVertices)
302 std::set<const VertexType*> verticesToDelete;
304 for (
const FaceType* face : visibleFaces) {
305 for (
const VertexType* vertex : face->
vertices()) {
306 if (horizonVertices.find(vertex) == horizonVertices.end()) {
307 verticesToDelete.insert(vertex);
313 for (
const VertexType* vertex : verticesToDelete) {
318template<Po
int3Concept Po
intType, FaceMeshConcept MeshType>
319std::vector<uint> addNewFaces(
321 const PointType& currentPoint,
322 const std::vector<std::pair<uint, uint>>& horizon)
324 using VertexType = MeshType::VertexType;
325 using FaceType = MeshType::FaceType;
327 std::vector<uint> newFaces;
329 newFaces.reserve(horizon.size());
336 for (
const auto& [faceIndex, edgeIndex] : horizon) {
337 uint v1 =
convexHull.face(faceIndex).vertexIndexMod(edgeIndex + 1);
338 uint v2 =
convexHull.face(faceIndex).vertexIndex(edgeIndex);
341 newFaces.push_back(f);
352 convexHull.face(faceIndex).setAdjFace(edgeIndex, f);
357 convexHull.face(firstFace).setAdjFace(0u, lastFace);
358 convexHull.face(lastFace).setAdjFace(2u, firstFace);
363template<Po
int3Concept Po
intType, FaceMeshConcept MeshType>
364void updateNewConflicts(
365 BipartiteGraph<PointType, uint>& conflictGraph,
367 const std::vector<uint>& newFaces,
368 const std::vector<std::set<PointType>>& potentialConflictPoints)
370 using FaceType = MeshType::FaceType;
372 for (uint i = 0; i < newFaces.size(); ++i) {
373 conflictGraph.addRightNode(newFaces[i]);
375 const FaceType& face =
convexHull.face(newFaces[i]);
377 for (
const auto& p : potentialConflictPoints[i]) {
379 conflictGraph.addArc(p, newFaces[i]);
399template<FaceMeshConcept MeshType, Range R, LoggerConcept LogType = NullLogger>
402 std::optional<uint>
seed = std::nullopt,
406 using PointType = std::ranges::range_value_t<R>;
407 using VertexType = MeshType::VertexType;
408 using FaceType = MeshType::FaceType;
412 "MeshType must have per-face adjacent faces.");
414 log.log(0,
"Shuffling points...");
417 std::ranges::begin(points), std::ranges::end(points));
421 log.log(0,
"Making first tetrahedron...");
423 auto result = detail::makeTetrahedron<MeshType>(
430 log.log(0,
"Computing convex hull...");
453 auto potentialConflictPoints = detail::potentialConflictPoints(
471 detail::updateNewConflicts(
482 log.log(100,
"Convex hull computed.");
497template<FaceMeshConcept MeshType, Range R, LoggerConcept LogType = NullLogger>
A class representing a box in N-dimensional space.
Definition box.h:46
PointT size() const
Computes the size of the box.
Definition box.h:267
A concept representing a 3D Point.
Definition point.h:872
Definition face_components.h:73
bool arePointsCollinear(const PointType &p0, const PointType &p1, const PointType &p2)
Checks if 3 points are collinear.
Definition visibility.h:88
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:85
bool arePointsCoplanar(const PointType &p0, const PointType &p1, const PointType &p2, const PointType &p3)
Checks if 4 points are coplanar.
Definition visibility.h:110
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:132
NullLogger nullLogger
The nullLogger object is an object of type NullLogger that is used as default argument in the functio...
Definition null_logger.h:123
void shuffle(R &&range, std::optional< uint > seed=std::nullopt)
Shuffle the elements of a range.
Definition random.h:71
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
auto boundingBox(const PointType &p)
Compute the bounding box of a single point.
Definition bounding_box.h:59
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
constexpr detail::FacesView faces
A view that allows to iterate overt the Face elements of an object.
Definition face.h:84
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:92