Pointcloud.cpp
Go to the documentation of this file.
1 /*
2  * OctoMap - An Efficient Probabilistic 3D Mapping Framework Based on Octrees
3  * https://octomap.github.io/
4  *
5  * Copyright (c) 2009-2013, K.M. Wurm and A. Hornung, University of Freiburg
6  * All rights reserved.
7  * License: New BSD
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the distribution.
17  * * Neither the name of the University of Freiburg nor the names of its
18  * contributors may be used to endorse or promote products derived from
19  * this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /* According to c++ standard including this header has no practical effect
35  * but it can be used to determine the c++ standard library implementation.
36  */
37 #include <ciso646>
38 
39 #if defined(_MSC_VER) || defined(_LIBCPP_VERSION)
40  #include <algorithm>
41  #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201103L) || __cplusplus >= 201103L)
42  #include <random>
43  #endif
44 #else
45  #include <ext/algorithm>
46 #endif
47 #include <assert.h>
48 #include <fstream>
49 #include <limits>
50 #include <math.h>
51 #include <sstream>
52 
53 #include <octomap/Pointcloud.h>
54 
55 namespace octomap {
56 
57 
59 
60  }
61 
63  this->clear();
64  }
65 
67 
68  // delete the points
69  if (points.size()) {
70  points.clear();
71  }
72  }
73 
74 
76  for (Pointcloud::const_iterator it = other.begin(); it != other.end(); it++) {
77  points.push_back(point3d(*it));
78  }
79  }
80 
82  for (Pointcloud::const_iterator it = other->begin(); it != other->end(); it++) {
83  points.push_back(point3d(*it));
84  }
85  }
86 
87 
88  void Pointcloud::push_back(const Pointcloud& other) {
89  for (Pointcloud::const_iterator it = other.begin(); it != other.end(); it++) {
90  points.push_back(point3d(*it));
91  }
92  }
93 
94  point3d Pointcloud::getPoint(unsigned int i) const{
95  if (i < points.size())
96  return points[i];
97  else {
98  OCTOMAP_WARNING("Pointcloud::getPoint index out of range!\n");
99  return points.back();
100  }
101  }
102 
104 
105  for (unsigned int i=0; i<points.size(); i++) {
106  points[i] = transform.transform(points[i]);
107  }
108 
109  // FIXME: not correct for multiple transforms
111  }
112 
113 
115 
116  // undo previous transform, then apply current transform
118 
119  for (unsigned int i=0; i<points.size(); i++) {
120  points[i] = transf.transform(points[i]);
121  }
122 
124  }
125 
126 
127  void Pointcloud::rotate(double roll, double pitch, double yaw) {
128 
129  for (unsigned int i=0; i<points.size(); i++) {
130  points[i].rotate_IP(roll, pitch, yaw);
131  }
132  }
133 
134 
135  void Pointcloud::calcBBX(point3d& lowerBound, point3d& upperBound) const {
136  float min_x, min_y, min_z;
137  float max_x, max_y, max_z;
138  min_x = min_y = min_z = 1e6;
139  max_x = max_y = max_z = -1e6;
140 
141  float x,y,z;
142 
143  for (Pointcloud::const_iterator it=begin(); it!=end(); it++) {
144 
145  x = (*it)(0);
146  y = (*it)(1);
147  z = (*it)(2);
148 
149  if (x < min_x) min_x = x;
150  if (y < min_y) min_y = y;
151  if (z < min_z) min_z = z;
152 
153  if (x > max_x) max_x = x;
154  if (y > max_y) max_y = y;
155  if (z > max_z) max_z = z;
156  }
157 
158  lowerBound(0) = min_x; lowerBound(1) = min_y; lowerBound(2) = min_z;
159  upperBound(0) = max_x; upperBound(1) = max_y; upperBound(2) = max_z;
160  }
161 
162 
163  void Pointcloud::crop(point3d lowerBound, point3d upperBound) {
164 
165  Pointcloud result;
166 
167  float min_x, min_y, min_z;
168  float max_x, max_y, max_z;
169  float x,y,z;
170 
171  min_x = lowerBound(0); min_y = lowerBound(1); min_z = lowerBound(2);
172  max_x = upperBound(0); max_y = upperBound(1); max_z = upperBound(2);
173 
174  for (Pointcloud::const_iterator it=begin(); it!=end(); it++) {
175  x = (*it)(0);
176  y = (*it)(1);
177  z = (*it)(2);
178 
179  if ( (x >= min_x) &&
180  (y >= min_y) &&
181  (z >= min_z) &&
182  (x <= max_x) &&
183  (y <= max_y) &&
184  (z <= max_z) ) {
185  result.push_back (x,y,z);
186  }
187  } // end for points
188 
189  this->clear();
190  this->push_back(result);
191 
192  }
193 
194 
195  void Pointcloud::minDist(double thres) {
196  Pointcloud result;
197 
198  float x,y,z;
199  for (Pointcloud::const_iterator it=begin(); it!=end(); it++) {
200  x = (*it)(0);
201  y = (*it)(1);
202  z = (*it)(2);
203  double dist = sqrt(x*x+y*y+z*z);
204  if ( dist > thres ) result.push_back (x,y,z);
205  } // end for points
206  this->clear();
207  this->push_back(result);
208  }
209 
210 
211  void Pointcloud::subSampleRandom(unsigned int num_samples, Pointcloud& sample_cloud) {
212  point3d_collection samples;
213  // visual studio does not support random_sample_n and neither does libc++
214  #if defined(_MSC_VER) || defined(_LIBCPP_VERSION)
215  samples.reserve(this->size());
216  samples.insert(samples.end(), this->begin(), this->end());
217  #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201103L) || __cplusplus >= 201103L)
218  std::random_device r;
219  std::mt19937 urbg(r());
220  std::shuffle(samples.begin(), samples.end(), urbg);
221  #else
222  std::random_shuffle(samples.begin(), samples.end());
223  #endif
224  samples.resize(num_samples);
225  #else
226  random_sample_n(begin(), end(), std::back_insert_iterator<point3d_collection>(samples), num_samples);
227  for (unsigned int i=0; i<samples.size(); i++) {
228  sample_cloud.push_back(samples[i]);
229  }
230  #endif
231  }
232 
233 
234  void Pointcloud::writeVrml(std::string filename){
235 
236  std::ofstream outfile (filename.c_str());
237 
238  outfile << "#VRML V2.0 utf8" << std::endl;
239  outfile << "Transform {" << std::endl;
240  outfile << "translation 0 0 0" << std::endl;
241  outfile << "rotation 0 0 0 0" << std::endl;
242  outfile << " children [" << std::endl;
243  outfile << " Shape{" << std::endl;
244  outfile << " geometry PointSet {" << std::endl;
245  outfile << " coord Coordinate {" << std::endl;
246  outfile << " point [" << std::endl;
247 
248  OCTOMAP_DEBUG_STR("PointCloud::writeVrml writing "
249  << points.size() << " points to "
250  << filename.c_str() << ".");
251 
252  for (unsigned int i = 0; i < (points.size()); i++){
253  outfile << "\t\t" << (points[i])(0)
254  << " " << (points[i])(1)
255  << " " << (points[i])(2)
256  << "\n";
257  }
258 
259  outfile << " ]" << std::endl;
260  outfile << " }" << std::endl;
261  outfile << " color Color{" << std::endl;
262  outfile << " color [" << std::endl;
263 
264  for (unsigned int i = 0; i < points.size(); i++){
265  outfile << "\t\t 1.0 1.0 1.0 \n";
266  }
267 
268  outfile << " ]" << std::endl;
269  outfile << " }" << std::endl;
270 
271  outfile << " }" << std::endl;
272  outfile << " }" << std::endl;
273 
274 
275  outfile << " ]" << std::endl;
276  outfile << "}" << std::endl;
277 
278 
279  }
280 
281  std::istream& Pointcloud::read(std::istream &s){
282  while (!s.eof()){
283  point3d p;
284  for (unsigned int i=0; i<3; i++){
285  s >> p(i);
286  }
287  if (!s.fail()){
288  this->push_back(p);
289  } else {
290  break;
291  }
292  }
293 
294  return s;
295  }
296 
297  std::istream& Pointcloud::readBinary(std::istream &s) {
298 
299  uint32_t pc_size = 0;
300  s.read((char*)&pc_size, sizeof(pc_size));
301  OCTOMAP_DEBUG("Reading %d points from binary file...", pc_size);
302 
303  if (pc_size > 0) {
304  this->points.reserve(pc_size);
305  point3d p;
306  for (uint32_t i=0; i<pc_size; i++) {
307  p.readBinary(s);
308  if (!s.fail()) {
309  this->push_back(p);
310  }
311  else {
312  OCTOMAP_ERROR("Pointcloud::readBinary: ERROR.\n" );
313  break;
314  }
315  }
316  }
317  assert(pc_size == this->size());
318 
319  OCTOMAP_DEBUG("done.\n");
320 
321  return s;
322  }
323 
324 
325  std::ostream& Pointcloud::writeBinary(std::ostream &s) const {
326 
327  // check if written unsigned int can hold size
328  size_t orig_size = this->size();
329  if (orig_size > std::numeric_limits<uint32_t>::max()){
330  OCTOMAP_ERROR("Pointcloud::writeBinary ERROR: Point cloud too large to be written");
331  return s;
332  }
333 
334  uint32_t pc_size = static_cast<uint32_t>(this->size());
335  OCTOMAP_DEBUG("Writing %u points to binary file...", pc_size);
336  s.write((char*)&pc_size, sizeof(pc_size));
337 
338  for (Pointcloud::const_iterator it = this->begin(); it != this->end(); it++) {
339  it->writeBinary(s);
340  }
341  OCTOMAP_DEBUG("done.\n");
342 
343  return s;
344  }
345 
346  std::istream &Pointcloud::readPCD(std::istream &s) {
347  // Check if the input stream is valid
348  if (!s.good()) {
349  throw std::runtime_error("Invalid input stream for PCD reading.");
350  }
351 
352  // Variables to store header information
353  std::string line;
354  int width = 0; // Number of points per row (for organized clouds)
355  int height = 0; // Number of rows (1 for unorganized clouds)
356  int points_count = 0; // Total number of points
357  bool data_ascii = false; // Flag for ASCII data type
358  bool header_read = false; // Flag to indicate header parsing completion
359 
360  // Parse the header line by line
361  while (std::getline(s, line)) {
362  if (line.find("VERSION") == 0) {
363  // Skip VERSION field (not used in this implementation)
364  continue;
365  } else if (line.find("FIELDS") == 0) {
366  // Parse FIELDS to ensure only x, y, z are present
367  std::stringstream ss(line);
368  std::string word;
369  ss >> word; // Skip "FIELDS"
370  std::string field;
371  while (ss >> field) {
372  if (field != "x" && field != "y" && field != "z") {
373  OCTOMAP_WARNING("readPCD: Unsupported field in PCD file: %s\n",
374  field.c_str());
375  }
376  }
377  } else if (line.find("SIZE") == 0) {
378  // Skip SIZE (assume 4 bytes for float)
379  continue;
380  } else if (line.find("TYPE") == 0) {
381  // Skip TYPE (assume float)
382  continue;
383  } else if (line.find("COUNT") == 0) {
384  // Skip COUNT (assume 1 element per field)
385  continue;
386  } else if (line.find("WIDTH") == 0) {
387  // Read width
388  std::stringstream ss(line);
389  std::string word;
390  ss >> word >> width;
391  } else if (line.find("HEIGHT") == 0) {
392  // Read height
393  std::stringstream ss(line);
394  std::string word;
395  ss >> word >> height;
396  } else if (line.find("VIEWPOINT") == 0) {
397  // Skip VIEWPOINT (not used)
398  continue;
399  } else if (line.find("POINTS") == 0) {
400  // Read total number of points
401  std::stringstream ss(line);
402  std::string word;
403  ss >> word >> points_count;
404  } else if (line.find("DATA") == 0) {
405  // Parse DATA type
406  std::stringstream ss(line);
407  std::string word, data_type;
408  ss >> word >> data_type;
409  if (data_type == "ascii") {
410  data_ascii = true;
411  } else {
412  throw std::runtime_error(
413  "readPCD: Unsupported data type: " + data_type +
414  ". Only ASCII supported in this implementation.");
415  }
416  header_read = true;
417  break; // Header complete, proceed to data
418  }
419  if (s.eof()) {
420  break; // End of stream reached
421  }
422  }
423 
424  // Validate header completion
425  if (!header_read) {
426  throw std::runtime_error(
427  "readPCD: Incomplete or missing header in PCD data.");
428  }
429 
430  // Calculate points_count if not provided but width and height are
431  if (points_count == 0 && width > 0 && height > 0) {
432  points_count = width * height;
433  }
434 
435  OCTOMAP_DEBUG("readPCD: Reading %d points from PCD stream.\n",
436  points_count);
437 
438  // Read ASCII point data
439  if (data_ascii) {
440  this->points.reserve(points_count); // Pre-allocate space for efficiency
441  float x, y, z;
442  for (int i = 0; i < points_count; ++i) {
443  if (!(s >> x >> y >> z)) {
444  if (s.eof()) {
445  OCTOMAP_WARNING("readPCD: End of stream reached before reading all "
446  "%d points.\n",
447  points_count);
448  break;
449  } else {
450  throw std::runtime_error(
451  "readPCD: Error reading point data from PCD stream.");
452  }
453  }
454  this->push_back(x, y, z); // Add point to the Pointcloud
455  }
456  } else {
457  throw std::runtime_error("readPCD: Binary PCD files are not supported in "
458  "this implementation.");
459  }
460 
461  // Verify the number of points read
462  if (this->size() != static_cast<size_t>(points_count)) {
463  OCTOMAP_WARNING("readPCD: Read %zu points, expected %d.\n", this->size(),
464  points_count);
465  }
466 
467  OCTOMAP_DEBUG("readPCD: Done reading PCD stream.\n");
468 
469  return s; // Return the stream for chaining
470  }
471 
472 } // end namespace
octomap::Pointcloud::points
point3d_collection points
Definition: Pointcloud.h:121
octomap::Pointcloud::readBinary
std::istream & readBinary(std::istream &s)
Definition: Pointcloud.cpp:297
octomap::Pointcloud
Definition: Pointcloud.h:47
octomap::Pointcloud::calcBBX
void calcBBX(point3d &lowerBound, point3d &upperBound) const
Calculate bounding box of Pointcloud.
Definition: Pointcloud.cpp:135
octomap::Pointcloud::crop
void crop(point3d lowerBound, point3d upperBound)
Crop Pointcloud to given bounding box.
Definition: Pointcloud.cpp:163
octomap::Pointcloud::push_back
void push_back(float x, float y, float z)
Definition: Pointcloud.h:61
octomap::Pointcloud::getPoint
point3d getPoint(unsigned int i) const
Definition: Pointcloud.cpp:94
octomap::Pointcloud::clear
void clear()
Definition: Pointcloud.cpp:66
OCTOMAP_DEBUG
#define OCTOMAP_DEBUG(...)
Definition: octomap_types.h:72
octomap::Pointcloud::~Pointcloud
~Pointcloud()
Definition: Pointcloud.cpp:62
OCTOMAP_DEBUG_STR
#define OCTOMAP_DEBUG_STR(args)
Definition: octomap_types.h:73
octomath::Vector3
This class represents a three-dimensional vector.
Definition: Vector3.h:50
octomap::Pointcloud::subSampleRandom
void subSampleRandom(unsigned int num_samples, Pointcloud &sample_cloud)
Definition: Pointcloud.cpp:211
octomap::Pointcloud::writeBinary
std::ostream & writeBinary(std::ostream &s) const
Definition: Pointcloud.cpp:325
octomath::Pose6D::transform
Vector3 transform(const Vector3 &v) const
Transformation of a vector.
Definition: Pose6D.cpp:85
octomap::Pointcloud::writeVrml
void writeVrml(std::string filename)
Export the Pointcloud to a VRML file.
Definition: Pointcloud.cpp:234
octomap::Pointcloud::rotate
void rotate(double roll, double pitch, double yaw)
Rotate each point in pointcloud.
Definition: Pointcloud.cpp:127
octomap::Pointcloud::current_inv_transform
pose6d current_inv_transform
Definition: Pointcloud.h:120
octomap::Pointcloud::read
std::istream & read(std::istream &s)
Definition: Pointcloud.cpp:281
OCTOMAP_ERROR
#define OCTOMAP_ERROR(...)
Definition: octomap_types.h:78
octomap::Pointcloud::readPCD
std::istream & readPCD(std::istream &s)
Definition: Pointcloud.cpp:346
octomap::Pointcloud::transform
void transform(pose6d transform)
Apply transform to each point.
Definition: Pointcloud.cpp:103
octomap::point3d_collection
std::vector< octomath::Vector3 > point3d_collection
Definition: octomap_types.h:53
octomath::Vector3::readBinary
std::istream & readBinary(std::istream &s)
Definition: Vector3.cpp:87
Pointcloud.h
octomap::Pointcloud::minDist
void minDist(double thres)
Definition: Pointcloud.cpp:195
OCTOMAP_WARNING
#define OCTOMAP_WARNING(...)
Definition: octomap_types.h:76
octomap::Pointcloud::Pointcloud
Pointcloud()
Definition: Pointcloud.cpp:58
octomap::Pointcloud::begin
iterator begin()
Definition: Pointcloud.h:100
octomap::Pointcloud::const_iterator
point3d_collection::const_iterator const_iterator
Definition: Pointcloud.h:99
octomap
octomath::Pose6D
This class represents a tree-dimensional pose of an object.
Definition: Pose6D.h:49
octomap::Pointcloud::transformAbsolute
void transformAbsolute(pose6d transform)
Apply transform to each point, undo previous transforms.
Definition: Pointcloud.cpp:114
octomap::point3d
octomath::Vector3 point3d
Use Vector3 (float precision) as a point3d in octomap.
Definition: octomap_types.h:49
octomap::Pointcloud::size
size_t size() const
Definition: Pointcloud.h:57
octomap::Pointcloud::end
iterator end()
Definition: Pointcloud.h:101


octomap
Author(s): Kai M. Wurm , Armin Hornung
autogenerated on Mon Apr 21 2025 02:39:48