ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
Rasterization.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 #include "Rasterization.h"
9 
10 #include <iostream>
11 #include <queue>
12 
13 using namespace std;
14 
15 // Since all the particles in cloth are formed as a regular grid,
16 // for each lidar point, its nearest Cloth point can be simply found by Rounding
17 // operation then record all the correspoinding lidar point for each cloth
18 // particle
19 
20 #if 1
21 
23  int xpos = p->pos_x;
24  int ypos = p->pos_y;
25  // Scan to the right
26  for (int i = xpos + 1; i < cloth.num_particles_width; i++) {
27  double crresHeight = cloth.getParticle(i, ypos).nearestPointHeight;
28  if (crresHeight > MIN_INF) return crresHeight;
29  }
30  // Scan to the left
31  for (int i = xpos - 1; i >= 0; i--) {
32  double crresHeight = cloth.getParticle(i, ypos).nearestPointHeight;
33  if (crresHeight > MIN_INF) return crresHeight;
34  }
35  // Scan vertically upward
36  for (int j = ypos - 1; j >= 0; j--) {
37  double crresHeight = cloth.getParticle(xpos, j).nearestPointHeight;
38  if (crresHeight > MIN_INF) return crresHeight;
39  }
40  // Scan vertically down
41  for (int j = ypos + 1; j < cloth.num_particles_height; j++) {
42  double crresHeight = cloth.getParticle(xpos, j).nearestPointHeight;
43  if (crresHeight > MIN_INF) return crresHeight;
44  }
45 
46  return findHeightValByNeighbor(p, cloth);
47 }
48 
50  queue<Particle *> nqueue;
51  vector<Particle *> pbacklist;
52  size_t neiborsize = p->neighborsList.size();
53  for (size_t i = 0; i < neiborsize; i++) {
54  p->isVisited = true;
55  nqueue.push(p->neighborsList[i]);
56  }
57 
58  // iterate over the nqueue
59  while (!nqueue.empty()) {
60  Particle *pneighbor = nqueue.front();
61  nqueue.pop();
62  pbacklist.push_back(pneighbor);
63  if (pneighbor->nearestPointHeight > MIN_INF) {
64  for (int i = 0; i < pbacklist.size(); i++)
65  pbacklist[i]->isVisited = false;
66  while (!nqueue.empty()) {
67  Particle *pp = nqueue.front();
68  pp->isVisited = false;
69  nqueue.pop();
70  }
71  return pneighbor->nearestPointHeight;
72  } else {
73  size_t nsize = pneighbor->neighborsList.size();
74  for (size_t i = 0; i < nsize; i++) {
75  Particle *ptmp = pneighbor->neighborsList[i];
76  if (!ptmp->isVisited) {
77  ptmp->isVisited = true;
78  nqueue.push(ptmp);
79  }
80  }
81  }
82  }
83  return MIN_INF;
84 }
85 
87  const wl::PointCloud &pc,
88  std::vector<double> &heightVal,
89  unsigned KNN) {
90  try {
91  // find the nearest cloth particle for each lidar point by Rounding
92  // operation
93  for (int i = 0; i < pc.size(); i++) {
94  double pc_x = pc[i].x;
95  double pc_z = pc[i].z;
96  // minus the top-left corner of the cloth
97  double deltaX = pc_x - cloth.origin_pos.x;
98  double deltaZ = pc_z - cloth.origin_pos.z;
99  int col = int(deltaX / cloth.step_x + 0.5);
100  int row = int(deltaZ / cloth.step_y + 0.5);
101  if (col >= 0 && row >= 0) {
102  Particle &pt = cloth.getParticle(col, row);
103  // Particle pt = cloth.getParticle(col, row); this give wrong
104  // results, since it made a copy
105  pt.correspondingLidarPointList.push_back(i);
106  double pc2particleDist =
107  SQUARE_DIST(pc_x, pc_z, pt.pos.x, pt.pos.z);
108  if (pc2particleDist < pt.tmpDist) {
109  pt.tmpDist = pc2particleDist;
110  pt.nearestPointHeight = pc[i].y;
111  pt.nearestPointIndex = i;
112  }
113  }
114  }
115 
116  heightVal.resize(cloth.getSize());
117  // #pragma omp parallel for
118  for (int i = 0; i < cloth.getSize(); i++) {
119  Particle &pcur = cloth.getParticleByIndex(i);
120  double nearestHeight = pcur.nearestPointHeight;
121 
122  if (nearestHeight > MIN_INF) {
123  heightVal[i] = nearestHeight;
124  } else {
125  heightVal[i] = findHeightValByScanline(&pcur, cloth);
126  }
127  }
128  } catch (const std::bad_alloc &) {
129  // not enough memory
130  return false;
131  }
132 
133  return true;
134 }
135 
136 #else
137 
138 // CGAL is slow but more stable, especially when the point cloud is sparse
139 // (relatively to the rectangular raster grid!)
140 #include <CGAL/Orthogonal_k_neighbor_search.h>
141 #include <CGAL/Search_traits_2.h>
142 #include <CGAL/Simple_cartesian.h>
143 #include <CGAL/point_generators_2.h>
144 
145 typedef CGAL::Simple_cartesian<double> K;
146 typedef K::Point_2 Point_d;
147 typedef CGAL::Search_traits_2<K> TreeTraits;
148 typedef CGAL::Orthogonal_k_neighbor_search<TreeTraits> Neighbor_search;
149 typedef Neighbor_search::Tree Tree;
150 
152  const wl::PointCloud& pc,
153  std::vector<double>& heightVal,
154  unsigned KNN) {
155  try {
156  // First establish the mapping xz->y, that is, the coordinates of y can
157  // be found through the coordinates of xz, because all point clouds
158  // cannot have xz coincident
159  std::map<std::string, double> mapstring;
160  std::list<Point_d> points_2d;
161 
162  for (size_t i = 0; i < pc.size(); i++) {
163  std::ostringstream ostrx, ostrz;
164  ostrx << pc[i].x;
165  ostrz << pc[i].z;
166  mapstring.insert(std::pair<std::string, double>(
167  ostrx.str() + ostrz.str(), pc[i].y));
168  points_2d.push_back(Point_d(pc[i].x, pc[i].z));
169  }
170  Tree tree(points_2d.begin(), points_2d.end());
171 
172  heightVal.resize(cloth.getSize());
173  for (int i = 0; i < cloth.getSize(); i++) {
174  const Particle& particle = cloth.getParticleByIndex(i);
175  Point_d query(particle.pos.x, particle.pos.z);
176  Neighbor_search search(tree, query, KNN);
177  double search_max = 0;
178  for (Neighbor_search::iterator it = search.begin();
179  it != search.end(); it++) {
180  std::ostringstream ostrx, ostrz;
181  ostrx << it->first.x();
182  ostrz << it->first.y();
183  double y = mapstring[ostrx.str() + ostrz.str()];
184  if (y > search_max || it == search.begin()) // first value
185  {
186  search_max = y;
187  }
188  }
189  heightVal[i] = search_max;
190  }
191  } catch (const std::bad_alloc&) {
192  // not enough memory
193  return false;
194  }
195 
196  return true;
197 }
198 
199 // we use CC_CORE_LIB --> potentially much faster but very slow when the the
200 // point cloud is sparse (relatively to the rectangular raster grid!)
201 
202 // CC_CORE_LIB
203 #include <DgmOctree.h>
205 #include <ReferenceCloud.h>
206 #include <SimpleCloud.h>
207 
208 #include <QThread>
209 
210 static bool ComputeMaxNeighborAltitude(
212  void** additionalParameters,
214  // additional parameters
215  const wl::PointCloud& pc = *(const wl::PointCloud*)additionalParameters[0];
216  std::vector<double>& heightVal =
217  *(std::vector<double>*)additionalParameters[1];
218  const cloudViewer::DgmOctree* cloudOctree =
219  (cloudViewer::DgmOctree*)additionalParameters[2];
220  unsigned KNN = *(unsigned*)additionalParameters[3];
221 
222  // structure for the nearest neighbor search
224  nNSS.level = cell.level;
225  nNSS.minNumberOfNeighbors = KNN;
226  cloudOctree->getCellPos(cell.truncatedCode, cell.level, nNSS.cellPos, true);
227  cloudOctree->computeCellCenter(nNSS.cellPos, cell.level, nNSS.cellCenter);
228 
229  // for each point of the current cell ('particles' octree) we look for its
230  // nearest neighbours in the point cloud (not too far!)
231  unsigned pointCount = cell.points->size();
232  for (unsigned i = 0; i < pointCount; i++) {
233  // find the nearest points around the current particle
234  cell.points->getPoint(i, nNSS.queryPoint);
235 
236  unsigned n = cloudOctree->findNearestNeighborsStartingFromCell(nNSS);
237 
238  unsigned particleIndex = cell.points->getPointGlobalIndex(i);
239 
240  // determine the (highest) neighbor altitude
241  double search_max = heightVal[particleIndex];
242  for (unsigned k = 0; k < std::min(KNN, n); ++k) {
243  unsigned pointIndex = nNSS.pointsInNeighbourhood[k].pointIndex;
244  if (std::isnan(search_max) || pc[pointIndex].y > search_max) {
245  search_max = pc[pointIndex].y;
246  }
247  }
248  heightVal[particleIndex] = search_max;
249  }
250 
251  return true;
252 }
253 
255  const wl::PointCloud& pc,
256  std::vector<double>& heightVal,
257  unsigned KNN) {
258  cloudViewer::SimpleCloud particlePoints;
259  if (!particlePoints.reserve(static_cast<unsigned>(cloth.getSize()))) {
260  // not enough memory
261  return false;
262  }
263  for (int i = 0; i < cloth.getSize(); i++) {
264  const Particle& particle = cloth.getParticleByIndex(i);
265  particlePoints.addPoint(
266  CCVector3(static_cast<PointCoordinateType>(particle.pos.x), 0,
267  static_cast<PointCoordinateType>(particle.pos.z)));
268  }
269 
270  // test
271  if (false) {
272  FILE* fp = fopen("particle.asc", "wt");
273  for (unsigned i = 0; i < particlePoints.size(); i++) {
274  const CCVector3* P = particlePoints.getPoint(i);
275  fprintf(fp, "%f %f %f\n", P->x, P->y, P->z);
276  }
277  fclose(fp);
278  }
279 
280  cloudViewer::SimpleCloud pcPoints;
281  if (!pcPoints.reserve(static_cast<unsigned>(pc.size()))) {
282  // not enough memory
283  return false;
284  }
285  for (size_t i = 0; i < pc.size(); i++) {
286  const wl::Point& P = pc[i];
287  pcPoints.addPoint(CCVector3(P.x, 0, P.z));
288  }
289 
290  // test
291  if (false) {
292  FILE* fp = fopen("points.asc", "wt");
293  for (unsigned i = 0; i < pcPoints.size(); i++) {
294  const CCVector3* P = pcPoints.getPoint(i);
295  fprintf(fp, "%f %f %f\n", P->x, P->y, P->z);
296  }
297  fclose(fp);
298  }
299 
300  try {
301  heightVal.resize(cloth.getSize(),
302  std::numeric_limits<double>::quiet_NaN());
303 
304  // we spatially 'synchronize' the cloud and particles octrees
305  cloudViewer::DgmOctree *cloudOctree = 0, *particleOctree = 0;
308  &particlePoints, &pcPoints, particleOctree, cloudOctree,
309  0, 0);
310 
313  // not enough memory (or invalid input)
314  return false;
315  }
316 
317  // additional parameters
318  void* additionalParameters[] = {(void*)(&pc), (void*)(&heightVal),
319  (void*)(cloudOctree), (void*)(&KNN)};
320 
321  int octreeLevel =
322  particleOctree->findBestLevelForAGivenPopulationPerCell(
323  std::max<unsigned>(2, KNN));
324  // int octreeLevel2 =
325  // cloudOctree->findBestLevelForComparisonWithOctree(particleOctree);
326 
327  int result = particleOctree->executeFunctionForAllCellsAtLevel(
328  octreeLevel, ComputeMaxNeighborAltitude, additionalParameters,
329  true, 0, "Rasterization", QThread::idealThreadCount());
330 
331  delete cloudOctree;
332  cloudOctree = 0;
333 
334  delete particleOctree;
335  particleOctree = 0;
336 
337  if (result == 0) {
338  // something went wrong
339  return false;
340  }
341  } catch (const std::bad_alloc&) {
342  // not enough memory
343  return false;
344  }
345 
346  return true;
347 }
348 
349 #endif
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
#define MIN_INF
Definition: Particle.h:16
#define SQUARE_DIST(x1, y1, x2, y2)
Definition: Rasterization.h:13
core::Tensor result
Definition: VtkUtils.cpp:76
Definition: Cloth.h:44
Particle & getParticleByIndex(int index)
Definition: Cloth.h:83
int getSize() const
Definition: Cloth.h:93
int num_particles_width
Definition: Cloth.h:88
double step_y
Definition: Cloth.h:91
int num_particles_height
Definition: Cloth.h:89
Vec3 origin_pos
Definition: Cloth.h:90
Particle & getParticle(int x, int y)
Definition: Cloth.h:77
double step_x
Definition: Cloth.h:91
int pos_x
Definition: Particle.h:35
double nearestPointHeight
Definition: Particle.h:52
double tmpDist
Definition: Particle.h:54
int pos_y
Definition: Particle.h:36
std::vector< int > correspondingLidarPointList
Definition: Particle.h:48
std::size_t nearestPointIndex
Definition: Particle.h:50
bool isVisited
Definition: Particle.h:33
Vec3 pos
Definition: Particle.h:38
std::vector< Particle * > neighborsList
Definition: Particle.h:44
static double findHeightValByNeighbor(Particle *p, Cloth &cloth)
static bool RasterTerrain(Cloth &cloth, const wl::PointCloud &pc, std::vector< double > &heightVal, unsigned KNN=1)
static double findHeightValByScanline(Particle *p, Cloth &cloth)
Type y
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
double z
Definition: Vec3.h:18
double x
Definition: Vec3.h:18
The octree structure used throughout the library.
Definition: DgmOctree.h:39
void getCellPos(CellCode code, unsigned char level, Tuple3i &cellPos, bool isCodeTruncated) const
Definition: DgmOctree.cpp:498
unsigned findNearestNeighborsStartingFromCell(NearestNeighboursSearchStruct &nNSS, bool getOnlyPointsWithValidScalar=false) const
Definition: DgmOctree.cpp:1655
void computeCellCenter(CellCode code, unsigned char level, CCVector3 &center, bool isCodeTruncated=false) const
Definition: DgmOctree.h:862
SOReturnCode
Return codes for DistanceComputationTools::synchronizeOctrees.
static SOReturnCode synchronizeOctrees(GenericIndexedCloudPersist *comparedCloud, GenericIndexedCloudPersist *referenceCloud, DgmOctree *&comparedOctree, DgmOctree *&referenceOctree, PointCoordinateType maxSearchDist=0, GenericProgressCallback *progressCb=nullptr)
Synchronizes (and re-build if necessary) two octrees.
unsigned size() const override
Returns the number of points.
virtual unsigned getPointGlobalIndex(unsigned localIndex) const
const CCVector3 * getPoint(unsigned index) const override
Returns the ith point.
int min(int a, int b)
Definition: cutil_math.h:53
Definition: Eigen.h:85
cloudViewer::NormalizedProgress * nProgress
unsigned char octreeLevel
Container of in/out parameters for nearest neighbour(s) search.
Definition: DgmOctree.h:161
unsigned char level
Level of subdivision of the octree at which to start the search.
Definition: DgmOctree.h:171
Tuple3i cellPos
Position in the octree of the cell including the query point.
Definition: DgmOctree.h:184
CCVector3 cellCenter
Coordinates of the center of the cell including the query point.
Definition: DgmOctree.h:189
unsigned minNumberOfNeighbors
Minimal number of neighbours to find.
Definition: DgmOctree.h:177
Octree cell descriptor.
Definition: DgmOctree.h:354
ReferenceCloud * points
Set of points lying inside this cell.
Definition: DgmOctree.h:365
unsigned char level
Cell level of subdivision.
Definition: DgmOctree.h:367
CellCode truncatedCode
Truncated cell code.
Definition: DgmOctree.h:361
Point type.
Definition: wlPointCloud.h:15