23 #include "../Src/FEMTree.h"
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,
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);
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,
289 const DenseNodeData<Real, UIntPack<FEMSigs...>>& solution,
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;
308 CoredVectorMeshData<Vertex, node_index_type> mesh;
310 if (samples && sampleData) {
311 typedef typename FEMTree<Dim,
312 Real>::template DensityEstimator<WEIGHT_DEGREE>
315 SparseNodeData<ProjectiveData<PointData<Real>, Real>,
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
>(
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);
344 mesh.resetIterator();
346 for (
size_t vidx = 0; vidx < mesh.outOfCorePointCount(); ++vidx) {
348 mesh.nextOutOfCorePoint(v);
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,
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>
392 int depth = params.
depth;
393 XForm<Real, Dim + 1> xForm = XForm<Real, Dim + 1>::Identity();
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);
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);
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) {
466 DenseNodeData<Real, Sigs> solution;
467 std::unique_ptr<DensityEstimator> density;
468 SparseNodeData<Point<Real, Dim>, NormalSigs>* normalInfo =
nullptr;
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>(
484 normalInfo =
new SparseNodeData<Point<Real, Dim>, NormalSigs>();
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
>(
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);
552 tree.template finalizeForMultigrid<MAX_DEGREE>(
554 typename FEMTree<Dim, Real>::template HasNormalDataFunctor<
555 NormalSigs>(*normalInfo),
556 normalInfo, density.get());
560 DenseNodeData<Real, Sigs> constraints;
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;
596 if (exact_interpolation) {
597 iInfo = FEMTree<Dim, Real>::
598 template InitializeExactPointInterpolationInfo<Real, 0>(
609 iInfo = FEMTree<Dim, Real>::
610 template InitializeApproximatePointInterpolationInfo<
622 tree.addInterpolationConstraints(constraints, solve_depth, *iInfo);
627 typename FEMTree<Dim, Real>::SolverInfo sInfo;
630 sInfo.cascadic =
true;
632 sInfo.iters = params.
iters;
634 sInfo.verbose =
false;
635 sInfo.showResidual =
false;
636 sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE;
637 sInfo.sliceBlockSize = 1;
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);
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;
724 typedef IsotropicUIntPack<
726 BOUNDARY_FREE>::Signature>
729 Execute<float>(pointStream, outMesh, params, FEMSigsFree());
732 typedef IsotropicUIntPack<
734 BOUNDARY_DIRICHLET>::Signature>
736 success = Execute<float>(pointStream, outMesh, params,
740 typedef IsotropicUIntPack<
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;
779 typedef IsotropicUIntPack<
781 BOUNDARY_FREE>::Signature>
783 success = Execute<double>(pointStream, outMesh, params,
787 typedef IsotropicUIntPack<
789 BOUNDARY_DIRICHLET>::Signature>
791 success = Execute<double>(pointStream, outMesh, params,
795 typedef IsotropicUIntPack<
797 BOUNDARY_NEUMANN>::Signature>
799 success = Execute<double>(pointStream, outMesh, params,
807 ThreadPool::Terminate();
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)
PointData & operator+=(const PointData &d)
PointData & operator*=(Real s)
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.
Eigen::MatrixXd::Index Index
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)
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
CumulativeDerivativeValues< Real, Dim, 0 > operator()(const Point< Real, Dim > &p, const CumulativeDerivativeValues< Real, Dim, 0 > &dValues) const