23 #include "../Src/FEMTree.h"
35 constexpr
int DEFAULT_FEM_DEGREE = 1;
39 inline float ComputeNorm(
const float vec[3]) {
40 return sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]);
43 inline double ComputeNorm(
const double vec[3]) {
44 return sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]);
54 template <
typename _Real>
97 template <
typename Real>
99 :
public InputPointStreamWithData<Real, DIMENSION, PointData<Real>> {
102 : cloud(_cloud), xform(nullptr), currentIndex(0) {}
104 void reset(
void)
override { currentIndex = 0; }
107 if (currentIndex >= cloud.size()) {
110 cloud.getPoint(currentIndex, p.coords);
112 if (xform !=
nullptr) {
116 if (cloud.hasNormals()) {
117 cloud.getNormal(currentIndex, d.
normal);
122 if (cloud.hasColors()) {
123 cloud.getColor(currentIndex, d.
color);
138 template <
unsigned int Dim,
class Real>
145 t =
Time(), FEMTree<Dim, Real>::ResetLocalMemoryUsage();
148 FEMTree<Dim, Real>::MemoryUsage();
165 template <
class Real,
unsigned int Dim>
167 Point<Real, Dim>
max,
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]);
174 scale *= scaleFactor;
175 for (
unsigned int i = 0; i < Dim; i++) {
176 center[i] -= scale / 2;
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];
184 return sXForm * tXForm;
187 template <
class Real,
unsigned int Dim>
189 Point<Real, Dim>
max,
195 for (
unsigned int d = 1; d < Dim; d++) {
196 resolution = std::max<Real>(resolution, (
max[d] -
min[d]) /
width);
198 resolution *= scaleFactor;
200 while ((1 << depth) < resolution) {
204 Point<Real, Dim> center = (
max +
min) / 2;
205 Real scale = (1 << depth) *
width;
207 for (
unsigned int i = 0; i < Dim; i++) {
208 center[i] -= scale / 2;
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];
216 return sXForm * tXForm;
219 template <
class Real,
unsigned int Dim>
224 Point<Real, Dim>
min,
max;
225 stream.boundingBox(
min,
max);
229 template <
class Real,
unsigned int Dim>
232 Point<Real, Dim>
min,
max;
233 stream.boundingBox(
min,
max);
237 template <
unsigned int Dim,
typename Real>
242 const Point<Real, Dim>& p)
const {
243 return CumulativeDerivativeValues<Real, Dim, 0>(target * weight);
247 template <
unsigned int Dim,
typename Real>
251 const Point<Real, Dim>& p,
252 const CumulativeDerivativeValues<Real, Dim, 0>& dValues)
const {
253 return dValues * weight;
257 const Point<Real, Dim>& p,
258 const CumulativeDerivativeValues<double, Dim, 0>& dValues)
const {
259 return dValues * weight;
265 template <
unsigned int Dim>
271 const Point<Real, Dim>& p,
272 const CumulativeDerivativeValues<Real, Dim, 0>& dValues)
const {
273 return dValues * weight;
279 template <
typename Vertex,
281 typename SetVertexFunction,
282 unsigned int... FEMSigs,
283 typename... SampleData>
286 UIntPack<FEMSigs...>,
287 std::tuple<SampleData...>,
288 FEMTree<
sizeof...(FEMSigs), Real>& tree,
291 const std::vector<
typename FEMTree<
sizeof...(FEMSigs),
292 Real>::PointSample>* samples,
294 const typename FEMTree<
sizeof...(FEMSigs),
295 Real>::
template DensityEstimator<WEIGHT_DEGREE>*
297 const SetVertexFunction& SetVertex,
298 XForm<Real,
sizeof...(FEMSigs) + 1> iXForm,
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;
305 const bool non_manifold =
true;
306 const bool polygon_mesh =
false;
310 if (samples && sampleData) {
311 typedef typename FEMTree<Dim,
312 Real>::template DensityEstimator<WEIGHT_DEGREE>
316 IsotropicUIntPack<Dim, DataSig>>
318 tree.template setMultiDepthDataField<DataSig, false>(
319 *samples, *sampleData,
320 (DensityEstimator*)
nullptr);
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);
327 (*color) *=
static_cast<Real
>(
328 pow(
params.colorPullFactor, tree.depth(n)));
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);
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);
361 for (
size_t tidx = 0; tidx < mesh.
polygonCount(); ++tidx) {
362 std::vector<CoredVertexIndex<node_index_type>> triangle;
364 if (triangle.size() == 3) {
365 out_mesh.
addTriangle(triangle[0].idx, triangle[1].idx,
373 template <
class Real,
typename... SampleData,
unsigned int... FEMSigs>
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...>
385 typedef typename FEMTree<Dim,
386 Real>::template DensityEstimator<WEIGHT_DEGREE>
388 typedef typename FEMTree<Dim, Real>::template InterpolationInfo<Real, 0>
393 XForm<Real, Dim + 1> xForm = XForm<Real, Dim + 1>::Identity();
395 if (
params.finestCellWidth > 0) {
397 static_cast<Real
>(
params.scale > 0 ?
params.scale : 1.0);
398 xForm = GetPointXForm<Real, Dim>(pointStream,
400 scaleFactor, depth) *
402 }
else if (
params.scale > 0) {
403 xForm = GetPointXForm<Real, Dim>(pointStream,
404 static_cast<Real
>(
params.scale)) *
407 pointStream.
xform = &xForm;
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);
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;
429 samples.reset(
new SampleSet);
430 sampleData.reset(
new SampleDataSet);
432 if (
params.normalConfidence > 0) {
433 auto ProcessDataWithConfidence = [&](
const Point<Real, Dim>& p,
435 Real l = ComputeNorm(d.normal);
436 if (std::isnan(l) || l == 0)
return static_cast<Real
>(-1.0);
438 return static_cast<Real
>(pow(l,
params.normalConfidence));
441 FEMTreeInitializer<Dim, Real>::template Initialize<PointData<Real>>(
442 tree.spaceRoot(), pointStream, depth, *samples, *sampleData,
443 true, tree.nodeAllocators[0], tree.initializer(),
444 ProcessDataWithConfidence);
446 auto ProcessData = [](
const Point<Real, Dim>& p,
448 Real l = ComputeNorm(d.normal);
449 if (std::isnan(l) || l == 0)
return static_cast<Real
>(-1.0);
454 return static_cast<Real
>(1.0);
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);
462 }
catch (std::exception e) {
467 std::unique_ptr<DensityEstimator> density;
469 Real pointWeightSum = 0;
471 tree.resetNodeIndices();
475 int kernelDepth = solve_depth - 2;
476 assert(kernelDepth >= 0);
478 density.reset(tree.template setDensityEstimator<WEIGHT_DEGREE>(
479 *samples, kernelDepth,
params.samplesPerNode, 1));
486 if (
params.normalConfidenceBias > 0) {
489 Point<Real, Dim>& out,
492 Point<Real, Dim> n(in.normal[0], in.normal[1],
494 Real l =
static_cast<Real
>(
Length(n));
498 if (l == 0)
return false;
501 bias =
static_cast<Real
>(
502 log(l) *
params.normalConfidenceBias /
503 log(1 << (Dim - 1)));
508 *normalInfo = tree.setDataField(
509 NormalSigs(), *samples, *sampleData, density.get(),
510 pointWeightSum, ConversionAndBiasFunction);
514 Point<Real, Dim>& out) {
515 Point<Real, Dim> n(in.normal[0], in.normal[1],
517 Real l =
static_cast<Real
>(
Length(n));
521 if (l == 0)
return false;
527 *normalInfo = tree.setDataField(
528 NormalSigs(), *samples, *sampleData, density.get(),
529 pointWeightSum, ConversionFunction);
532 auto InvertNormal = [&](
unsigned int,
size_t i) {
533 (*normalInfo)[i] *=
static_cast<Real
>(-1.0);
536 ThreadPool::Parallel_for(0, normalInfo->size(), InvertNormal);
542 if (!
params.withColors ||
params.colorPullFactor == 0) {
552 tree.template finalizeForMultigrid<MAX_DEGREE>(
554 typename FEMTree<Dim, Real>::template HasNormalDataFunctor<
555 NormalSigs>(*normalInfo),
556 normalInfo, density.get());
562 constraints = tree.initDenseNodeData(Sigs());
563 typename FEMIntegrator::template Constraint<
564 Sigs, IsotropicUIntPack<Dim, 1>, NormalSigs,
565 IsotropicUIntPack<Dim, 0>, Dim>
567 unsigned int derivatives2[Dim];
569 for (
unsigned int d = 0; d < Dim; d++) derivatives2[d] = 0;
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);
584 tree.addFEMConstraints(F, *normalInfo, constraints, solve_depth);
590 normalInfo =
nullptr;
594 InterpolationInfo* iInfo =
nullptr;
595 if (
params.pointWeight > 0) {
596 if (exact_interpolation) {
597 iInfo = FEMTree<Dim, Real>::
598 template InitializeExactPointInterpolationInfo<Real, 0>(
602 static_cast<Real
>(
params.pointWeight) *
605 static_cast<Real
>(
params.pointWeight) *
609 iInfo = FEMTree<Dim, Real>::
610 template InitializeApproximatePointInterpolationInfo<
615 static_cast<Real
>(
params.pointWeight) *
618 static_cast<Real
>(
params.pointWeight) *
622 tree.addInterpolationConstraints(constraints, solve_depth, *iInfo);
627 typename FEMTree<Dim, Real>::SolverInfo sInfo;
630 sInfo.cascadic =
true;
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;
641 typename FEMIntegrator::template System<Sigs,
642 IsotropicUIntPack<Dim, 1>>
645 solution = tree.solveSystem(Sigs(), F, constraints, solve_depth,
658 double valueSum = 0, weightSum = 0;
659 typename FEMTree<Dim, Real>::template MultiThreadedEvaluator<Sigs, 0>
660 evaluator(&tree, solution);
662 std::vector<double> valueSums(ThreadPool::NumThreads(), 0);
663 std::vector<double> weightSums(ThreadPool::NumThreads(), 0);
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;
671 evaluator.values(sample.data / sample.weight, thread,
672 (*samples)[j].node)[0] *
677 ThreadPool::Parallel_for(0, samples->size(), func);
679 for (
size_t t = 0; t < valueSums.size(); t++) {
680 valueSum += valueSums[t];
681 weightSum += weightSums[t];
684 isoValue =
static_cast<Real
>(valueSum / weightSum);
686 if (!
params.withColors ||
params.colorPullFactor == 0) {
691 auto SetVertex = [](
Vertex<Real>& v, Point<Real, Dim> p,
double w,
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);
711 ThreadPool::Init((ThreadPool::ParallelType)(
int)ThreadPool::OPEN_MP,
712 std::thread::hardware_concurrency());
714 ThreadPool::Init((ThreadPool::ParallelType)(
int)ThreadPool::THREAD_POOL,
715 std::thread::hardware_concurrency());
720 bool success =
false;
722 switch (
params.boundary) {
724 typedef IsotropicUIntPack<
725 DIMENSION, FEMDegreeAndBType<DEFAULT_FEM_DEGREE,
726 BOUNDARY_FREE>::Signature>
729 Execute<float>(pointStream, outMesh,
params, FEMSigsFree());
732 typedef IsotropicUIntPack<
733 DIMENSION, FEMDegreeAndBType<DEFAULT_FEM_DEGREE,
734 BOUNDARY_DIRICHLET>::Signature>
736 success = Execute<float>(pointStream, outMesh,
params,
740 typedef IsotropicUIntPack<
741 DIMENSION, FEMDegreeAndBType<DEFAULT_FEM_DEGREE,
742 BOUNDARY_NEUMANN>::Signature>
744 success = Execute<float>(pointStream, outMesh,
params,
752 ThreadPool::Terminate();
766 ThreadPool::Init((ThreadPool::ParallelType)(
int)ThreadPool::OPEN_MP,
767 std::thread::hardware_concurrency());
769 ThreadPool::Init((ThreadPool::ParallelType)(
int)ThreadPool::THREAD_POOL,
770 std::thread::hardware_concurrency());
775 bool success =
false;
777 switch (
params.boundary) {
779 typedef IsotropicUIntPack<
780 DIMENSION, FEMDegreeAndBType<DEFAULT_FEM_DEGREE,
781 BOUNDARY_FREE>::Signature>
783 success = Execute<double>(pointStream, outMesh,
params,
787 typedef IsotropicUIntPack<
788 DIMENSION, FEMDegreeAndBType<DEFAULT_FEM_DEGREE,
789 BOUNDARY_DIRICHLET>::Signature>
791 success = Execute<double>(pointStream, outMesh,
params,
795 typedef IsotropicUIntPack<
796 DIMENSION, FEMDegreeAndBType<DEFAULT_FEM_DEGREE,
797 BOUNDARY_NEUMANN>::Signature>
799 success = Execute<double>(pointStream, outMesh,
params,
807 ThreadPool::Terminate();
int omp_get_num_procs(void)
static bool Execute(PointStream< Real > &pointStream, PoissonReconLib::IMesh< Real > &out_mesh, const PoissonReconLib::Parameters ¶ms, UIntPack< FEMSigs... >)
void ExtractMesh(const PoissonReconLib::Parameters ¶ms, 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)
double Length(const Point3D< Real > &p)
cmdLineReadable * params[]
int nextPolygon(std::vector< CoredVertexIndex > &vertices)
int nextOutOfCorePoint(Vertex &p)
int outOfCorePointCount(void)
void reset(void) override
PointStream(const PoissonReconLib::ICloud< Real > &_cloud)
bool nextPoint(Point< Real, 3 > &p, PointData< Real > &d) override
const PoissonReconLib::ICloud< Real > & cloud
virtual bool hasNormals() const =0
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 ¶ms, 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)
Vertex & operator/=(Real s)
Vertex(const Point< Real, 3 > &point)
Vertex & operator+=(const Vertex &p)
void Extract(const std::string &file_path, const std::string &extract_dir)
Function to extract compressed files.
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)
PointData & operator+=(const PointData &d)
PointData & operator*=(Real s)
Parameters()
Default initializer.
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
CumulativeDerivativeValues< Real, Dim, 0 > operator()(const Point< Real, Dim > &p, const CumulativeDerivativeValues< Real, Dim, 0 > &dValues) const