ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ecvQhull.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 // CV_CORE_LIB
9 #include <CVConst.h>
10 #include <CVLog.h>
11 
12 // LOCAL
13 #include "ecvHObjectCaster.h"
14 #include "ecvMesh.h"
15 #include "ecvPointCloud.h"
16 #include "ecvQhull.h"
17 #include "ecvTetraMesh.h"
18 
19 // QHULL_LIB
20 #include "libqhullcpp/PointCoordinates.h"
21 #include "libqhullcpp/Qhull.h"
22 #include "libqhullcpp/QhullFacet.h"
23 #include "libqhullcpp/QhullFacetList.h"
24 #include "libqhullcpp/QhullVertexSet.h"
25 
26 // SYSTEM
27 #include <unordered_map>
28 #include <unordered_set>
29 
30 namespace cloudViewer {
31 namespace geometry {
32 
33 std::tuple<std::shared_ptr<ccMesh>, std::vector<size_t>>
34 Qhull::ComputeConvexHull(const std::vector<Eigen::Vector3d>& points) {
36 }
37 
38 std::tuple<std::shared_ptr<ccMesh>, std::vector<size_t>>
39 Qhull::ComputeConvexHull(const std::vector<CCVector3>& points) {
40  ccPointCloud* baseVertices = new ccPointCloud("vertices");
41  assert(baseVertices);
42  baseVertices->setEnabled(false);
43  // DGM: no need to lock it as it is only used by one mesh!
44  baseVertices->setLocked(false);
45  auto convex_hull = std::make_shared<ccMesh>(baseVertices);
46  convex_hull->addChild(baseVertices);
47  convex_hull->setName("ConvexMesh");
48  std::vector<size_t> pt_map;
49 
50  std::vector<double> qhull_points_data(points.size() * 3);
51  for (size_t pidx = 0; pidx < points.size(); ++pidx) {
52  const auto& pt = points[pidx];
53  qhull_points_data[pidx * 3 + 0] = pt[0];
54  qhull_points_data[pidx * 3 + 1] = pt[1];
55  qhull_points_data[pidx * 3 + 2] = pt[2];
56  }
57 
58  orgQhull::PointCoordinates qhull_points(3, "");
59  qhull_points.append(qhull_points_data);
60 
61  orgQhull::Qhull qhull;
62  qhull.runQhull(qhull_points.comment().c_str(), qhull_points.dimension(),
63  qhull_points.count(), qhull_points.coordinates(), "Qt");
64 
65  orgQhull::QhullFacetList facets = qhull.facetList();
66 
67  if (!convex_hull->resize(facets.count())) {
68  assert(false);
69  }
70  std::unordered_map<unsigned int, unsigned int> vert_map;
71  std::unordered_set<unsigned int> inserted_vertices;
72  int tidx = 0;
73  for (orgQhull::QhullFacetList::iterator it = facets.begin();
74  it != facets.end(); ++it) {
75  if (!(*it).isGood()) continue;
76 
77  orgQhull::QhullFacet f = *it;
78  orgQhull::QhullVertexSet vSet = f.vertices();
79  int triangle_subscript = 0;
80  for (orgQhull::QhullVertexSet::iterator vIt = vSet.begin();
81  vIt != vSet.end(); ++vIt) {
82  orgQhull::QhullVertex v = *vIt;
83  orgQhull::QhullPoint p = v.point();
84 
85  unsigned int vidx = static_cast<unsigned int>(p.id());
86  convex_hull->getTriangleVertIndexes(tidx)->i[triangle_subscript] =
87  vidx;
88  triangle_subscript++;
89 
90  if (inserted_vertices.count(vidx) == 0) {
91  inserted_vertices.insert(vidx);
92  vert_map[vidx] = baseVertices->size();
93  double* coords = p.coordinates();
94  baseVertices->addPoint(
95  CCVector3(static_cast<PointCoordinateType>(coords[0]),
96  static_cast<PointCoordinateType>(coords[1]),
97  static_cast<PointCoordinateType>(coords[2])));
98  pt_map.push_back(vidx);
99  }
100  }
101 
102  tidx++;
103  }
104 
105  for (unsigned int i = 0; i < convex_hull->size(); ++i) {
107  convex_hull->getTriangleVertIndexes(i);
108  tsi->i1 = vert_map[tsi->i1];
109  tsi->i2 = vert_map[tsi->i2];
110  tsi->i3 = vert_map[tsi->i3];
111  }
112 
113  // do some cleaning
114  {
115  baseVertices->shrinkToFit();
116  convex_hull->shrinkToFit();
117  NormsIndexesTableType* normals = convex_hull->getTriNormsTable();
118  if (normals) {
119  normals->shrink_to_fit();
120  }
121  }
122 
123  return std::make_tuple(convex_hull, pt_map);
124 }
125 
126 std::tuple<std::shared_ptr<TetraMesh>, std::vector<size_t>>
127 Qhull::ComputeDelaunayTetrahedralization(const std::vector<CCVector3>& points) {
130 }
131 
132 std::tuple<std::shared_ptr<TetraMesh>, std::vector<size_t>>
134  const std::vector<Eigen::Vector3d>& points) {
135  typedef decltype(TetraMesh::tetras_)::value_type Vector4i;
136  auto delaunay_triangulation = std::make_shared<TetraMesh>();
137  std::vector<size_t> pt_map;
138 
139  if (points.size() < 4) {
140  CVLog::Error(
141  "[ComputeDelaunayTriangulation3D] not enough points to create "
142  "a tetrahedral mesh.");
143  }
144 
145  // qhull cannot deal with this case
146  if (points.size() == 4) {
147  delaunay_triangulation->vertices_ = points;
148  delaunay_triangulation->tetras_.push_back(Vector4i(0, 1, 2, 3));
149  return std::make_tuple(delaunay_triangulation, pt_map);
150  }
151 
152  std::vector<double> qhull_points_data(points.size() * 3);
153  for (size_t pidx = 0; pidx < points.size(); ++pidx) {
154  const auto& pt = points[pidx];
155  qhull_points_data[pidx * 3 + 0] = pt[0];
156  qhull_points_data[pidx * 3 + 1] = pt[1];
157  qhull_points_data[pidx * 3 + 2] = pt[2];
158  }
159 
160  orgQhull::PointCoordinates qhull_points(3, "");
161  qhull_points.append(qhull_points_data);
162 
163  orgQhull::Qhull qhull;
164  qhull.runQhull(qhull_points.comment().c_str(), qhull_points.dimension(),
165  qhull_points.count(), qhull_points.coordinates(),
166  "d Qbb Qt");
167 
168  orgQhull::QhullFacetList facets = qhull.facetList();
169  delaunay_triangulation->tetras_.resize(facets.count());
170  std::unordered_map<int, int> vert_map;
171  std::unordered_set<int> inserted_vertices;
172  int tidx = 0;
173  for (orgQhull::QhullFacetList::iterator it = facets.begin();
174  it != facets.end(); ++it) {
175  if (!(*it).isGood()) continue;
176 
177  orgQhull::QhullFacet f = *it;
178  orgQhull::QhullVertexSet vSet = f.vertices();
179  int tetra_subscript = 0;
180  for (orgQhull::QhullVertexSet::iterator vIt = vSet.begin();
181  vIt != vSet.end(); ++vIt) {
182  orgQhull::QhullVertex v = *vIt;
183  orgQhull::QhullPoint p = v.point();
184 
185  int vidx = p.id();
186  delaunay_triangulation->tetras_[tidx](tetra_subscript) = vidx;
187  tetra_subscript++;
188 
189  if (inserted_vertices.count(vidx) == 0) {
190  inserted_vertices.insert(vidx);
191  vert_map[vidx] = int(delaunay_triangulation->vertices_.size());
192  double* coords = p.coordinates();
193  delaunay_triangulation->vertices_.push_back(
194  Eigen::Vector3d(coords[0], coords[1], coords[2]));
195  pt_map.push_back(vidx);
196  }
197  }
198 
199  tidx++;
200  }
201 
202  for (auto& tetra : delaunay_triangulation->tetras_) {
203  tetra(0) = vert_map[tetra(0)];
204  tetra(1) = vert_map[tetra(1)];
205  tetra(2) = vert_map[tetra(2)];
206  tetra(3) = vert_map[tetra(3)];
207  }
208 
209  return std::make_tuple(delaunay_triangulation, pt_map);
210 }
211 
212 } // namespace geometry
213 } // namespace cloudViewer
Vector3Tpl< PointCoordinateType > CCVector3
Default 3D Vector.
Definition: CVGeom.h:798
float PointCoordinateType
Type of the coordinates of a (N-D) point.
Definition: CVTypes.h:16
int points
static bool Error(const char *format,...)
Display an error dialog with formatted message.
Definition: CVLog.cpp:143
Array of compressed 3D normals (single index)
static std::vector< Eigen::Matrix< double, 3, 1 > > fromArrayContainer(const std::vector< Vector3Tpl< PointCoordinateType >> &container)
Definition: CVGeom.h:301
virtual void setLocked(bool state)
Sets the "enabled" property.
Definition: ecvObject.h:117
virtual void setEnabled(bool state)
Sets the "enabled" property.
Definition: ecvObject.h:102
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void shrinkToFit()
Removes unused capacity.
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
unsigned size() const override
Definition: PointCloudTpl.h:38
static std::tuple< std::shared_ptr< ccMesh >, std::vector< size_t > > ComputeConvexHull(const std::vector< Eigen::Vector3d > &points)
Definition: ecvQhull.cpp:34
static std::tuple< std::shared_ptr< TetraMesh >, std::vector< size_t > > ComputeDelaunayTetrahedralization(const std::vector< Eigen::Vector3d > &points)
Definition: ecvQhull.cpp:133
std::vector< Eigen::Vector4i, cloudViewer::utility::Vector4i_allocator > tetras_
List of tetras denoted by the index of points forming the tetra.
Definition: ecvTetraMesh.h:108
double normals[3]
Generic file read and write utility for python interface.
Eigen::Matrix< Index, 4, 1 > Vector4i
Definition: knncpp.h:31
Triangle described by the indexes of its 3 vertices.