GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/shape/convex.cpp Lines: 2 16 12.5 %
Date: 2024-02-09 12:57:42 Branches: 1 50 2.0 %

Line Branch Exec Source
1
#include <hpp/fcl/shape/convex.h>
2
3
#ifdef HPP_FCL_HAS_QHULL
4
#include <libqhullcpp/QhullError.h>
5
#include <libqhullcpp/QhullFacet.h>
6
#include <libqhullcpp/QhullLinkedList.h>
7
#include <libqhullcpp/QhullVertex.h>
8
#include <libqhullcpp/QhullVertexSet.h>
9
#include <libqhullcpp/QhullRidge.h>
10
#include <libqhullcpp/Qhull.h>
11
12
using orgQhull::Qhull;
13
using orgQhull::QhullFacet;
14
using orgQhull::QhullPoint;
15
using orgQhull::QhullRidgeSet;
16
using orgQhull::QhullVertex;
17
using orgQhull::QhullVertexList;
18
using orgQhull::QhullVertexSet;
19
#endif
20
21
namespace hpp {
22
namespace fcl {
23
24
// Reorders `tri` such that the dot product between the normal of triangle and
25
// the vector `triangle barycentre - convex_tri.center` is positive.
26
void reorderTriangle(const Convex<Triangle>* convex_tri, Triangle& tri) {
27
  Vec3f p0, p1, p2;
28
  p0 = convex_tri->points[tri[0]];
29
  p1 = convex_tri->points[tri[1]];
30
  p2 = convex_tri->points[tri[2]];
31
32
  Vec3f barycentre_tri, center_barycenter;
33
  barycentre_tri = (p0 + p1 + p2) / 3;
34
  center_barycenter = barycentre_tri - convex_tri->center;
35
36
  Vec3f edge_tri1, edge_tri2, n_tri;
37
  edge_tri1 = p1 - p0;
38
  edge_tri2 = p2 - p1;
39
  n_tri = edge_tri1.cross(edge_tri2);
40
41
  if (center_barycenter.dot(n_tri) < 0) {
42
    tri.set(tri[1], tri[0], tri[2]);
43
  }
44
}
45
46
1
ConvexBase* ConvexBase::convexHull(const Vec3f* pts, unsigned int num_points,
47
                                   bool keepTriangles,
48
                                   const char* qhullCommand) {
49
#ifdef HPP_FCL_HAS_QHULL
50
  if (num_points <= 3) {
51
    throw std::invalid_argument(
52
        "You shouldn't use this function with less than"
53
        " 4 points.");
54
  }
55
  assert(pts[0].data() + 3 == pts[1].data());
56
57
  Qhull qh;
58
  const char* command =
59
      qhullCommand ? qhullCommand : (keepTriangles ? "Qt" : "");
60
  qh.runQhull("", 3, static_cast<int>(num_points), pts[0].data(), command);
61
62
  if (qh.qhullStatus() != qh_ERRnone) {
63
    if (qh.hasQhullMessage()) std::cerr << qh.qhullMessage() << std::endl;
64
    throw std::logic_error("Qhull failed");
65
  }
66
67
  typedef std::size_t index_type;
68
  typedef int size_type;
69
70
  // Map index in pts to index in vertices. -1 means not used
71
  std::vector<int> pts_to_vertices(num_points, -1);
72
73
  // Initialize the vertices
74
  int nvertex = (qh.vertexCount());
75
  Vec3f* vertices = new Vec3f[size_t(nvertex)];
76
  QhullVertexList vertexList(qh.vertexList());
77
  int i_vertex = 0;
78
  for (QhullVertexList::const_iterator v = vertexList.begin();
79
       v != vertexList.end(); ++v) {
80
    QhullPoint pt((*v).point());
81
    pts_to_vertices[(size_t)pt.id()] = (int)i_vertex;
82
    vertices[i_vertex] = Vec3f(pt[0], pt[1], pt[2]);
83
    ++i_vertex;
84
  }
85
  assert(i_vertex == nvertex);
86
87
  Convex<Triangle>* convex_tri(NULL);
88
  ConvexBase* convex(NULL);
89
  if (keepTriangles)
90
    convex = convex_tri = new Convex<Triangle>();
91
  else
92
    convex = new ConvexBase;
93
  convex->initialize(true, vertices, static_cast<unsigned int>(nvertex));
94
95
  // Build the neighbors
96
  convex->neighbors = new Neighbors[size_t(nvertex)];
97
  std::vector<std::set<index_type> > nneighbors(static_cast<size_t>(nvertex));
98
  if (keepTriangles) {
99
    convex_tri->num_polygons = static_cast<unsigned int>(qh.facetCount());
100
    convex_tri->polygons = new Triangle[convex_tri->num_polygons];
101
    convex_tri->computeCenter();
102
  }
103
104
  unsigned int c_nneighbors = 0;
105
  unsigned int i_polygon = 0;
106
107
  // Compute the neighbors from the edges of the faces.
108
  for (QhullFacet facet = qh.beginFacet(); facet != qh.endFacet();
109
       facet = facet.next()) {
110
    if (facet.isSimplicial()) {
111
      // In 3D, simplicial faces have 3 vertices. We mark them as neighbors.
112
      QhullVertexSet f_vertices(facet.vertices());
113
      size_t n = static_cast<size_t>(f_vertices.count());
114
      assert(n == 3);
115
      Triangle tri(
116
          static_cast<size_t>(
117
              pts_to_vertices[static_cast<size_t>(f_vertices[0].point().id())]),
118
          static_cast<size_t>(
119
              pts_to_vertices[static_cast<size_t>(f_vertices[1].point().id())]),
120
          static_cast<size_t>(pts_to_vertices[static_cast<size_t>(
121
              f_vertices[2].point().id())]));
122
      if (keepTriangles) {
123
        reorderTriangle(convex_tri, tri);
124
        convex_tri->polygons[i_polygon++] = tri;
125
      }
126
      for (size_t j = 0; j < n; ++j) {
127
        size_t i = (j == 0) ? n - 1 : j - 1;
128
        size_t k = (j == n - 1) ? 0 : j + 1;
129
        // Update neighbors of pj;
130
        if (nneighbors[tri[j]].insert(tri[i]).second) c_nneighbors++;
131
        if (nneighbors[tri[j]].insert(tri[k]).second) c_nneighbors++;
132
      }
133
    } else {
134
      if (keepTriangles) {  // TODO I think there is a memory leak here.
135
        throw std::invalid_argument(
136
            "You requested to keep triangles so you "
137
            "must pass option \"Qt\" to qhull via the qhull command argument.");
138
      }
139
      // Non-simplicial faces have more than 3 vertices and contains a list of
140
      // rigdes. Ridges are (3-1)D simplex (i.e. one edge). We mark the two
141
      // vertices of each ridge as neighbors.
142
      QhullRidgeSet f_ridges(facet.ridges());
143
      for (size_type j = 0; j < f_ridges.count(); ++j) {
144
        assert(f_ridges[j].vertices().count() == 2);
145
        int pi = pts_to_vertices[static_cast<size_t>(
146
                f_ridges[j].vertices()[0].point().id())],
147
            pj = pts_to_vertices[static_cast<size_t>(
148
                f_ridges[j].vertices()[1].point().id())];
149
        // Update neighbors of pi and pj;
150
        if (nneighbors[static_cast<size_t>(pj)]
151
                .insert(static_cast<size_t>(pi))
152
                .second)
153
          c_nneighbors++;
154
        if (nneighbors[static_cast<size_t>(pi)]
155
                .insert(static_cast<size_t>(pj))
156
                .second)
157
          c_nneighbors++;
158
      }
159
    }
160
  }
161
  assert(!keepTriangles || i_polygon == qh.facetCount());
162
163
  // Fill the neighbor attribute of the returned object.
164
  convex->nneighbors_ = new unsigned int[c_nneighbors];
165
  unsigned int* p_nneighbors = convex->nneighbors_;
166
  for (size_t i = 0; i < static_cast<size_t>(nvertex); ++i) {
167
    Neighbors& n = convex->neighbors[i];
168
    if (nneighbors[i].size() >= (std::numeric_limits<unsigned char>::max)())
169
      throw std::logic_error("Too many neighbors.");
170
    n.count_ = (unsigned char)nneighbors[i].size();
171
    n.n_ = p_nneighbors;
172
    p_nneighbors =
173
        std::copy(nneighbors[i].begin(), nneighbors[i].end(), p_nneighbors);
174
  }
175
  assert(p_nneighbors == convex->nneighbors_ + c_nneighbors);
176
  return convex;
177
#else
178
  throw std::logic_error(
179
1
      "Library built without qhull. Cannot build object of this type.");
180
  HPP_FCL_UNUSED_VARIABLE(pts);
181
  HPP_FCL_UNUSED_VARIABLE(num_points);
182
  HPP_FCL_UNUSED_VARIABLE(keepTriangles);
183
  HPP_FCL_UNUSED_VARIABLE(qhullCommand);
184
#endif
185
}
186
}  // namespace fcl
187
}  // namespace hpp