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) {
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 itP1 = std::next(itP0);
99 auto itP2 = std::next(itP1);
100 auto itP3 = std::next(itP2);
101 auto itP = std::next(itP2);
103 auto rEnd = std::ranges::end(points);
106 itP = std::next(itP);
110 throw std::runtime_error(
"All points are coplanar.");
113 std::iter_swap(itP, itP3);
116template<FaceMeshConcept MeshType, Po
int3Concept Po
intType>
117MeshType makeTetrahedron(
123 using FaceType = MeshType::FaceType;
128 result = createTetrahedron<MeshType>(p0, p2, p1, p3);
131 result = createTetrahedron<MeshType>(p0, p1, p2, p3);
134 if constexpr (face::HasOptionalAdjacentFaces<FaceType>) {
135 result.enablePerFaceAdjacentFaces();
138 updatePerFaceAdjacentFaces(result);
143template<FaceMeshConcept MeshType, Range R>
144auto initConflictGraph(
const MeshType& mesh, R&& points)
145 requires Point3Concept<std::ranges::range_value_t<R>>
147 using PointType = std::ranges::range_value_t<R>;
148 using MPointType = MeshType::VertexType::PositionType;
149 using FaceType = MeshType::FaceType;
150 using GraphType = BipartiteGraph<PointType, uint>;
156 for (
const auto& face : mesh.
faces()) {
157 graph.addRightNode(face.index());
160 for (
const auto& point : points) {
162 for (
const auto& face : mesh.
faces()) {
165 graph.addLeftNode(point);
168 graph.addArc(point, face.index());
189template<FaceConcept FaceType, VertexConcept VertexType>
190std::vector<std::pair<uint, uint>> horizonFaces(
191 const std::set<const FaceType*>& visibleFaces,
192 std::set<const VertexType*>& horizonVertices)
194 std::vector<std::pair<uint, uint>> horizon;
196 const FaceType* firstFace =
nullptr;
198 const FaceType* currentFace =
nullptr;
203 for (
auto it = visibleFaces.begin(); it != visibleFaces.end() && !found;
206 for (
const FaceType* adjFace : (*it)->
adjFaces()) {
208 if (visibleFaces.find(adjFace) == visibleFaces.end()) {
211 currentFace = firstFace;
212 currentEdge = firstEdge;
221 MeshPos<FaceType> pos(currentFace, currentEdge);
223 horizonVertices.insert(pos.vertex());
225 while (visibleFaces.find(pos.face()) != visibleFaces.end()) {
226 pos.nextEdgeAdjacentToV();
228 auto p = std::make_pair(pos.face()->index(), pos.edge());
229 horizon.push_back(p);
232 currentFace = pos.face();
233 currentEdge = pos.edge();
234 }
while (currentFace != firstFace || currentEdge != firstEdge);
239template<Po
int3Concept Po
intType, FaceMeshConcept MeshType>
240auto potentialConflictPoints(
241 const BipartiteGraph<PointType, uint>& conflictGraph,
242 const PointType& currentPoint,
246 using FaceType = MeshType::FaceType;
248 std::vector<std::set<PointType>> potentialConflictPoints(horizon.size());
251 for (
const auto& [faceIndex, edgeIndex] : horizon) {
252 for (
const auto& p : conflictGraph.adjacentRightNodes(faceIndex)) {
253 potentialConflictPoints[i].insert(p);
256 const FaceType& face =
convexHull.face(faceIndex);
258 uint adjFaceIndex = face.adjFace(edgeIndex)->index();
260 for (
const auto& p : conflictGraph.adjacentRightNodes(adjFaceIndex)) {
261 potentialConflictPoints[i].insert(p);
264 potentialConflictPoints[i].erase(currentPoint);
269 return potentialConflictPoints;
273 FaceMeshConcept MeshType,
274 FaceConcept FaceType,
275 VertexConcept VertexType>
276void deleteVisibleFaces(
278 const std::set<const FaceType*>& visibleFaces,
279 const std::set<const VertexType*>& horizonVertices)
281 std::set<const VertexType*> verticesToDelete;
283 for (
const FaceType* face : visibleFaces) {
284 for (
const VertexType* vertex : face->
vertices()) {
285 if (horizonVertices.find(vertex) == horizonVertices.end()) {
286 verticesToDelete.insert(vertex);
292 for (
const VertexType* vertex : verticesToDelete) {
297template<Po
int3Concept Po
intType, FaceMeshConcept MeshType>
298std::vector<uint> addNewFaces(
300 const PointType& currentPoint,
301 const std::vector<std::pair<uint, uint>>& horizon)
303 using VertexType = MeshType::VertexType;
304 using FaceType = MeshType::FaceType;
306 std::vector<uint> newFaces;
308 newFaces.reserve(horizon.size());
315 for (
const auto& [faceIndex, edgeIndex] : horizon) {
316 uint v1 =
convexHull.face(faceIndex).vertexIndexMod(edgeIndex + 1);
317 uint v2 =
convexHull.face(faceIndex).vertexIndex(edgeIndex);
320 newFaces.push_back(f);
331 convexHull.face(faceIndex).setAdjFace(edgeIndex, f);
336 convexHull.face(firstFace).setAdjFace(0, lastFace);
337 convexHull.face(lastFace).setAdjFace(2, firstFace);
342template<Po
int3Concept Po
intType, FaceMeshConcept MeshType>
343void updateNewConflicts(
344 BipartiteGraph<PointType, uint>& conflictGraph,
346 const std::vector<uint>& newFaces,
347 const std::vector<std::set<PointType>>& potentialConflictPoints)
349 using FaceType = MeshType::FaceType;
351 for (uint i = 0; i < newFaces.size(); ++i) {
352 conflictGraph.addRightNode(newFaces[i]);
354 const FaceType& face =
convexHull.face(newFaces[i]);
356 for (
const auto& p : potentialConflictPoints[i]) {
358 conflictGraph.addArc(p, newFaces[i]);
378template<FaceMeshConcept MeshType, Range R, LoggerConcept LogType = NullLogger>
381 std::optional<uint>
seed = std::nullopt,
385 using PointType = std::ranges::range_value_t<R>;
386 using VertexType = MeshType::VertexType;
387 using FaceType = MeshType::FaceType;
391 "MeshType must have per-face adjacent faces.");
393 log.log(0,
"Shuffling points...");
396 std::ranges::begin(points), std::ranges::end(points));
400 log.log(0,
"Making first tetrahedron...");
402 auto result = detail::makeTetrahedron<MeshType>(
409 log.log(0,
"Computing convex hull...");
432 auto potentialConflictPoints = detail::potentialConflictPoints(
450 detail::updateNewConflicts(
461 log.log(100,
"Convex hull computed.");
476template<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:871
Definition face_components.h:72
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:89
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:111
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:70
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