ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
PoissonReconLib.cpp
Go to the documentation of this file.
1 // ##########################################################################
2 // # #
3 // # ACloudViewer WRAPPER: PoissonReconLib #
4 // # #
5 // # This program is free software; you can redistribute it and/or modify #
6 // # it under the terms of the GNU General Public License as published by #
7 // # the Free Software Foundation; version 2 or later of the License. #
8 // # #
9 // # This program is distributed in the hope that it will be useful, #
10 // # but WITHOUT ANY WARRANTY; without even the implied warranty of #
11 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
12 // # GNU General Public License for more details. #
13 // # #
14 // # COPYRIGHT: Daniel Girardeau-Montaut #
15 // # #
16 // ##########################################################################
17 
18 #include "PoissonReconLib.h"
19 
20 // PoissonRecon
21 #include <cassert>
22 
23 #include "../Src/FEMTree.h"
24 #include "PointData.h"
25 
26 namespace {
27 // The order of the B-Spline used to splat in data for color interpolation
28 constexpr int DATA_DEGREE = 0;
29 // The order of the B-Spline used to splat in the weights for density estimation
30 constexpr int WEIGHT_DEGREE = 2;
31 // The order of the B-Spline used to splat in the normals for constructing the
32 // Laplacian constraints
33 constexpr int NORMAL_DEGREE = 2;
34 // The default finite-element degree
35 constexpr int DEFAULT_FEM_DEGREE = 1;
36 // The dimension of the system
37 constexpr int DIMENSION = 3;
38 
39 inline float ComputeNorm(const float vec[3]) {
40  return sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]);
41 }
42 
43 inline double ComputeNorm(const double vec[3]) {
44  return sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]);
45 }
46 } // namespace
47 
49 #ifdef WITH_OPENMP
50  threads = omp_get_num_procs();
51 #endif
52 }
53 
54 template <typename _Real>
55 class Vertex : public PointData<_Real> {
56 public:
57  typedef _Real Real;
58 
59  Vertex(const Point<Real, 3>& point)
60  : PointData<Real>(), point(point), w(0) {}
61 
62  Vertex(const Point<Real, 3>& point,
63  const PointData<Real>& data,
64  double _w = 0.0)
65  : PointData<Real>(data.normal, data.color), point(point), w(_w) {}
66 
67  Vertex() : Vertex(Point<Real, 3>(0, 0, 0)) {}
68 
71  point *= s;
72  w *= s;
73 
74  return *this;
75  }
76 
79  point /= s;
80  w /= s;
81  return *this;
82  }
83 
84  Vertex& operator+=(const Vertex& p) {
86  point += p.point;
87  w += p.w;
88 
89  return *this;
90  }
91 
92 public:
93  Point<Real, 3> point;
94  double w;
95 };
96 
97 template <typename Real>
99  : public InputPointStreamWithData<Real, DIMENSION, PointData<Real>> {
100 public:
102  : cloud(_cloud), xform(nullptr), currentIndex(0) {}
103 
104  void reset(void) override { currentIndex = 0; }
105 
106  bool nextPoint(Point<Real, 3>& p, PointData<Real>& d) override {
107  if (currentIndex >= cloud.size()) {
108  return false;
109  }
110  cloud.getPoint(currentIndex, p.coords);
111 
112  if (xform != nullptr) {
113  p = (*xform) * p;
114  }
115 
116  if (cloud.hasNormals()) {
117  cloud.getNormal(currentIndex, d.normal);
118  } else {
119  d.normal[0] = d.normal[1] = d.normal[2];
120  }
121 
122  if (cloud.hasColors()) {
123  cloud.getColor(currentIndex, d.color);
124  } else {
125  d.color[0] = d.color[1] = d.color[2];
126  }
127 
128  currentIndex++;
129  return true;
130  }
131 
132 public:
134  XForm<Real, 4>* xform;
135  size_t currentIndex;
136 };
137 
138 template <unsigned int Dim, class Real>
140  FEMTree<Dim, Real>& tree;
141  double t;
142 
143  FEMTreeProfiler(FEMTree<Dim, Real>& t) : tree(t) {}
144  void start(void) {
145  t = Time(), FEMTree<Dim, Real>::ResetLocalMemoryUsage();
146  }
147  void dumpOutput(const char* header) const {
148  FEMTree<Dim, Real>::MemoryUsage();
149  // if (header) {
150  // utility::LogDebug("{} {} (s), {} (MB) / {} (MB) / {} (MB)",
151  // header, Time() - t, FEMTree<Dim,
152  // Real>::LocalMemoryUsage(), FEMTree<Dim,
153  // Real>::MaxMemoryUsage(),
154  // MemoryInfo::PeakMemoryUsageMB());
155  // }
156  // else {
157  // utility::LogDebug("{} (s), {} (MB) / {} (MB) / {} (MB)", Time()
158  //- t, FEMTree<Dim, Real>::LocalMemoryUsage(),
159  // FEMTree<Dim, Real>::MaxMemoryUsage(),
160  // MemoryInfo::PeakMemoryUsageMB());
161  // }
162  }
163 };
164 
165 template <class Real, unsigned int Dim>
166 XForm<Real, Dim + 1> GetBoundingBoxXForm(Point<Real, Dim> min,
167  Point<Real, Dim> max,
168  Real scaleFactor) {
169  Point<Real, Dim> center = (max + min) / 2;
170  Real scale = max[0] - min[0];
171  for (unsigned int d = 1; d < Dim; d++) {
172  scale = std::max<Real>(scale, max[d] - min[d]);
173  }
174  scale *= scaleFactor;
175  for (unsigned int i = 0; i < Dim; i++) {
176  center[i] -= scale / 2;
177  }
178  XForm<Real, Dim + 1> tXForm = XForm<Real, Dim + 1>::Identity(),
179  sXForm = XForm<Real, Dim + 1>::Identity();
180  for (unsigned int i = 0; i < Dim; i++) {
181  sXForm(i, i) = static_cast<Real>(1. / scale),
182  tXForm(Dim, i) = -center[i];
183  }
184  return sXForm * tXForm;
185 }
186 
187 template <class Real, unsigned int Dim>
188 XForm<Real, Dim + 1> GetBoundingBoxXForm(Point<Real, Dim> min,
189  Point<Real, Dim> max,
190  Real width,
191  Real scaleFactor,
192  int& depth) {
193  // Get the target resolution (along the largest dimension)
194  Real resolution = (max[0] - min[0]) / width;
195  for (unsigned int d = 1; d < Dim; d++) {
196  resolution = std::max<Real>(resolution, (max[d] - min[d]) / width);
197  }
198  resolution *= scaleFactor;
199  depth = 0;
200  while ((1 << depth) < resolution) {
201  depth++;
202  }
203 
204  Point<Real, Dim> center = (max + min) / 2;
205  Real scale = (1 << depth) * width;
206 
207  for (unsigned int i = 0; i < Dim; i++) {
208  center[i] -= scale / 2;
209  }
210  XForm<Real, Dim + 1> tXForm = XForm<Real, Dim + 1>::Identity();
211  XForm<Real, Dim + 1> sXForm = XForm<Real, Dim + 1>::Identity();
212  for (unsigned int i = 0; i < Dim; i++) {
213  sXForm(i, i) = static_cast<Real>(1.0 / scale);
214  tXForm(Dim, i) = -center[i];
215  }
216  return sXForm * tXForm;
217 }
218 
219 template <class Real, unsigned int Dim>
220 XForm<Real, Dim + 1> GetPointXForm(InputPointStream<Real, Dim>& stream,
221  Real width,
222  Real scaleFactor,
223  int& depth) {
224  Point<Real, Dim> min, max;
225  stream.boundingBox(min, max);
226  return GetBoundingBoxXForm(min, max, width, scaleFactor, depth);
227 }
228 
229 template <class Real, unsigned int Dim>
230 XForm<Real, Dim + 1> GetPointXForm(InputPointStream<Real, Dim>& stream,
231  Real scaleFactor) {
232  Point<Real, Dim> min, max;
233  stream.boundingBox(min, max);
234  return GetBoundingBoxXForm(min, max, scaleFactor);
235 }
236 
237 template <unsigned int Dim, typename Real>
239  Real target, weight;
240  ConstraintDual(Real t, Real w) : target(t), weight(w) {}
241  CumulativeDerivativeValues<Real, Dim, 0> operator()(
242  const Point<Real, Dim>& p) const {
243  return CumulativeDerivativeValues<Real, Dim, 0>(target * weight);
244  };
245 };
246 
247 template <unsigned int Dim, typename Real>
248 struct SystemDual {
249  SystemDual(Real w) : weight(w) {}
250  CumulativeDerivativeValues<Real, Dim, 0> operator()(
251  const Point<Real, Dim>& p,
252  const CumulativeDerivativeValues<Real, Dim, 0>& dValues) const {
253  return dValues * weight;
254  };
255 
256  CumulativeDerivativeValues<double, Dim, 0> operator()(
257  const Point<Real, Dim>& p,
258  const CumulativeDerivativeValues<double, Dim, 0>& dValues) const {
259  return dValues * weight;
260  };
261 
262  Real weight;
263 };
264 
265 template <unsigned int Dim>
266 struct SystemDual<Dim, double> {
267  typedef double Real;
268 
269  SystemDual(Real w) : weight(w) {}
270  CumulativeDerivativeValues<Real, Dim, 0> operator()(
271  const Point<Real, Dim>& p,
272  const CumulativeDerivativeValues<Real, Dim, 0>& dValues) const {
273  return dValues * weight;
274  };
275 
277 };
278 
279 template <typename Vertex,
280  typename Real,
281  typename SetVertexFunction,
282  unsigned int... FEMSigs,
283  typename... SampleData>
285  const PoissonReconLib::Parameters& params,
286  UIntPack<FEMSigs...>,
287  std::tuple<SampleData...>,
288  FEMTree<sizeof...(FEMSigs), Real>& tree,
289  const DenseNodeData<Real, UIntPack<FEMSigs...>>& solution,
290  Real isoValue,
291  const std::vector<typename FEMTree<sizeof...(FEMSigs),
292  Real>::PointSample>* samples,
293  std::vector<PointData<Real>>* sampleData,
294  const typename FEMTree<sizeof...(FEMSigs),
295  Real>::template DensityEstimator<WEIGHT_DEGREE>*
296  density,
297  const SetVertexFunction& SetVertex,
298  XForm<Real, sizeof...(FEMSigs) + 1> iXForm,
299  PoissonReconLib::IMesh<Real>& out_mesh) {
300  static const int Dim = sizeof...(FEMSigs);
301  typedef UIntPack<FEMSigs...> Sigs;
302  static const unsigned int DataSig =
303  FEMDegreeAndBType<DATA_DEGREE, BOUNDARY_FREE>::Signature;
304 
305  const bool non_manifold = true;
306  const bool polygon_mesh = false;
307 
308  CoredVectorMeshData<Vertex, node_index_type> mesh;
309 
310  if (samples && sampleData) {
311  typedef typename FEMTree<Dim,
312  Real>::template DensityEstimator<WEIGHT_DEGREE>
313  DensityEstimator;
314 
315  SparseNodeData<ProjectiveData<PointData<Real>, Real>,
316  IsotropicUIntPack<Dim, DataSig>>
317  _sampleData =
318  tree.template setMultiDepthDataField<DataSig, false>(
319  *samples, *sampleData,
320  (DensityEstimator*)nullptr);
321 
322  for (const RegularTreeNode<Dim, FEMTreeNodeData, depth_and_offset_type>*
323  n = tree.tree().nextNode();
324  n; n = tree.tree().nextNode(n)) {
325  ProjectiveData<PointData<Real>, Real>* color = _sampleData(n);
326  if (color)
327  (*color) *= static_cast<Real>(
328  pow(params.colorPullFactor, tree.depth(n)));
329  }
330 
331  IsoSurfaceExtractor<Dim, Real, Vertex>::template Extract<
333  Sigs(), UIntPack<WEIGHT_DEGREE>(), UIntPack<DataSig>(), tree,
334  density, &_sampleData, solution, isoValue, mesh, SetVertex,
335  !params.linearFit, !non_manifold, polygon_mesh, false);
336  } else {
337  IsoSurfaceExtractor<Dim, Real, Vertex>::template Extract<
339  Sigs(), UIntPack<WEIGHT_DEGREE>(), UIntPack<DataSig>(), tree,
340  density, nullptr, solution, isoValue, mesh, SetVertex,
341  !params.linearFit, !non_manifold, polygon_mesh, false);
342  }
343 
344  mesh.resetIterator();
345 
346  for (size_t vidx = 0; vidx < mesh.outOfCorePointCount(); ++vidx) {
347  Vertex v;
348  mesh.nextOutOfCorePoint(v);
349  v.point = iXForm * v.point;
350 
351  out_mesh.addVertex(v.point.coords);
352  if (sampleData) {
353  // out_mesh.addNormal(v.normal);
354  out_mesh.addColor(v.color);
355  }
356  if (params.density) {
357  out_mesh.addDensity(v.w);
358  }
359  }
360 
361  for (size_t tidx = 0; tidx < mesh.polygonCount(); ++tidx) {
362  std::vector<CoredVertexIndex<node_index_type>> triangle;
363  mesh.nextPolygon(triangle);
364  if (triangle.size() == 3) {
365  out_mesh.addTriangle(triangle[0].idx, triangle[1].idx,
366  triangle[2].idx);
367  } else {
368  assert(false);
369  }
370  }
371 }
372 
373 template <class Real, typename... SampleData, unsigned int... FEMSigs>
374 static bool Execute(PointStream<Real>& pointStream,
376  const PoissonReconLib::Parameters& params,
377  UIntPack<FEMSigs...>) {
378  static const int Dim = sizeof...(FEMSigs);
379  typedef UIntPack<FEMSigs...> Sigs;
380  typedef UIntPack<FEMSignature<FEMSigs>::Degree...> Degrees;
381  typedef UIntPack<FEMDegreeAndBType<
382  NORMAL_DEGREE, DerivativeBoundary<FEMSignature<FEMSigs>::BType,
383  1>::BType>::Signature...>
384  NormalSigs;
385  typedef typename FEMTree<Dim,
386  Real>::template DensityEstimator<WEIGHT_DEGREE>
387  DensityEstimator;
388  typedef typename FEMTree<Dim, Real>::template InterpolationInfo<Real, 0>
389  InterpolationInfo;
390 
391  // Compute scaling transformation (and optionally the depth)
392  int depth = params.depth;
393  XForm<Real, Dim + 1> xForm = XForm<Real, Dim + 1>::Identity();
394  {
395  if (params.finestCellWidth > 0) {
396  Real scaleFactor =
397  static_cast<Real>(params.scale > 0 ? params.scale : 1.0);
398  xForm = GetPointXForm<Real, Dim>(pointStream,
399  params.finestCellWidth,
400  scaleFactor, depth) *
401  xForm; // warning: depth may change!
402  } else if (params.scale > 0) {
403  xForm = GetPointXForm<Real, Dim>(pointStream,
404  static_cast<Real>(params.scale)) *
405  xForm;
406  }
407  pointStream.xform = &xForm;
408  }
409 
410  if (depth < 2) {
411  // depth should be greater than 2
412  assert(false);
413  return false;
414  }
415 
416  // default parameters
417  const int solve_depth = depth;
418  const int full_depth = 5;
419  const bool exact_interpolation = false;
420  const Real target_value = static_cast<Real>(0.5);
421 
422  // Read in the samples (and color data)
423  FEMTree<Dim, Real> tree(MEMORY_ALLOCATOR_BLOCK_SIZE);
424  typedef std::vector<typename FEMTree<Dim, Real>::PointSample> SampleSet;
425  typedef std::vector<PointData<Real>> SampleDataSet;
426  std::unique_ptr<SampleSet> samples;
427  std::unique_ptr<SampleDataSet> sampleData;
428  try {
429  samples.reset(new SampleSet);
430  sampleData.reset(new SampleDataSet);
431 
432  if (params.normalConfidence > 0) {
433  auto ProcessDataWithConfidence = [&](const Point<Real, Dim>& p,
434  PointData<Real>& d) {
435  Real l = ComputeNorm(d.normal);
436  if (std::isnan(l) || l == 0) return static_cast<Real>(-1.0);
437 
438  return static_cast<Real>(pow(l, params.normalConfidence));
439  };
440 
441  FEMTreeInitializer<Dim, Real>::template Initialize<PointData<Real>>(
442  tree.spaceRoot(), pointStream, depth, *samples, *sampleData,
443  true, tree.nodeAllocators[0], tree.initializer(),
444  ProcessDataWithConfidence);
445  } else {
446  auto ProcessData = [](const Point<Real, Dim>& p,
447  PointData<Real>& d) {
448  Real l = ComputeNorm(d.normal);
449  if (std::isnan(l) || l == 0) return static_cast<Real>(-1.0);
450 
451  d.normal[0] /= l;
452  d.normal[1] /= l;
453  d.normal[2] /= l;
454  return static_cast<Real>(1.0);
455  };
456 
457  FEMTreeInitializer<Dim, Real>::template Initialize<PointData<Real>>(
458  tree.spaceRoot(), pointStream, solve_depth, *samples,
459  *sampleData, true, tree.nodeAllocators[0],
460  tree.initializer(), ProcessData);
461  }
462  } catch (std::exception e) {
463  return false;
464  }
465 
466  DenseNodeData<Real, Sigs> solution;
467  std::unique_ptr<DensityEstimator> density;
468  SparseNodeData<Point<Real, Dim>, NormalSigs>* normalInfo = nullptr;
469  Real pointWeightSum = 0;
470  {
471  tree.resetNodeIndices();
472 
473  // Get the kernel density estimator
474  {
475  int kernelDepth = solve_depth - 2;
476  assert(kernelDepth >= 0);
477 
478  density.reset(tree.template setDensityEstimator<WEIGHT_DEGREE>(
479  *samples, kernelDepth, params.samplesPerNode, 1));
480  }
481 
482  // Transform the Hermite samples into a vector field
483  {
484  normalInfo = new SparseNodeData<Point<Real, Dim>, NormalSigs>();
485 
486  if (params.normalConfidenceBias > 0) {
487  std::function<bool(PointData<Real>, Point<Real, Dim>&, Real&)>
488  ConversionAndBiasFunction = [&](PointData<Real> in,
489  Point<Real, Dim>& out,
490  Real& bias) {
491  // Point<Real, Dim> n = in.template data<0>();
492  Point<Real, Dim> n(in.normal[0], in.normal[1],
493  in.normal[2]);
494  Real l = static_cast<Real>(Length(n));
495  // It is possible that the samples have non-zero
496  // normals but there are two co-located samples with
497  // negative normals...
498  if (l == 0) return false;
499 
500  out = n / l;
501  bias = static_cast<Real>(
502  log(l) * params.normalConfidenceBias /
503  log(1 << (Dim - 1)));
504 
505  return true;
506  };
507 
508  *normalInfo = tree.setDataField(
509  NormalSigs(), *samples, *sampleData, density.get(),
510  pointWeightSum, ConversionAndBiasFunction);
511  } else {
512  std::function<bool(PointData<Real>, Point<Real, Dim>&)>
513  ConversionFunction = [](PointData<Real> in,
514  Point<Real, Dim>& out) {
515  Point<Real, Dim> n(in.normal[0], in.normal[1],
516  in.normal[2]);
517  Real l = static_cast<Real>(Length(n));
518  // It is possible that the samples have non-zero
519  // normals but there are two co-located samples with
520  // negative normals...
521  if (l == 0) return false;
522 
523  out = n / l;
524  return true;
525  };
526 
527  *normalInfo = tree.setDataField(
528  NormalSigs(), *samples, *sampleData, density.get(),
529  pointWeightSum, ConversionFunction);
530  }
531 
532  auto InvertNormal = [&](unsigned int, size_t i) {
533  (*normalInfo)[i] *= static_cast<Real>(-1.0);
534  };
535 
536  ThreadPool::Parallel_for(0, normalInfo->size(), InvertNormal);
537  }
538 
539  if (!params.density) {
540  density.reset();
541  }
542  if (!params.withColors || params.colorPullFactor == 0) {
543  sampleData.reset();
544  }
545 
546  // Trim the tree and prepare for multigrid
547  {
548  constexpr int MAX_DEGREE = NORMAL_DEGREE > Degrees::Max()
549  ? NORMAL_DEGREE
550  : Degrees::Max();
551 
552  tree.template finalizeForMultigrid<MAX_DEGREE>(
553  full_depth,
554  typename FEMTree<Dim, Real>::template HasNormalDataFunctor<
555  NormalSigs>(*normalInfo),
556  normalInfo, density.get());
557  }
558 
559  // Add the FEM constraints
560  DenseNodeData<Real, Sigs> constraints;
561  {
562  constraints = tree.initDenseNodeData(Sigs());
563  typename FEMIntegrator::template Constraint<
564  Sigs, IsotropicUIntPack<Dim, 1>, NormalSigs,
565  IsotropicUIntPack<Dim, 0>, Dim>
566  F;
567  unsigned int derivatives2[Dim];
568 
569  for (unsigned int d = 0; d < Dim; d++) derivatives2[d] = 0;
570 
571  typedef IsotropicUIntPack<Dim, 1> Derivatives1;
572  typedef IsotropicUIntPack<Dim, 0> Derivatives2;
573  for (unsigned int d = 0; d < Dim; d++) {
574  unsigned int derivatives1[Dim];
575  for (unsigned int dd = 0; dd < Dim; dd++)
576  derivatives1[dd] = (dd == d ? 1 : 0);
577 
578  F.weights[d]
581  derivatives2)] = 1;
582  }
583 
584  tree.addFEMConstraints(F, *normalInfo, constraints, solve_depth);
585  }
586 
587  // Free up the normal info
588  if (normalInfo) {
589  delete normalInfo;
590  normalInfo = nullptr;
591  }
592 
593  // Add the interpolation constraints
594  InterpolationInfo* iInfo = nullptr;
595  if (params.pointWeight > 0) {
596  if (exact_interpolation) {
597  iInfo = FEMTree<Dim, Real>::
598  template InitializeExactPointInterpolationInfo<Real, 0>(
599  tree, *samples,
601  target_value,
602  static_cast<Real>(params.pointWeight) *
603  pointWeightSum),
605  static_cast<Real>(params.pointWeight) *
606  pointWeightSum),
607  true, 0);
608  } else {
609  iInfo = FEMTree<Dim, Real>::
610  template InitializeApproximatePointInterpolationInfo<
611  Real, 0>(
612  tree, *samples,
614  target_value,
615  static_cast<Real>(params.pointWeight) *
616  pointWeightSum),
618  static_cast<Real>(params.pointWeight) *
619  pointWeightSum),
620  true, 1);
621  }
622  tree.addInterpolationConstraints(constraints, solve_depth, *iInfo);
623  }
624 
625  // Solve the linear system
626  {
627  typename FEMTree<Dim, Real>::SolverInfo sInfo;
628  {
629  sInfo.cgDepth = 0;
630  sInfo.cascadic = true;
631  sInfo.vCycles = 1;
632  sInfo.iters = params.iters;
633  sInfo.cgAccuracy = params.cgAccuracy;
634  sInfo.verbose = false;
635  sInfo.showResidual = false;
636  sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE;
637  sInfo.sliceBlockSize = 1;
638  sInfo.baseDepth = params.baseDepth;
639  sInfo.baseVCycles = params.baseVCycles;
640  }
641  typename FEMIntegrator::template System<Sigs,
642  IsotropicUIntPack<Dim, 1>>
643  F({0.0, 1.0});
644 
645  solution = tree.solveSystem(Sigs(), F, constraints, solve_depth,
646  sInfo, iInfo);
647  }
648 
649  // Free up the interpolation info
650  if (iInfo) {
651  delete iInfo;
652  iInfo = nullptr;
653  }
654  }
655 
656  Real isoValue = 0;
657  {
658  double valueSum = 0, weightSum = 0;
659  typename FEMTree<Dim, Real>::template MultiThreadedEvaluator<Sigs, 0>
660  evaluator(&tree, solution);
661 
662  std::vector<double> valueSums(ThreadPool::NumThreads(), 0);
663  std::vector<double> weightSums(ThreadPool::NumThreads(), 0);
664 
665  auto func = [&](unsigned int thread, size_t j) {
666  const ProjectiveData<Point<Real, Dim>, Real>& sample =
667  (*samples)[j].sample;
668  if (sample.weight > 0) {
669  weightSums[thread] += sample.weight;
670  valueSums[thread] +=
671  evaluator.values(sample.data / sample.weight, thread,
672  (*samples)[j].node)[0] *
673  sample.weight;
674  }
675  };
676 
677  ThreadPool::Parallel_for(0, samples->size(), func);
678 
679  for (size_t t = 0; t < valueSums.size(); t++) {
680  valueSum += valueSums[t];
681  weightSum += weightSums[t];
682  }
683 
684  isoValue = static_cast<Real>(valueSum / weightSum);
685 
686  if (!params.withColors || params.colorPullFactor == 0) {
687  samples.reset();
688  }
689  }
690 
691  auto SetVertex = [](Vertex<Real>& v, Point<Real, Dim> p, double w,
692  PointData<Real> d) { v = Vertex<Real>(p, d, w); };
693 
694  ExtractMesh<Vertex<Real>, Real>(
695  params, UIntPack<FEMSigs...>(), std::tuple<SampleData...>(), tree,
696  solution, isoValue, samples.get(), sampleData.get(), density.get(),
697  SetVertex, xForm.inverse(), out_mesh);
698 
699  return true;
700 }
701 
703  const ICloud<float>& inCloud,
704  IMesh<float>& outMesh) {
705  if (!inCloud.hasNormals()) {
706  // we need normals
707  return false;
708  }
709 
710 #ifdef WITH_OPENMP
711  ThreadPool::Init((ThreadPool::ParallelType)(int)ThreadPool::OPEN_MP,
712  std::thread::hardware_concurrency());
713 #else
714  ThreadPool::Init((ThreadPool::ParallelType)(int)ThreadPool::THREAD_POOL,
715  std::thread::hardware_concurrency());
716 #endif
717 
718  PointStream<float> pointStream(inCloud);
719 
720  bool success = false;
721 
722  switch (params.boundary) {
723  case Parameters::FREE:
724  typedef IsotropicUIntPack<
725  DIMENSION, FEMDegreeAndBType<DEFAULT_FEM_DEGREE,
726  BOUNDARY_FREE>::Signature>
727  FEMSigsFree;
728  success =
729  Execute<float>(pointStream, outMesh, params, FEMSigsFree());
730  break;
732  typedef IsotropicUIntPack<
733  DIMENSION, FEMDegreeAndBType<DEFAULT_FEM_DEGREE,
734  BOUNDARY_DIRICHLET>::Signature>
735  FEMSigsDirichlet;
736  success = Execute<float>(pointStream, outMesh, params,
737  FEMSigsDirichlet());
738  break;
739  case Parameters::NEUMANN:
740  typedef IsotropicUIntPack<
741  DIMENSION, FEMDegreeAndBType<DEFAULT_FEM_DEGREE,
742  BOUNDARY_NEUMANN>::Signature>
743  FEMSigsNeumann;
744  success = Execute<float>(pointStream, outMesh, params,
745  FEMSigsNeumann());
746  break;
747  default:
748  assert(false);
749  break;
750  }
751 
752  ThreadPool::Terminate();
753 
754  return success;
755 }
756 
758  const ICloud<double>& inCloud,
759  IMesh<double>& outMesh) {
760  if (!inCloud.hasNormals()) {
761  // we need normals
762  return false;
763  }
764 
765 #ifdef WITH_OPENMP
766  ThreadPool::Init((ThreadPool::ParallelType)(int)ThreadPool::OPEN_MP,
767  std::thread::hardware_concurrency());
768 #else
769  ThreadPool::Init((ThreadPool::ParallelType)(int)ThreadPool::THREAD_POOL,
770  std::thread::hardware_concurrency());
771 #endif
772 
773  PointStream<double> pointStream(inCloud);
774 
775  bool success = false;
776 
777  switch (params.boundary) {
778  case Parameters::FREE:
779  typedef IsotropicUIntPack<
780  DIMENSION, FEMDegreeAndBType<DEFAULT_FEM_DEGREE,
781  BOUNDARY_FREE>::Signature>
782  FEMSigsFree;
783  success = Execute<double>(pointStream, outMesh, params,
784  FEMSigsFree());
785  break;
787  typedef IsotropicUIntPack<
788  DIMENSION, FEMDegreeAndBType<DEFAULT_FEM_DEGREE,
789  BOUNDARY_DIRICHLET>::Signature>
790  FEMSigsDirichlet;
791  success = Execute<double>(pointStream, outMesh, params,
792  FEMSigsDirichlet());
793  break;
794  case Parameters::NEUMANN:
795  typedef IsotropicUIntPack<
796  DIMENSION, FEMDegreeAndBType<DEFAULT_FEM_DEGREE,
797  BOUNDARY_NEUMANN>::Signature>
798  FEMSigsNeumann;
799  success = Execute<double>(pointStream, outMesh, params,
800  FEMSigsNeumann());
801  break;
802  default:
803  assert(false);
804  break;
805  }
806 
807  ThreadPool::Terminate();
808 
809  return success;
810 }
double normal[3]
int width
math::float4 color
static bool Execute(PointStream< Real > &pointStream, PoissonReconLib::IMesh< Real > &out_mesh, const PoissonReconLib::Parameters &params, UIntPack< FEMSigs... >)
void ExtractMesh(const PoissonReconLib::Parameters &params, UIntPack< FEMSigs... >, std::tuple< SampleData... >, FEMTree< sizeof...(FEMSigs), Real > &tree, const DenseNodeData< Real, UIntPack< FEMSigs... >> &solution, Real isoValue, const std::vector< typename FEMTree< sizeof...(FEMSigs), Real >::PointSample > *samples, std::vector< PointData< Real >> *sampleData, const typename FEMTree< sizeof...(FEMSigs), Real >::template DensityEstimator< WEIGHT_DEGREE > *density, const SetVertexFunction &SetVertex, XForm< Real, sizeof...(FEMSigs)+1 > iXForm, PoissonReconLib::IMesh< Real > &out_mesh)
XForm< Real, Dim+1 > GetPointXForm(InputPointStream< Real, Dim > &stream, Real width, Real scaleFactor, int &depth)
XForm< Real, Dim+1 > GetBoundingBoxXForm(Point< Real, Dim > min, Point< Real, Dim > max, Real scaleFactor)
Real normal[3]
Definition: PointData.h:60
PointData & operator+=(const PointData &d)
Definition: PointData.h:40
Real color[3]
Definition: PointData.h:61
PointData & operator*=(Real s)
Definition: PointData.h:49
void reset(void) override
PointStream(const PoissonReconLib::ICloud< Real > &_cloud)
XForm< Real, 4 > * xform
bool nextPoint(Point< Real, 3 > &p, PointData< Real > &d) override
const PoissonReconLib::ICloud< Real > & cloud
Input cloud interface.
virtual bool hasNormals() const =0
Output mesh interface.
virtual void addDensity(double d)=0
virtual void addColor(const Real *rgb)=0
virtual void addVertex(const Real *coords)=0
virtual void addTriangle(size_t i1, size_t i2, size_t i3)=0
static bool Reconstruct(const Parameters &params, const PoissonReconLib::ICloud< float > &inCloud, PoissonReconLib::IMesh< float > &ouMesh)
Reconstruct a mesh from a point cloud (float version)
Vertex & operator*=(Real s)
Vertex(const Point< Real, 3 > &point, const PointData< Real > &data, double _w=0.0)
Point< Real, 3 > point
Vertex & operator/=(Real s)
Vertex(const Point< Real, 3 > &point)
Vertex & operator+=(const Vertex &p)
const double * e
GraphType data
Definition: graph_cut.cc:138
void Extract(const std::string &file_path, const std::string &extract_dir)
Function to extract compressed files.
Definition: Extract.cpp:33
Eigen::MatrixXd::Index Index
Definition: knncpp.h:26
static const int DEFAULT_FEM_DEGREE
static const int WEIGHT_DEGREE
static const int DATA_DEGREE
static const int DIMENSION
static const int NORMAL_DEGREE
ConstraintDual(Real t, Real w)
CumulativeDerivativeValues< Real, Dim, 0 > operator()(const Point< Real, Dim > &p) const
void dumpOutput(const char *header) const
FEMTree< Dim, Real > & tree
FEMTreeProfiler(FEMTree< Dim, Real > &t)
Algorithm parameters.
int baseVCycles
Coarse MG solver v-cycles.
float cgAccuracy
This flag specifies the accuracy cut-off to be used for CG.
float normalConfidence
Normal confidence exponent.
Parameters()
Default initializer.
float colorPullFactor
Data pull factor.
int baseDepth
Coarse MG solver depth.
BoundaryType boundary
Boundary type for the finite elements.
float normalConfidenceBias
Normal confidence bias exponent.
int iters
The number of solver iterations.
CumulativeDerivativeValues< Real, Dim, 0 > operator()(const Point< Real, Dim > &p, const CumulativeDerivativeValues< Real, Dim, 0 > &dValues) const
CumulativeDerivativeValues< double, Dim, 0 > operator()(const Point< Real, Dim > &p, const CumulativeDerivativeValues< double, Dim, 0 > &dValues) const
SystemDual(Real w)
CumulativeDerivativeValues< Real, Dim, 0 > operator()(const Point< Real, Dim > &p, const CumulativeDerivativeValues< Real, Dim, 0 > &dValues) const