src/shape/convex.cpp
Go to the documentation of this file.
1 #include "coal/shape/convex.h"
2 
3 #ifdef COAL_HAS_QHULL
10 #include <libqhullcpp/Qhull.h>
11 
12 using orgQhull::Qhull;
18 #endif
19 
20 namespace coal {
21 
22 // Reorders `tri` such that the dot product between the normal of triangle and
23 // the vector `triangle barycentre - convex_tri.center` is positive.
24 void reorderTriangle(const Convex<Triangle>* convex_tri, Triangle& tri) {
25  Vec3s p0, p1, p2;
26  p0 = (*(convex_tri->points))[tri[0]];
27  p1 = (*(convex_tri->points))[tri[1]];
28  p2 = (*(convex_tri->points))[tri[2]];
29 
30  Vec3s barycentre_tri, center_barycenter;
31  barycentre_tri = (p0 + p1 + p2) / 3;
32  center_barycenter = barycentre_tri - convex_tri->center;
33 
34  Vec3s edge_tri1, edge_tri2, n_tri;
35  edge_tri1 = p1 - p0;
36  edge_tri2 = p2 - p1;
37  n_tri = edge_tri1.cross(edge_tri2);
38 
39  if (center_barycenter.dot(n_tri) < 0) {
40  tri.set(tri[1], tri[0], tri[2]);
41  }
42 }
43 
44 ConvexBase* ConvexBase::convexHull(std::shared_ptr<std::vector<Vec3s>>& pts,
45  unsigned int num_points, bool keepTriangles,
46  const char* qhullCommand) {
49  return ConvexBase::convexHull(pts->data(), num_points, keepTriangles,
50  qhullCommand);
52 }
53 
54 ConvexBase* ConvexBase::convexHull(const Vec3s* pts, unsigned int num_points,
55  bool keepTriangles,
56  const char* qhullCommand) {
57 #ifdef COAL_HAS_QHULL
58  if (num_points <= 3) {
60  "You shouldn't use this function with less than"
61  " 4 points.",
62  std::invalid_argument);
63  }
64  assert(pts[0].data() + 3 == pts[1].data());
65 
66  Qhull qh;
67  const char* command =
68  qhullCommand ? qhullCommand : (keepTriangles ? "Qt" : "");
69  qh.runQhull("", 3, static_cast<int>(num_points), pts[0].data(), command);
70 
71  if (qh.qhullStatus() != qh_ERRnone) {
72  if (qh.hasQhullMessage()) std::cerr << qh.qhullMessage() << std::endl;
73  COAL_THROW_PRETTY("Qhull failed", std::logic_error);
74  }
75 
76  typedef std::size_t index_type;
77  typedef int size_type;
78 
79  // Map index in pts to index in vertices. -1 means not used
80  std::vector<int> pts_to_vertices(num_points, -1);
81 
82  // Initialize the vertices
83  size_t nvertex = static_cast<size_t>(qh.vertexCount());
84  std::shared_ptr<std::vector<Vec3s>> vertices(
85  new std::vector<Vec3s>(size_t(nvertex)));
86  QhullVertexList vertexList(qh.vertexList());
87  size_t i_vertex = 0;
88  for (QhullVertexList::const_iterator v = vertexList.begin();
89  v != vertexList.end(); ++v) {
90  QhullPoint pt((*v).point());
91  pts_to_vertices[(size_t)pt.id()] = (int)i_vertex;
92  (*vertices)[i_vertex] = Vec3s(pt[0], pt[1], pt[2]);
93  ++i_vertex;
94  }
95  assert(i_vertex == nvertex);
96 
97  Convex<Triangle>* convex_tri(NULL);
98  ConvexBase* convex(NULL);
99  if (keepTriangles)
100  convex = convex_tri = new Convex<Triangle>();
101  else
102  convex = new ConvexBase;
103  convex->initialize(vertices, static_cast<unsigned int>(nvertex));
104 
105  // Build the neighbors
106  convex->neighbors.reset(new std::vector<Neighbors>(size_t(nvertex)));
107  std::vector<std::set<index_type>> nneighbors(static_cast<size_t>(nvertex));
108  if (keepTriangles) {
109  convex_tri->num_polygons = static_cast<unsigned int>(qh.facetCount());
110  convex_tri->polygons.reset(
111  new std::vector<Triangle>(convex_tri->num_polygons));
112  convex_tri->computeCenter();
113  }
114 
115  unsigned int c_nneighbors = 0;
116  unsigned int i_polygon = 0;
117 
118  // Compute the neighbors from the edges of the faces.
119  for (QhullFacet facet = qh.beginFacet(); facet != qh.endFacet();
120  facet = facet.next()) {
121  if (facet.isSimplicial()) {
122  // In 3D, simplicial faces have 3 vertices. We mark them as neighbors.
123  QhullVertexSet f_vertices(facet.vertices());
124  size_t n = static_cast<size_t>(f_vertices.count());
125  assert(n == 3);
126  Triangle tri(
127  static_cast<size_t>(
128  pts_to_vertices[static_cast<size_t>(f_vertices[0].point().id())]),
129  static_cast<size_t>(
130  pts_to_vertices[static_cast<size_t>(f_vertices[1].point().id())]),
131  static_cast<size_t>(pts_to_vertices[static_cast<size_t>(
132  f_vertices[2].point().id())]));
133  if (keepTriangles) {
134  reorderTriangle(convex_tri, tri);
135  (*convex_tri->polygons)[i_polygon++] = tri;
136  }
137  for (size_t j = 0; j < n; ++j) {
138  size_t i = (j == 0) ? n - 1 : j - 1;
139  size_t k = (j == n - 1) ? 0 : j + 1;
140  // Update neighbors of pj;
141  if (nneighbors[tri[j]].insert(tri[i]).second) c_nneighbors++;
142  if (nneighbors[tri[j]].insert(tri[k]).second) c_nneighbors++;
143  }
144  } else {
145  if (keepTriangles) { // TODO I think there is a memory leak here.
147  "You requested to keep triangles so you "
148  "must pass option \"Qt\" to qhull via the qhull command argument.",
149  std::invalid_argument);
150  }
151  // Non-simplicial faces have more than 3 vertices and contains a list of
152  // rigdes. Ridges are (3-1)D simplex (i.e. one edge). We mark the two
153  // vertices of each ridge as neighbors.
154  QhullRidgeSet f_ridges(facet.ridges());
155  for (size_type j = 0; j < f_ridges.count(); ++j) {
156  assert(f_ridges[j].vertices().count() == 2);
157  int pi = pts_to_vertices[static_cast<size_t>(
158  f_ridges[j].vertices()[0].point().id())],
159  pj = pts_to_vertices[static_cast<size_t>(
160  f_ridges[j].vertices()[1].point().id())];
161  // Update neighbors of pi and pj;
162  if (nneighbors[static_cast<size_t>(pj)]
163  .insert(static_cast<size_t>(pi))
164  .second)
165  c_nneighbors++;
166  if (nneighbors[static_cast<size_t>(pi)]
167  .insert(static_cast<size_t>(pj))
168  .second)
169  c_nneighbors++;
170  }
171  }
172  }
173  assert(!keepTriangles || static_cast<int>(i_polygon) == qh.facetCount());
174 
175  // Build the double representation (free in this case because qhull has
176  // alreday run)
177  convex->buildDoubleDescriptionFromQHullResult(qh);
178 
179  // Fill the neighbor attribute of the returned object.
180  convex->nneighbors_.reset(new std::vector<unsigned int>(c_nneighbors));
181  unsigned int* p_nneighbors = convex->nneighbors_->data();
182  std::vector<Neighbors>& neighbors_ = *(convex->neighbors);
183  for (size_t i = 0; i < static_cast<size_t>(nvertex); ++i) {
184  Neighbors& n = neighbors_[i];
185  if (nneighbors[i].size() >= (std::numeric_limits<unsigned char>::max)())
186  COAL_THROW_PRETTY("Too many neighbors.", std::logic_error);
187  n.count_ = (unsigned char)nneighbors[i].size();
188  n.n_ = p_nneighbors;
189  p_nneighbors =
190  std::copy(nneighbors[i].begin(), nneighbors[i].end(), p_nneighbors);
191  }
192  assert(p_nneighbors == convex->nneighbors_->data() + c_nneighbors);
193 
194  // Now that the neighbors are computed, we can call the
195  // `buildSupportWarmStart` function.
196  convex->buildSupportWarmStart();
197  return convex;
198 #else
200  "Library built without qhull. Cannot build object of this type.",
201  std::logic_error);
204  COAL_UNUSED_VARIABLE(keepTriangles);
205  COAL_UNUSED_VARIABLE(qhullCommand);
206 #endif
207 }
208 
209 #ifdef COAL_HAS_QHULL
210 void ConvexBase::buildDoubleDescription() {
211  if (num_points <= 3) {
213  "You shouldn't use this function with a convex less than"
214  " 4 points.",
215  std::invalid_argument);
216  }
217 
218  Qhull qh;
219  const char* command = "Qt";
220  qh.runQhull("", 3, static_cast<int>(num_points), (*points)[0].data(),
221  command);
222 
223  if (qh.qhullStatus() != qh_ERRnone) {
224  if (qh.hasQhullMessage()) std::cerr << qh.qhullMessage() << std::endl;
225  COAL_THROW_PRETTY("Qhull failed", std::logic_error);
226  }
227 
228  buildDoubleDescriptionFromQHullResult(qh);
229 }
230 
231 void ConvexBase::buildDoubleDescriptionFromQHullResult(const Qhull& qh) {
232  num_normals_and_offsets = static_cast<unsigned int>(qh.facetCount());
233  normals.reset(new std::vector<Vec3s>(num_normals_and_offsets));
234  std::vector<Vec3s>& normals_ = *normals;
235  offsets.reset(new std::vector<double>(num_normals_and_offsets));
236  std::vector<double>& offsets_ = *offsets;
237  unsigned int i_normal = 0;
238  for (QhullFacet facet = qh.beginFacet(); facet != qh.endFacet();
239  facet = facet.next()) {
240  const orgQhull::QhullHyperplane& plane = facet.hyperplane();
241  normals_[i_normal] = Vec3s(plane.coordinates()[0], plane.coordinates()[1],
242  plane.coordinates()[2]);
243  offsets_[i_normal] = plane.offset();
244  i_normal++;
245  }
246  assert(static_cast<int>(i_normal) == qh.facetCount());
247 }
248 #endif
249 
250 } // namespace coal
coal::Convex::num_polygons
unsigned int num_polygons
Definition: coal/shape/convex.h:102
QhullFacet.h
orgQhull::QhullVertexSet
Definition: QhullVertexSet.h:33
orgQhull::QhullRidgeSet
QhullSet< QhullRidge > QhullRidgeSet
Definition: QhullFacet.h:39
coal::Vec3s
Eigen::Matrix< CoalScalar, 3, 1 > Vec3s
Definition: coal/data_types.h:77
coal::ConvexBase::Neighbors::n_
unsigned int * n_
Definition: coal/shape/geometric_shapes.h:689
coal::ConvexBase::num_points
unsigned int num_points
Definition: coal/shape/geometric_shapes.h:720
coal::ConvexBase::neighbors
std::shared_ptr< std::vector< Neighbors > > neighbors
Neighbors of each vertex. It is an array of size num_points. For each vertex, it contains the number ...
Definition: coal/shape/geometric_shapes.h:732
orgQhull::QhullVertexList
QhullLinkedList< QhullVertex > QhullVertexList
Definition: QhullVertex.h:34
COAL_COMPILER_DIAGNOSTIC_PUSH
#define COAL_COMPILER_DIAGNOSTIC_PUSH
Definition: include/coal/fwd.hh:120
coal::Triangle::set
void set(index_type p1, index_type p2, index_type p3)
Set the vertex indices of the triangle.
Definition: coal/data_types.h:123
orgQhull::QhullPoint
Definition: QhullPoint.h:39
data
data
Qhull.h
coal
Main namespace.
Definition: coal/broadphase/broadphase_bruteforce.h:44
coal::ConvexBase::ConvexBase
ConvexBase()
Construct an uninitialized convex object Initialization is done with ConvexBase::initialize.
Definition: coal/shape/geometric_shapes.h:762
QhullVertexSet.h
coal::ConvexBase::normals
std::shared_ptr< std::vector< Vec3s > > normals
An array of the normals of the polygon.
Definition: coal/shape/geometric_shapes.h:723
orgQhull::QhullHyperplane::coordinates
const coordT * coordinates() const
Definition: QhullHyperplane.h:78
convex.h
coal::ConvexBase::Neighbors::count_
unsigned char count_
Definition: coal/shape/geometric_shapes.h:688
coal::ConvexBase::Neighbors
Definition: coal/shape/geometric_shapes.h:687
orgQhull::Qhull
Interface to Qhull from C++.
Definition: Qhull.h:49
qh_ERRnone
#define qh_ERRnone
Definition: libqhull.h:193
coal::ConvexBase::num_normals_and_offsets
unsigned int num_normals_and_offsets
Definition: coal/shape/geometric_shapes.h:727
COAL_UNUSED_VARIABLE
#define COAL_UNUSED_VARIABLE(var)
Definition: include/coal/fwd.hh:56
QhullRidge.h
qh
#define qh
Definition: libqhull.h:457
COAL_THROW_PRETTY
#define COAL_THROW_PRETTY(message, exception)
Definition: include/coal/fwd.hh:64
coal::ConvexBase::convexHull
static ConvexBase * convexHull(std::shared_ptr< std::vector< Vec3s >> &points, unsigned int num_points, bool keepTriangles, const char *qhullCommand=NULL)
Build a convex hull based on Qhull library and store the vertices and optionally the triangles.
Definition: src/shape/convex.cpp:44
orgQhull::QhullHyperplane::offset
coordT offset() const
Definition: QhullHyperplane.h:85
coal::ConvexBase::initialize
void initialize(std::shared_ptr< std::vector< Vec3s >> points_, unsigned int num_points_)
Initialize the points of the convex shape This also initializes the ConvexBase::center.
Definition: src/shape/geometric_shapes.cpp:43
orgQhull::QhullHyperplane
Definition: QhullHyperplane.h:39
coal::Convex
Convex polytope.
Definition: coal/serialization/collision_object.h:51
octree.p1
tuple p1
Definition: octree.py:54
orgQhull::QhullFacet
A QhullFacet is the C++ equivalent to Qhull's facetT*.
Definition: QhullFacet.h:43
coal::reorderTriangle
void reorderTriangle(const Convex< Triangle > *convex_tri, Triangle &tri)
Definition: src/shape/convex.cpp:24
coal::ConvexBase::buildSupportWarmStart
void buildSupportWarmStart()
Build the support points warm starts.
Definition: src/narrowphase/gjk.cpp:1471
coal::ConvexBase::offsets
std::shared_ptr< std::vector< double > > offsets
An array of the offsets to the normals of the polygon. Note: there are as many offsets as normals.
Definition: coal/shape/geometric_shapes.h:726
COAL_COMPILER_DIAGNOSTIC_POP
#define COAL_COMPILER_DIAGNOSTIC_POP
Definition: include/coal/fwd.hh:121
coal::Convex::polygons
std::shared_ptr< std::vector< PolygonT > > polygons
An array of PolygonT object. PolygonT should contains a list of vertices for each polygon,...
Definition: coal/shape/convex.h:101
COAL_COMPILER_DIAGNOSTIC_IGNORED_DEPRECECATED_DECLARATIONS
#define COAL_COMPILER_DIAGNOSTIC_IGNORED_DEPRECECATED_DECLARATIONS
Definition: include/coal/fwd.hh:122
QhullVertex.h
pi
constexpr CoalScalar pi
Definition: collision_node_asserts.cpp:10
coal::Triangle
Triangle with 3 indices for points.
Definition: coal/data_types.h:111
coal::ConvexBase::nneighbors_
std::shared_ptr< std::vector< unsigned int > > nneighbors_
Array of indices of the neighbors of each vertex. Since we don't know a priori the number of neighbor...
Definition: coal/shape/geometric_shapes.h:801
coal::ConvexBase::points
std::shared_ptr< std::vector< Vec3s > > points
An array of the points of the polygon.
Definition: coal/shape/geometric_shapes.h:719
QhullError.h
obb.v
list v
Definition: obb.py:48
coal::ConvexBase
Base for convex polytope.
Definition: coal/shape/geometric_shapes.h:645
QhullLinkedList.h


hpp-fcl
Author(s):
autogenerated on Sat Nov 23 2024 03:44:57