ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
Cloud2CloudDist.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 "Cloud2CloudDist.h"
9 
10 // system
11 #include <cmath>
12 
13 // For each lidar point, we find its neibors in cloth particles by Rounding
14 // operation.
15 // use for neighbor particles to do bilinear interpolation.
16 #if 1
17 
18 bool Cloud2CloudDist::Compute(const Cloth& cloth,
19  const wl::PointCloud& pc,
20  double class_threshold,
21  std::vector<int>& groundIndexes,
22  std::vector<int>& offGroundIndexes,
23  unsigned N /*=3*/) {
24  try {
25  // Find the direct distance between each lidar point and the cloth, and
26  // use this distance threshold to classify the point cloud Bilinear
27  // interpolation for each lidar point, find the projection in the cloth
28  // grid, and the sub grid which contains it.
29  // use the four corner of the subgrid to do bilinear interpolation;
30  for (int i = 0; i < pc.size(); i++) {
31  double pc_x = pc[i].x;
32  double pc_z = pc[i].z;
33  // Subtract this coordinate from the upper left corner of the cloth
34  double deltaX = pc_x - cloth.origin_pos.x;
35  double deltaZ = pc_z - cloth.origin_pos.z;
36  // Get the coordinates of the upper left corner of the small cloth
37  // grid where the laser point is located. Assuming that the four
38  // corner points are respectively 0 1 2 3 and numbered clockwise
39  int col0 = int(deltaX / cloth.step_x);
40  int row0 = int(deltaZ / cloth.step_y);
41  int col1 = col0 + 1;
42  int row1 = row0;
43  int col2 = col0 + 1;
44  int row2 = row0 + 1;
45  int col3 = col0;
46  int row3 = row0 + 1;
47  // Establish a coordinate system with the upper left corner of the
48  // sub-grid and normalize it to [0,1]
49  double subdeltaX = (deltaX - col0 * cloth.step_x) / cloth.step_x;
50  double subdeltaZ = (deltaZ - row0 * cloth.step_y) / cloth.step_y;
51  // cout << subdeltaX << " " << subdeltaZ << endl;
52  // bilinear interpolation;
53  // f(x,y)=f(0,0)(1-x)(1-y)+f(0,1)(1-x)y+f(1,1)xy+f(1,0)x(1-y)
54  double fxy = cloth.getParticle(col0, row0).pos.y * (1 - subdeltaX) *
55  (1 - subdeltaZ) +
56  cloth.getParticle(col3, row3).pos.y * (1 - subdeltaX) *
57  subdeltaZ +
58  cloth.getParticle(col2, row2).pos.y * subdeltaX *
59  subdeltaZ +
60  cloth.getParticle(col1, row1).pos.y * subdeltaX *
61  (1 - subdeltaZ);
62  double height_var = fxy - pc[i].y;
63  if (std::fabs(height_var) < class_threshold) {
64  groundIndexes.push_back(i);
65  } else {
66  offGroundIndexes.push_back(i);
67  }
68  }
69  } catch (const std::bad_alloc&) {
70  // not enough memory
71  return false;
72  }
73 
74  return true;
75 }
76 
77 #else
78 
79 // CGAL //CGAL is much slower for this operation
80 #include <CGAL/Orthogonal_k_neighbor_search.h>
81 #include <CGAL/Search_traits_2.h>
82 #include <CGAL/Simple_cartesian.h>
83 #include <CGAL/point_generators_2.h>
84 
85 typedef CGAL::Simple_cartesian<double> K;
86 typedef K::Point_2 Point_d;
87 typedef CGAL::Search_traits_2<K> TreeTraits;
88 typedef CGAL::Orthogonal_k_neighbor_search<TreeTraits> Neighbor_search;
89 typedef Neighbor_search::Tree Tree;
90 
91 bool Cloud2CloudDist::Compute(const Cloth& cloth,
92  const wl::PointCloud& pc,
93  double class_threshold,
94  std::vector<int>& groundIndexes,
95  std::vector<int>& offGroundIndexes,
96  unsigned N /*=3*/) {
97  try {
98  std::list<Point_d> points_2d;
99  std::map<std::string, double> mapstring;
100 
101  // maping coordinates xy->z to query the height value of each point
102  for (int i = 0; i < cloth.getSize(); i++) {
103  const Particle& particle = cloth.getParticleByIndex(i);
104  std::ostringstream ostrx, ostrz;
105  ostrx << particle.pos.x;
106  ostrz << particle.pos.z;
107  mapstring.insert(std::pair<std::string, double>(
108  ostrx.str() + ostrz.str(), particle.pos.y));
109  points_2d.push_back(Point_d(particle.pos.x, particle.pos.z));
110  }
111 
112  Tree tree(points_2d.begin(), points_2d.end());
113  // step two query the nearest point of cloth for each terrain point
114  for (int i = 0; i < pc.size(); i++) {
115  Point_d query(pc[i].x, pc[i].z);
116  Neighbor_search search(tree, query, N);
117  double search_min = 0;
118  for (Neighbor_search::iterator it = search.begin();
119  it != search.end(); it++) {
120  std::ostringstream ostrx, ostrz;
121  ostrx << it->first.x();
122  ostrz << it->first.y();
123  double y = mapstring[ostrx.str() + ostrz.str()];
124  search_min = search_min + y / N;
125  // if (y > search_min)
126  //{
127  // search_min = y;
128  // }
129  }
130  if (std::fabs(search_min - pc[i].y) < class_threshold) {
131  groundIndexes.push_back(i);
132  } else {
133  offGroundIndexes.push_back(i);
134  }
135  }
136  } catch (const std::bad_alloc&) {
137  // not enough memory
138  return false;
139  }
140 
141  return true;
142 }
143 
144 // cloudViewer is always much faster
145 
146 // CC_CORE_LIB
147 #include <DgmOctree.h>
149 #include <ReferenceCloud.h>
150 #include <SimpleCloud.h>
151 
152 #include <QThread>
153 
154 static bool ComputeMeanNeighborAltitude(
156  void** additionalParameters,
158  // additional parameters
159  const Cloth& cloth = *(const Cloth*)additionalParameters[0];
160  const cloudViewer::DgmOctree* particleOctree =
161  (cloudViewer::DgmOctree*)additionalParameters[1];
162  unsigned N = *(unsigned*)additionalParameters[2];
163 
164  // structure for the nearest neighbor search
166  nNSS.level = cell.level;
167  nNSS.minNumberOfNeighbors = N;
168  particleOctree->getCellPos(cell.truncatedCode, cell.level, nNSS.cellPos,
169  true);
170  particleOctree->computeCellCenter(nNSS.cellPos, cell.level,
171  nNSS.cellCenter);
172 
173  // for each point of the cloud we look for its nearest neighbours in the
174  // set of particles
175  unsigned pointCount = cell.points->size();
176  for (unsigned i = 0; i < pointCount; i++) {
177  // find the nearest particles around the current point
178  cell.points->getPoint(i, nNSS.queryPoint);
179 
180  unsigned n = particleOctree->findNearestNeighborsStartingFromCell(nNSS);
181  unsigned kNN = std::min(N, n);
182  if (kNN == 0) {
183  assert(false);
184  continue;
185  }
186 
187  // compute the average height
188  double search_min = 0;
189  for (unsigned k = 0; k < kNN; ++k) {
190  unsigned particleIndex = nNSS.pointsInNeighbourhood[k].pointIndex;
191  double y = cloth.getParticleByIndex(particleIndex).pos.y;
192  search_min += y;
193  }
194  search_min /= kNN;
195 
196  cell.points->setPointScalarValue(i,
197  static_cast<ScalarType>(search_min));
198  }
199 
200  return true;
201 }
202 
203 bool Cloud2CloudDist::Compute(const Cloth& cloth,
204  s const wl::PointCloud& pc,
205  double class_threshold,
206  std::vector<int>& groundIndexes,
207  std::vector<int>& offGroundIndexes,
208  unsigned N /*=3*/) {
209  cloudViewer::SimpleCloud particlePoints;
210  if (!particlePoints.reserve(static_cast<unsigned>(cloth.getSize()))) {
211  // not enough memory
212  return false;
213  }
214  for (int i = 0; i < cloth.getSize(); i++) {
215  const Particle& particle = cloth.getParticleByIndex(i);
216  particlePoints.addPoint(
217  CCVector3(static_cast<PointCoordinateType>(particle.pos.x), 0,
218  static_cast<PointCoordinateType>(particle.pos.z)));
219  }
220 
221  cloudViewer::SimpleCloud pcPoints;
222  if (!pcPoints.reserve(static_cast<unsigned>(pc.size())) ||
223  !pcPoints.enableScalarField()) {
224  // not enough memory
225  return false;
226  }
227  for (size_t i = 0; i < pc.size(); i++) {
228  const wl::Point& P = pc[i];
229  pcPoints.addPoint(CCVector3(P.x, 0, P.z));
230  }
231 
232  try {
233  // we spatially 'synchronize' the cloud and particles octrees
234  cloudViewer::DgmOctree *cloudOctree = 0, *particleOctree = 0;
237  &particlePoints, &pcPoints, particleOctree, cloudOctree,
238  0, 0);
239 
242  // not enough memory (or invalid input)
243  return false;
244  }
245 
246  // additional parameters
247  void* additionalParameters[] = {(void*)(&cloth),
248  (void*)(particleOctree), (void*)(&N)};
249 
250  int octreeLevel =
252  std::max<unsigned>(2, N));
253 
254  int result = cloudOctree->executeFunctionForAllCellsAtLevel(
255  octreeLevel, ComputeMeanNeighborAltitude, additionalParameters,
256  true, 0, "Rasterization", QThread::idealThreadCount());
257 
258  delete cloudOctree;
259  cloudOctree = 0;
260 
261  delete particleOctree;
262  particleOctree = 0;
263 
264  if (result == 0) {
265  // something went wrong
266  return false;
267  }
268 
269  // now classify the points
270  for (unsigned i = 0; i < pcPoints.size(); ++i) {
271  if (std::fabs(pcPoints.getPointScalarValue(i) - pc[i].y) <
272  class_threshold) {
273  groundIndexes.push_back(i);
274  } else {
275  offGroundIndexes.push_back(i);
276  }
277  }
278 
279  } catch (const std::bad_alloc&) {
280  // not enough memory
281  return false;
282  }
283 
284  return true;
285 }
286 
287 #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
core::Tensor result
Definition: VtkUtils.cpp:76
static double class_threshold
Definition: ccCSFDlg.cpp:15
Definition: Cloth.h:44
Particle & getParticleByIndex(int index)
Definition: Cloth.h:83
int getSize() const
Definition: Cloth.h:93
double step_y
Definition: Cloth.h:91
Vec3 origin_pos
Definition: Cloth.h:90
Particle & getParticle(int x, int y)
Definition: Cloth.h:77
double step_x
Definition: Cloth.h:91
static bool Compute(const Cloth &cloth, const wl::PointCloud &pc, double class_threshold, std::vector< int > &groundIndexes, std::vector< int > &offGroundIndexes, unsigned N=3)
Vec3 pos
Definition: Particle.h:38
double z
Definition: Vec3.h:18
double y
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
unsigned executeFunctionForAllCellsAtLevel(unsigned char level, octreeCellFunc func, void **additionalParameters, bool multiThread=false, GenericProgressCallback *progressCb=nullptr, const char *functionTitle=nullptr, int maxThreadCount=0)
Definition: DgmOctree.cpp:3573
unsigned char findBestLevelForAGivenPopulationPerCell(unsigned indicativeNumberOfPointsPerCell) const
Definition: DgmOctree.cpp:2737
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.
void setPointScalarValue(unsigned pointIndex, ScalarType value) override
Sets the ith point associated scalar value.
unsigned size() const override
Returns the number of points.
const CCVector3 * getPoint(unsigned index) const override
Returns the ith point.
__host__ __device__ float2 fabs(float2 v)
Definition: cutil_math.h:1254
int min(int a, int b)
Definition: cutil_math.h:53
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