Point Cloud Library (PCL) 1.12.0
marching_cubes.hpp
1/*
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2010, Willow Garage, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of Willow Garage, Inc. nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *
34 */
35
36#ifndef PCL_SURFACE_IMPL_MARCHING_CUBES_H_
37#define PCL_SURFACE_IMPL_MARCHING_CUBES_H_
38
39#include <pcl/surface/marching_cubes.h>
40#include <pcl/common/common.h>
41#include <pcl/common/vector_average.h>
42#include <pcl/Vertices.h>
43
44//////////////////////////////////////////////////////////////////////////////////////////////
45template <typename PointNT>
47{
48}
49
50//////////////////////////////////////////////////////////////////////////////////////////////
51template <typename PointNT> void
53{
54 PointNT max_pt, min_pt;
55 pcl::getMinMax3D (*input_, min_pt, max_pt);
56
57 lower_boundary_ = min_pt.getArray3fMap ();
58 upper_boundary_ = max_pt.getArray3fMap ();
59
60 const Eigen::Array3f size3_extend = 0.5f * percentage_extend_grid_
61 * (upper_boundary_ - lower_boundary_);
62
63 lower_boundary_ -= size3_extend;
64 upper_boundary_ += size3_extend;
65}
66
67
68//////////////////////////////////////////////////////////////////////////////////////////////
69template <typename PointNT> void
71 Eigen::Vector3f &p2,
72 float val_p1,
73 float val_p2,
74 Eigen::Vector3f &output)
75{
76 const float mu = (iso_level_ - val_p1) / (val_p2 - val_p1);
77 output = p1 + mu * (p2 - p1);
78}
79
80
81//////////////////////////////////////////////////////////////////////////////////////////////
82template <typename PointNT> void
83pcl::MarchingCubes<PointNT>::createSurface (const std::vector<float> &leaf_node,
84 const Eigen::Vector3i &index_3d,
86{
87 int cubeindex = 0;
88 if (leaf_node[0] < iso_level_) cubeindex |= 1;
89 if (leaf_node[1] < iso_level_) cubeindex |= 2;
90 if (leaf_node[2] < iso_level_) cubeindex |= 4;
91 if (leaf_node[3] < iso_level_) cubeindex |= 8;
92 if (leaf_node[4] < iso_level_) cubeindex |= 16;
93 if (leaf_node[5] < iso_level_) cubeindex |= 32;
94 if (leaf_node[6] < iso_level_) cubeindex |= 64;
95 if (leaf_node[7] < iso_level_) cubeindex |= 128;
96
97 // Cube is entirely in/out of the surface
98 if (edgeTable[cubeindex] == 0)
99 return;
100
101 const Eigen::Vector3f center = lower_boundary_
102 + size_voxel_ * index_3d.cast<float> ().array ();
103
104 std::vector<Eigen::Vector3f, Eigen::aligned_allocator<Eigen::Vector3f> > p;
105 p.resize (8);
106 for (int i = 0; i < 8; ++i)
107 {
108 Eigen::Vector3f point = center;
109 if (i & 0x4)
110 point[1] = static_cast<float> (center[1] + size_voxel_[1]);
111
112 if (i & 0x2)
113 point[2] = static_cast<float> (center[2] + size_voxel_[2]);
114
115 if ((i & 0x1) ^ ((i >> 1) & 0x1))
116 point[0] = static_cast<float> (center[0] + size_voxel_[0]);
117
118 p[i] = point;
119 }
120
121 // Find the vertices where the surface intersects the cube
122 std::vector<Eigen::Vector3f, Eigen::aligned_allocator<Eigen::Vector3f> > vertex_list;
123 vertex_list.resize (12);
124 if (edgeTable[cubeindex] & 1)
125 interpolateEdge (p[0], p[1], leaf_node[0], leaf_node[1], vertex_list[0]);
126 if (edgeTable[cubeindex] & 2)
127 interpolateEdge (p[1], p[2], leaf_node[1], leaf_node[2], vertex_list[1]);
128 if (edgeTable[cubeindex] & 4)
129 interpolateEdge (p[2], p[3], leaf_node[2], leaf_node[3], vertex_list[2]);
130 if (edgeTable[cubeindex] & 8)
131 interpolateEdge (p[3], p[0], leaf_node[3], leaf_node[0], vertex_list[3]);
132 if (edgeTable[cubeindex] & 16)
133 interpolateEdge (p[4], p[5], leaf_node[4], leaf_node[5], vertex_list[4]);
134 if (edgeTable[cubeindex] & 32)
135 interpolateEdge (p[5], p[6], leaf_node[5], leaf_node[6], vertex_list[5]);
136 if (edgeTable[cubeindex] & 64)
137 interpolateEdge (p[6], p[7], leaf_node[6], leaf_node[7], vertex_list[6]);
138 if (edgeTable[cubeindex] & 128)
139 interpolateEdge (p[7], p[4], leaf_node[7], leaf_node[4], vertex_list[7]);
140 if (edgeTable[cubeindex] & 256)
141 interpolateEdge (p[0], p[4], leaf_node[0], leaf_node[4], vertex_list[8]);
142 if (edgeTable[cubeindex] & 512)
143 interpolateEdge (p[1], p[5], leaf_node[1], leaf_node[5], vertex_list[9]);
144 if (edgeTable[cubeindex] & 1024)
145 interpolateEdge (p[2], p[6], leaf_node[2], leaf_node[6], vertex_list[10]);
146 if (edgeTable[cubeindex] & 2048)
147 interpolateEdge (p[3], p[7], leaf_node[3], leaf_node[7], vertex_list[11]);
148
149 // Create the triangle
150 for (int i = 0; triTable[cubeindex][i] != -1; i += 3)
151 {
152 PointNT p1, p2, p3;
153 p1.getVector3fMap () = vertex_list[triTable[cubeindex][i]];
154 cloud.push_back (p1);
155 p2.getVector3fMap () = vertex_list[triTable[cubeindex][i+1]];
156 cloud.push_back (p2);
157 p3.getVector3fMap () = vertex_list[triTable[cubeindex][i+2]];
158 cloud.push_back (p3);
159 }
160}
161
162
163//////////////////////////////////////////////////////////////////////////////////////////////
164template <typename PointNT> void
166 Eigen::Vector3i &index3d)
167{
168 leaf.resize (8);
169
170 leaf[0] = getGridValue (index3d);
171 leaf[1] = getGridValue (index3d + Eigen::Vector3i (1, 0, 0));
172 leaf[2] = getGridValue (index3d + Eigen::Vector3i (1, 0, 1));
173 leaf[3] = getGridValue (index3d + Eigen::Vector3i (0, 0, 1));
174 leaf[4] = getGridValue (index3d + Eigen::Vector3i (0, 1, 0));
175 leaf[5] = getGridValue (index3d + Eigen::Vector3i (1, 1, 0));
176 leaf[6] = getGridValue (index3d + Eigen::Vector3i (1, 1, 1));
177 leaf[7] = getGridValue (index3d + Eigen::Vector3i (0, 1, 1));
178
179 for (int i = 0; i < 8; ++i)
180 {
181 if (std::isnan (leaf[i]))
182 {
183 leaf.clear ();
184 break;
185 }
186 }
187}
188
189
190//////////////////////////////////////////////////////////////////////////////////////////////
191template <typename PointNT> float
193{
194 /// TODO what to return?
195 if (pos[0] < 0 || pos[0] >= res_x_)
196 return -1.0f;
197 if (pos[1] < 0 || pos[1] >= res_y_)
198 return -1.0f;
199 if (pos[2] < 0 || pos[2] >= res_z_)
200 return -1.0f;
201
202 return grid_[pos[0]*res_y_*res_z_ + pos[1]*res_z_ + pos[2]];
203}
204
205
206//////////////////////////////////////////////////////////////////////////////////////////////
207template <typename PointNT> void
209{
211
212 performReconstruction (points, output.polygons);
213
214 pcl::toPCLPointCloud2 (points, output.cloud);
215}
216
217
218//////////////////////////////////////////////////////////////////////////////////////////////
219template <typename PointNT> void
221 std::vector<pcl::Vertices> &polygons)
222{
223 if (!(iso_level_ >= 0 && iso_level_ < 1))
224 {
225 PCL_ERROR ("[pcl::%s::performReconstruction] Invalid iso level %f! Please use a number between 0 and 1.\n",
226 getClassName ().c_str (), iso_level_);
227 points.clear ();
228 polygons.clear ();
229 return;
230 }
231
232 // the point cloud really generated from Marching Cubes, prev intermediate_cloud_
233 pcl::PointCloud<PointNT> intermediate_cloud;
234
235 // Create grid
236 grid_ = std::vector<float> (res_x_*res_y_*res_z_, NAN);
237
238 // Compute bounding box and voxel size
239 getBoundingBox ();
240 size_voxel_ = (upper_boundary_ - lower_boundary_)
241 * Eigen::Array3f (res_x_, res_y_, res_z_).inverse ();
242
243 // Transform the point cloud into a voxel grid
244 // This needs to be implemented in a child class
245 voxelizeData ();
246
247 // preallocate memory assuming a hull. suppose 6 point per voxel
248 double size_reserve = std::min((double) intermediate_cloud.points.max_size (),
249 2.0 * 6.0 * (double) (res_y_*res_z_ + res_x_*res_z_ + res_x_*res_y_));
250 intermediate_cloud.reserve ((std::size_t) size_reserve);
251
252 for (int x = 1; x < res_x_-1; ++x)
253 for (int y = 1; y < res_y_-1; ++y)
254 for (int z = 1; z < res_z_-1; ++z)
255 {
256 Eigen::Vector3i index_3d (x, y, z);
257 std::vector<float> leaf_node;
258 getNeighborList1D (leaf_node, index_3d);
259 if (!leaf_node.empty ())
260 createSurface (leaf_node, index_3d, intermediate_cloud);
261 }
262
263 points.swap (intermediate_cloud);
264
265 polygons.resize (points.size () / 3);
266 for (std::size_t i = 0; i < polygons.size (); ++i)
267 {
269 v.vertices.resize (3);
270 for (int j = 0; j < 3; ++j)
271 v.vertices[j] = static_cast<int> (i) * 3 + j;
272 polygons[i] = v;
273 }
274}
275
276#define PCL_INSTANTIATE_MarchingCubes(T) template class PCL_EXPORTS pcl::MarchingCubes<T>;
277
278#endif // PCL_SURFACE_IMPL_MARCHING_CUBES_H_
279
void performReconstruction(pcl::PolygonMesh &output) override
Extract the surface.
virtual float getGridValue(Eigen::Vector3i pos)
Method that returns the scalar value at the given grid position.
void getBoundingBox()
Get the bounding box for the input data points.
void interpolateEdge(Eigen::Vector3f &p1, Eigen::Vector3f &p2, float val_p1, float val_p2, Eigen::Vector3f &output)
Interpolate along the voxel edge.
void createSurface(const std::vector< float > &leaf_node, const Eigen::Vector3i &index_3d, pcl::PointCloud< PointNT > &cloud)
Calculate out the corresponding polygons in the leaf node.
void getNeighborList1D(std::vector< float > &leaf, Eigen::Vector3i &index3d)
Method that returns the scalar values of the neighbors of a given 3D position in the grid.
~MarchingCubes()
Destructor.
void push_back(const PointT &pt)
Insert a new point in the cloud, at the end of the container.
Definition: point_cloud.h:652
void clear()
Removes all points in a cloud and sets the width and height to 0.
Definition: point_cloud.h:874
std::size_t size() const
Definition: point_cloud.h:443
void reserve(std::size_t n)
Definition: point_cloud.h:445
void swap(PointCloud< PointT > &rhs)
Swap a point cloud with another cloud.
Definition: point_cloud.h:861
std::vector< PointT, Eigen::aligned_allocator< PointT > > points
The point data.
Definition: point_cloud.h:395
Define standard C methods and C++ classes that are common to all methods.
void getMinMax3D(const pcl::PointCloud< PointT > &cloud, PointT &min_pt, PointT &max_pt)
Get the minimum and maximum values on each of the 3 (x-y-z) dimensions in a given pointcloud.
Definition: common.hpp:295
void toPCLPointCloud2(const pcl::PointCloud< PointT > &cloud, pcl::PCLPointCloud2 &msg)
Convert a pcl::PointCloud<T> object to a PCLPointCloud2 binary data blob.
Definition: conversions.h:239
const unsigned int edgeTable[256]
const int triTable[256][16]
std::vector< ::pcl::Vertices > polygons
Definition: PolygonMesh.h:23
::pcl::PCLPointCloud2 cloud
Definition: PolygonMesh.h:21
Describes a set of vertices in a polygon mesh, by basically storing an array of indices.
Definition: Vertices.h:15
Indices vertices
Definition: Vertices.h:19